|
1 (* ========================================================================= *) |
|
2 (* CLAUSE = ID + THEOREM *) |
|
3 (* Copyright (c) 2002-2004 Joe Hurd, distributed under the GNU GPL version 2 *) |
|
4 (* ========================================================================= *) |
|
5 |
|
6 structure Clause :> Clause = |
|
7 struct |
|
8 |
|
9 open Useful; |
|
10 |
|
11 (* ------------------------------------------------------------------------- *) |
|
12 (* Helper functions. *) |
|
13 (* ------------------------------------------------------------------------- *) |
|
14 |
|
15 val newId = |
|
16 let |
|
17 val r = ref 0 |
|
18 in |
|
19 fn () => case r of ref n => let val () = r := n + 1 in n end |
|
20 end; |
|
21 |
|
22 (* ------------------------------------------------------------------------- *) |
|
23 (* A type of clause. *) |
|
24 (* ------------------------------------------------------------------------- *) |
|
25 |
|
26 datatype literalOrder = |
|
27 NoLiteralOrder |
|
28 | UnsignedLiteralOrder |
|
29 | PositiveLiteralOrder; |
|
30 |
|
31 type parameters = |
|
32 {ordering : KnuthBendixOrder.kbo, |
|
33 orderLiterals : literalOrder, |
|
34 orderTerms : bool}; |
|
35 |
|
36 type clauseId = int; |
|
37 |
|
38 type clauseInfo = {parameters : parameters, id : clauseId, thm : Thm.thm}; |
|
39 |
|
40 datatype clause = Clause of clauseInfo; |
|
41 |
|
42 (* ------------------------------------------------------------------------- *) |
|
43 (* Pretty printing. *) |
|
44 (* ------------------------------------------------------------------------- *) |
|
45 |
|
46 val showId = ref false; |
|
47 |
|
48 local |
|
49 val ppIdThm = Print.ppPair Print.ppInt Thm.pp; |
|
50 in |
|
51 fun pp (Clause {id,thm,...}) = |
|
52 if !showId then ppIdThm (id,thm) else Thm.pp thm; |
|
53 end; |
|
54 |
|
55 fun toString cl = Print.toString pp cl; |
|
56 |
|
57 (* ------------------------------------------------------------------------- *) |
|
58 (* Basic operations. *) |
|
59 (* ------------------------------------------------------------------------- *) |
|
60 |
|
61 val default : parameters = |
|
62 {ordering = KnuthBendixOrder.default, |
|
63 orderLiterals = PositiveLiteralOrder, |
|
64 orderTerms = true}; |
|
65 |
|
66 fun mk info = Clause info |
|
67 |
|
68 fun dest (Clause info) = info; |
|
69 |
|
70 fun id (Clause {id = i, ...}) = i; |
|
71 |
|
72 fun thm (Clause {thm = th, ...}) = th; |
|
73 |
|
74 fun equalThms cl cl' = Thm.equal (thm cl) (thm cl'); |
|
75 |
|
76 fun new parameters thm = |
|
77 Clause {parameters = parameters, id = newId (), thm = thm}; |
|
78 |
|
79 fun literals cl = Thm.clause (thm cl); |
|
80 |
|
81 fun isTautology (Clause {thm,...}) = Thm.isTautology thm; |
|
82 |
|
83 fun isContradiction (Clause {thm,...}) = Thm.isContradiction thm; |
|
84 |
|
85 (* ------------------------------------------------------------------------- *) |
|
86 (* The term ordering is used to cut down inferences. *) |
|
87 (* ------------------------------------------------------------------------- *) |
|
88 |
|
89 fun strictlyLess ordering x_y = |
|
90 case KnuthBendixOrder.compare ordering x_y of |
|
91 SOME LESS => true |
|
92 | _ => false; |
|
93 |
|
94 fun isLargerTerm ({ordering,orderTerms,...} : parameters) l_r = |
|
95 not orderTerms orelse not (strictlyLess ordering l_r); |
|
96 |
|
97 local |
|
98 fun atomToTerms atm = |
|
99 case total Atom.destEq atm of |
|
100 NONE => [Term.Fn atm] |
|
101 | SOME (l,r) => [l,r]; |
|
102 |
|
103 fun notStrictlyLess ordering (xs,ys) = |
|
104 let |
|
105 fun less x = List.exists (fn y => strictlyLess ordering (x,y)) ys |
|
106 in |
|
107 not (List.all less xs) |
|
108 end; |
|
109 in |
|
110 fun isLargerLiteral ({ordering,orderLiterals,...} : parameters) lits = |
|
111 case orderLiterals of |
|
112 NoLiteralOrder => K true |
|
113 | UnsignedLiteralOrder => |
|
114 let |
|
115 fun addLit ((_,atm),acc) = atomToTerms atm @ acc |
|
116 |
|
117 val tms = LiteralSet.foldl addLit [] lits |
|
118 in |
|
119 fn (_,atm') => notStrictlyLess ordering (atomToTerms atm', tms) |
|
120 end |
|
121 | PositiveLiteralOrder => |
|
122 case LiteralSet.findl (K true) lits of |
|
123 NONE => K true |
|
124 | SOME (pol,_) => |
|
125 let |
|
126 fun addLit ((p,atm),acc) = |
|
127 if p = pol then atomToTerms atm @ acc else acc |
|
128 |
|
129 val tms = LiteralSet.foldl addLit [] lits |
|
130 in |
|
131 fn (pol',atm') => |
|
132 if pol <> pol' then pol |
|
133 else notStrictlyLess ordering (atomToTerms atm', tms) |
|
134 end; |
|
135 end; |
|
136 |
|
137 fun largestLiterals (Clause {parameters,thm,...}) = |
|
138 let |
|
139 val litSet = Thm.clause thm |
|
140 val isLarger = isLargerLiteral parameters litSet |
|
141 fun addLit (lit,s) = if isLarger lit then LiteralSet.add s lit else s |
|
142 in |
|
143 LiteralSet.foldr addLit LiteralSet.empty litSet |
|
144 end; |
|
145 |
|
146 (*MetisTrace6 |
|
147 val largestLiterals = fn cl => |
|
148 let |
|
149 val ppResult = LiteralSet.pp |
|
150 val () = Print.trace pp "Clause.largestLiterals: cl" cl |
|
151 val result = largestLiterals cl |
|
152 val () = Print.trace ppResult "Clause.largestLiterals: result" result |
|
153 in |
|
154 result |
|
155 end; |
|
156 *) |
|
157 |
|
158 fun largestEquations (cl as Clause {parameters,...}) = |
|
159 let |
|
160 fun addEq lit ort (l_r as (l,_)) acc = |
|
161 if isLargerTerm parameters l_r then (lit,ort,l) :: acc else acc |
|
162 |
|
163 fun addLit (lit,acc) = |
|
164 case total Literal.destEq lit of |
|
165 NONE => acc |
|
166 | SOME (l,r) => |
|
167 let |
|
168 val acc = addEq lit Rewrite.RightToLeft (r,l) acc |
|
169 val acc = addEq lit Rewrite.LeftToRight (l,r) acc |
|
170 in |
|
171 acc |
|
172 end |
|
173 in |
|
174 LiteralSet.foldr addLit [] (largestLiterals cl) |
|
175 end; |
|
176 |
|
177 local |
|
178 fun addLit (lit,acc) = |
|
179 let |
|
180 fun addTm ((path,tm),acc) = (lit,path,tm) :: acc |
|
181 in |
|
182 foldl addTm acc (Literal.nonVarTypedSubterms lit) |
|
183 end; |
|
184 in |
|
185 fun largestSubterms cl = LiteralSet.foldl addLit [] (largestLiterals cl); |
|
186 |
|
187 fun allSubterms cl = LiteralSet.foldl addLit [] (literals cl); |
|
188 end; |
|
189 |
|
190 (* ------------------------------------------------------------------------- *) |
|
191 (* Subsumption. *) |
|
192 (* ------------------------------------------------------------------------- *) |
|
193 |
|
194 fun subsumes (subs : clause Subsume.subsume) cl = |
|
195 Subsume.isStrictlySubsumed subs (literals cl); |
|
196 |
|
197 (* ------------------------------------------------------------------------- *) |
|
198 (* Simplifying rules: these preserve the clause id. *) |
|
199 (* ------------------------------------------------------------------------- *) |
|
200 |
|
201 fun freshVars (Clause {parameters,id,thm}) = |
|
202 Clause {parameters = parameters, id = id, thm = Rule.freshVars thm}; |
|
203 |
|
204 fun simplify (Clause {parameters,id,thm}) = |
|
205 case Rule.simplify thm of |
|
206 NONE => NONE |
|
207 | SOME thm => SOME (Clause {parameters = parameters, id = id, thm = thm}); |
|
208 |
|
209 fun reduce units (Clause {parameters,id,thm}) = |
|
210 Clause {parameters = parameters, id = id, thm = Units.reduce units thm}; |
|
211 |
|
212 fun rewrite rewr (cl as Clause {parameters,id,thm}) = |
|
213 let |
|
214 fun simp th = |
|
215 let |
|
216 val {ordering,...} = parameters |
|
217 val cmp = KnuthBendixOrder.compare ordering |
|
218 in |
|
219 Rewrite.rewriteIdRule rewr cmp id th |
|
220 end |
|
221 |
|
222 (*MetisTrace4 |
|
223 val () = Print.trace Rewrite.pp "Clause.rewrite: rewr" rewr |
|
224 val () = Print.trace Print.ppInt "Clause.rewrite: id" id |
|
225 val () = Print.trace pp "Clause.rewrite: cl" cl |
|
226 *) |
|
227 |
|
228 val thm = |
|
229 case Rewrite.peek rewr id of |
|
230 NONE => simp thm |
|
231 | SOME ((_,thm),_) => if Rewrite.isReduced rewr then thm else simp thm |
|
232 |
|
233 val result = Clause {parameters = parameters, id = id, thm = thm} |
|
234 |
|
235 (*MetisTrace4 |
|
236 val () = Print.trace pp "Clause.rewrite: result" result |
|
237 *) |
|
238 in |
|
239 result |
|
240 end |
|
241 (*MetisDebug |
|
242 handle Error err => raise Error ("Clause.rewrite:\n" ^ err); |
|
243 *) |
|
244 |
|
245 (* ------------------------------------------------------------------------- *) |
|
246 (* Inference rules: these generate new clause ids. *) |
|
247 (* ------------------------------------------------------------------------- *) |
|
248 |
|
249 fun factor (cl as Clause {parameters,thm,...}) = |
|
250 let |
|
251 val lits = largestLiterals cl |
|
252 |
|
253 fun apply sub = new parameters (Thm.subst sub thm) |
|
254 in |
|
255 map apply (Rule.factor' lits) |
|
256 end; |
|
257 |
|
258 (*MetisTrace5 |
|
259 val factor = fn cl => |
|
260 let |
|
261 val () = Print.trace pp "Clause.factor: cl" cl |
|
262 val result = factor cl |
|
263 val () = Print.trace (Print.ppList pp) "Clause.factor: result" result |
|
264 in |
|
265 result |
|
266 end; |
|
267 *) |
|
268 |
|
269 fun resolve (cl1,lit1) (cl2,lit2) = |
|
270 let |
|
271 (*MetisTrace5 |
|
272 val () = Print.trace pp "Clause.resolve: cl1" cl1 |
|
273 val () = Print.trace Literal.pp "Clause.resolve: lit1" lit1 |
|
274 val () = Print.trace pp "Clause.resolve: cl2" cl2 |
|
275 val () = Print.trace Literal.pp "Clause.resolve: lit2" lit2 |
|
276 *) |
|
277 val Clause {parameters, thm = th1, ...} = cl1 |
|
278 and Clause {thm = th2, ...} = cl2 |
|
279 val sub = Literal.unify Subst.empty lit1 (Literal.negate lit2) |
|
280 (*MetisTrace5 |
|
281 val () = Print.trace Subst.pp "Clause.resolve: sub" sub |
|
282 *) |
|
283 val lit1 = Literal.subst sub lit1 |
|
284 val lit2 = Literal.negate lit1 |
|
285 val th1 = Thm.subst sub th1 |
|
286 and th2 = Thm.subst sub th2 |
|
287 val _ = isLargerLiteral parameters (Thm.clause th1) lit1 orelse |
|
288 (*MetisTrace5 |
|
289 (trace "Clause.resolve: th1 violates ordering\n"; false) orelse |
|
290 *) |
|
291 raise Error "resolve: clause1: ordering constraints" |
|
292 val _ = isLargerLiteral parameters (Thm.clause th2) lit2 orelse |
|
293 (*MetisTrace5 |
|
294 (trace "Clause.resolve: th2 violates ordering\n"; false) orelse |
|
295 *) |
|
296 raise Error "resolve: clause2: ordering constraints" |
|
297 val th = Thm.resolve lit1 th1 th2 |
|
298 (*MetisTrace5 |
|
299 val () = Print.trace Thm.pp "Clause.resolve: th" th |
|
300 *) |
|
301 val cl = Clause {parameters = parameters, id = newId (), thm = th} |
|
302 (*MetisTrace5 |
|
303 val () = Print.trace pp "Clause.resolve: cl" cl |
|
304 *) |
|
305 in |
|
306 cl |
|
307 end; |
|
308 |
|
309 fun paramodulate (cl1,lit1,ort1,tm1) (cl2,lit2,path2,tm2) = |
|
310 let |
|
311 (*MetisTrace5 |
|
312 val () = Print.trace pp "Clause.paramodulate: cl1" cl1 |
|
313 val () = Print.trace Literal.pp "Clause.paramodulate: lit1" lit1 |
|
314 val () = Print.trace Rewrite.ppOrient "Clause.paramodulate: ort1" ort1 |
|
315 val () = Print.trace Term.pp "Clause.paramodulate: tm1" tm1 |
|
316 val () = Print.trace pp "Clause.paramodulate: cl2" cl2 |
|
317 val () = Print.trace Literal.pp "Clause.paramodulate: lit2" lit2 |
|
318 val () = Print.trace Term.ppPath "Clause.paramodulate: path2" path2 |
|
319 val () = Print.trace Term.pp "Clause.paramodulate: tm2" tm2 |
|
320 *) |
|
321 val Clause {parameters, thm = th1, ...} = cl1 |
|
322 and Clause {thm = th2, ...} = cl2 |
|
323 val sub = Subst.unify Subst.empty tm1 tm2 |
|
324 val lit1 = Literal.subst sub lit1 |
|
325 and lit2 = Literal.subst sub lit2 |
|
326 and th1 = Thm.subst sub th1 |
|
327 and th2 = Thm.subst sub th2 |
|
328 |
|
329 val _ = isLargerLiteral parameters (Thm.clause th1) lit1 orelse |
|
330 raise Error "Clause.paramodulate: with clause: ordering" |
|
331 val _ = isLargerLiteral parameters (Thm.clause th2) lit2 orelse |
|
332 raise Error "Clause.paramodulate: into clause: ordering" |
|
333 |
|
334 val eqn = (Literal.destEq lit1, th1) |
|
335 val eqn as (l_r,_) = |
|
336 case ort1 of |
|
337 Rewrite.LeftToRight => eqn |
|
338 | Rewrite.RightToLeft => Rule.symEqn eqn |
|
339 (*MetisTrace6 |
|
340 val () = Print.trace Rule.ppEquation "Clause.paramodulate: eqn" eqn |
|
341 *) |
|
342 val _ = isLargerTerm parameters l_r orelse |
|
343 raise Error "Clause.paramodulate: equation: ordering constraints" |
|
344 val th = Rule.rewrRule eqn lit2 path2 th2 |
|
345 (*MetisTrace5 |
|
346 val () = Print.trace Thm.pp "Clause.paramodulate: th" th |
|
347 *) |
|
348 in |
|
349 Clause {parameters = parameters, id = newId (), thm = th} |
|
350 end |
|
351 (*MetisTrace5 |
|
352 handle Error err => |
|
353 let |
|
354 val () = trace ("Clause.paramodulate: failed: " ^ err ^ "\n") |
|
355 in |
|
356 raise Error err |
|
357 end; |
|
358 *) |
|
359 |
|
360 end |