changeset 41130 | 130771a48c70 |
parent 41127 | 2ea84c8535c6 |
child 41131 | fc9d503c3d67 |
41129:b88cfc0f7456 | 41130:130771a48c70 |
---|---|
23 fun z3_exn msg = raise SMT_Failure.SMT (SMT_Failure.Other_Failure |
23 fun z3_exn msg = raise SMT_Failure.SMT (SMT_Failure.Other_Failure |
24 ("Z3 proof reconstruction: " ^ msg)) |
24 ("Z3 proof reconstruction: " ^ msg)) |
25 |
25 |
26 |
26 |
27 |
27 |
28 (** net of schematic rules **) |
28 (* net of schematic rules *) |
29 |
29 |
30 val z3_ruleN = "z3_rule" |
30 val z3_ruleN = "z3_rule" |
31 |
31 |
32 local |
32 local |
33 val description = "declaration of Z3 proof rules" |
33 val description = "declaration of Z3 proof rules" |
62 |
62 |
63 end |
63 end |
64 |
64 |
65 |
65 |
66 |
66 |
67 (** proof tools **) |
67 (* proof tools *) |
68 |
68 |
69 fun named ctxt name prover ct = |
69 fun named ctxt name prover ct = |
70 let val _ = SMT_Config.trace_msg ctxt I ("Z3: trying " ^ name ^ " ...") |
70 let val _ = SMT_Config.trace_msg ctxt I ("Z3: trying " ^ name ^ " ...") |
71 in prover ct end |
71 in prover ct end |
72 |
72 |
105 THEN_ALL_NEW Classical.fast_tac HOL_cs |
105 THEN_ALL_NEW Classical.fast_tac HOL_cs |
106 end |
106 end |
107 |
107 |
108 |
108 |
109 |
109 |
110 (** theorems and proofs **) |
110 (* theorems and proofs *) |
111 |
111 |
112 (* theorem incarnations *) |
112 (** theorem incarnations **) |
113 |
113 |
114 datatype theorem = |
114 datatype theorem = |
115 Thm of thm | (* theorem without special features *) |
115 Thm of thm | (* theorem without special features *) |
116 MetaEq of thm | (* meta equality "t == s" *) |
116 MetaEq of thm | (* meta equality "t == s" *) |
117 Literals of thm * L.littab |
117 Literals of thm * L.littab |
126 |
126 |
127 fun literals_of (Literals (_, lits)) = lits |
127 fun literals_of (Literals (_, lits)) = lits |
128 | literals_of p = L.make_littab [thm_of p] |
128 | literals_of p = L.make_littab [thm_of p] |
129 |
129 |
130 |
130 |
131 (* proof representation *) |
|
132 |
|
133 datatype proof = Unproved of P.proof_step | Proved of theorem |
|
134 |
|
135 |
|
136 |
131 |
137 (** core proof rules **) |
132 (** core proof rules **) |
138 |
133 |
139 (* assumption *) |
134 (* assumption *) |
140 |
|
141 local |
135 local |
142 val remove_trigger = @{lemma "trigger t p == p" |
136 val remove_trigger = @{lemma "trigger t p == p" |
143 by (rule eq_reflection, rule trigger_def)} |
137 by (rule eq_reflection, rule trigger_def)} |
144 |
138 |
145 val remove_weight = @{lemma "weight w p == p" |
139 val remove_weight = @{lemma "weight w p == p" |
176 fun find_assm ctxt (unfolds, assms) ct = |
170 fun find_assm ctxt (unfolds, assms) ct = |
177 fst (lookup_assm ctxt assms (Thm.rhs_of (rewrite_conv ctxt unfolds ct))) |
171 fst (lookup_assm ctxt assms (Thm.rhs_of (rewrite_conv ctxt unfolds ct))) |
178 end |
172 end |
179 |
173 |
180 |
174 |
181 |
|
182 (* P = Q ==> P ==> Q or P --> Q ==> P ==> Q *) |
175 (* P = Q ==> P ==> Q or P --> Q ==> P ==> Q *) |
183 local |
176 local |
184 val meta_iffD1 = @{lemma "P == Q ==> P ==> (Q::bool)" by simp} |
177 val meta_iffD1 = @{lemma "P == Q ==> P ==> (Q::bool)" by simp} |
185 val meta_iffD1_c = T.precompose2 Thm.dest_binop meta_iffD1 |
178 val meta_iffD1_c = T.precompose2 Thm.dest_binop meta_iffD1 |
186 |
179 |
194 val thm = T.compose iffD1_c pq handle THM _ => T.compose mp_c pq |
187 val thm = T.compose iffD1_c pq handle THM _ => T.compose mp_c pq |
195 in Thm (Thm.implies_elim thm p) end |
188 in Thm (Thm.implies_elim thm p) end |
196 end |
189 end |
197 |
190 |
198 |
191 |
199 |
|
200 (* and_elim: P1 & ... & Pn ==> Pi *) |
192 (* and_elim: P1 & ... & Pn ==> Pi *) |
201 (* not_or_elim: ~(P1 | ... | Pn) ==> ~Pi *) |
193 (* not_or_elim: ~(P1 | ... | Pn) ==> ~Pi *) |
202 local |
194 local |
203 fun is_sublit conj t = L.exists_lit conj (fn u => u aconv t) |
195 fun is_sublit conj t = L.exists_lit conj (fn u => u aconv t) |
204 |
196 |
206 let |
198 let |
207 val lit = the (L.get_first_lit (is_sublit conj t) lits) |
199 val lit = the (L.get_first_lit (is_sublit conj t) lits) |
208 val ls = L.explode conj false false [t] lit |
200 val ls = L.explode conj false false [t] lit |
209 val lits' = fold L.insert_lit ls (L.delete_lit lit lits) |
201 val lits' = fold L.insert_lit ls (L.delete_lit lit lits) |
210 |
202 |
211 fun upd (Proved thm) = Proved (Literals (thm_of thm, lits')) |
203 fun upd thm = Literals (thm_of thm, lits') |
212 | upd p = p |
|
213 in (the (L.lookup_lit lits' t), Inttab.map_entry idx upd ptab) end |
204 in (the (L.lookup_lit lits' t), Inttab.map_entry idx upd ptab) end |
214 |
205 |
215 fun lit_elim conj (p, idx) ct ptab = |
206 fun lit_elim conj (p, idx) ct ptab = |
216 let val lits = literals_of p |
207 let val lits = literals_of p |
217 in |
208 in |
223 val and_elim = lit_elim true |
214 val and_elim = lit_elim true |
224 val not_or_elim = lit_elim false |
215 val not_or_elim = lit_elim false |
225 end |
216 end |
226 |
217 |
227 |
218 |
228 |
|
229 (* P1, ..., Pn |- False ==> |- ~P1 | ... | ~Pn *) |
219 (* P1, ..., Pn |- False ==> |- ~P1 | ... | ~Pn *) |
230 local |
220 local |
231 fun step lit thm = |
221 fun step lit thm = |
232 Thm.implies_elim (Thm.implies_intr (Thm.cprop_of lit) thm) lit |
222 Thm.implies_elim (Thm.implies_intr (Thm.cprop_of lit) thm) lit |
233 val explode_disj = L.explode false false false |
223 val explode_disj = L.explode false false false |
242 val hyps = map_filter (try HOLogic.dest_Trueprop) (#hyps (Thm.rep_thm thm)) |
232 val hyps = map_filter (try HOLogic.dest_Trueprop) (#hyps (Thm.rep_thm thm)) |
243 in Thm (T.compose ccontr (T.under_assumption (intro hyps thm) cu)) end |
233 in Thm (T.compose ccontr (T.under_assumption (intro hyps thm) cu)) end |
244 end |
234 end |
245 |
235 |
246 |
236 |
247 |
|
248 (* \/{P1, ..., Pn, Q1, ..., Qn}, ~P1, ..., ~Pn ==> \/{Q1, ..., Qn} *) |
237 (* \/{P1, ..., Pn, Q1, ..., Qn}, ~P1, ..., ~Pn ==> \/{Q1, ..., Qn} *) |
249 local |
238 local |
250 val explode_disj = L.explode false true false |
239 val explode_disj = L.explode false true false |
251 val join_disj = L.join false |
240 val join_disj = L.join false |
252 fun unit thm thms th = |
241 fun unit thm thms th = |
262 |> T.under_assumption (unit thm thms) |
251 |> T.under_assumption (unit thm thms) |
263 |> Thm o T.discharge thm o T.compose contrapos |
252 |> Thm o T.discharge thm o T.compose contrapos |
264 end |
253 end |
265 |
254 |
266 |
255 |
267 |
|
268 (* P ==> P == True or P ==> P == False *) |
256 (* P ==> P == True or P ==> P == False *) |
269 local |
257 local |
270 val iff1 = @{lemma "P ==> P == (~ False)" by simp} |
258 val iff1 = @{lemma "P ==> P == (~ False)" by simp} |
271 val iff2 = @{lemma "~P ==> P == False" by simp} |
259 val iff2 = @{lemma "~P ==> P == False" by simp} |
272 in |
260 in |
273 fun iff_true thm = MetaEq (thm COMP iff1) |
261 fun iff_true thm = MetaEq (thm COMP iff1) |
274 fun iff_false thm = MetaEq (thm COMP iff2) |
262 fun iff_false thm = MetaEq (thm COMP iff2) |
275 end |
263 end |
276 |
|
277 |
264 |
278 |
265 |
279 (* distributivity of | over & *) |
266 (* distributivity of | over & *) |
280 fun distributivity ctxt = Thm o try_apply ctxt [] [ |
267 fun distributivity ctxt = Thm o try_apply ctxt [] [ |
281 named ctxt "fast" (T.by_tac (Classical.fast_tac HOL_cs))] |
268 named ctxt "fast" (T.by_tac (Classical.fast_tac HOL_cs))] |
282 (* FIXME: not very well tested *) |
269 (* FIXME: not very well tested *) |
283 |
270 |
284 |
271 |
285 |
|
286 (* Tseitin-like axioms *) |
272 (* Tseitin-like axioms *) |
287 |
|
288 local |
273 local |
289 val disjI1 = @{lemma "(P ==> Q) ==> ~P | Q" by fast} |
274 val disjI1 = @{lemma "(P ==> Q) ==> ~P | Q" by fast} |
290 val disjI2 = @{lemma "(~P ==> Q) ==> P | Q" by fast} |
275 val disjI2 = @{lemma "(~P ==> Q) ==> P | Q" by fast} |
291 val disjI3 = @{lemma "(~Q ==> P) ==> P | Q" by fast} |
276 val disjI3 = @{lemma "(~Q ==> P) ==> P | Q" by fast} |
292 val disjI4 = @{lemma "(Q ==> P) ==> P | ~Q" by fast} |
277 val disjI4 = @{lemma "(Q ==> P) ==> P | ~Q" by fast} |
332 T.by_abstraction (true, false) ctxt [] (fn ctxt' => |
317 T.by_abstraction (true, false) ctxt [] (fn ctxt' => |
333 named ctxt' "simp+fast" (T.by_tac simp_fast_tac))] |
318 named ctxt' "simp+fast" (T.by_tac simp_fast_tac))] |
334 end |
319 end |
335 |
320 |
336 |
321 |
337 |
|
338 (* local definitions *) |
322 (* local definitions *) |
339 local |
323 local |
340 val intro_rules = [ |
324 val intro_rules = [ |
341 @{lemma "n == P ==> (~n | P) & (n | ~P)" by simp}, |
325 @{lemma "n == P ==> (~n | P) & (n | ~P)" by simp}, |
342 @{lemma "n == (if P then s else t) ==> (~P | n = s) & (P | n = t)" |
326 @{lemma "n == (if P then s else t) ==> (~P | n = s) & (P | n = t)" |
361 get_first (try (fn rule => MetaEq (thm COMP rule))) apply_rules |
345 get_first (try (fn rule => MetaEq (thm COMP rule))) apply_rules |
362 |> the_default (Thm thm) |
346 |> the_default (Thm thm) |
363 end |
347 end |
364 |
348 |
365 |
349 |
366 |
|
367 (* negation normal form *) |
350 (* negation normal form *) |
368 |
|
369 local |
351 local |
370 val quant_rules1 = ([ |
352 val quant_rules1 = ([ |
371 @{lemma "(!!x. P x == Q) ==> ALL x. P x == Q" by simp}, |
353 @{lemma "(!!x. P x == Q) ==> ALL x. P x == Q" by simp}, |
372 @{lemma "(!!x. P x == Q) ==> EX x. P x == Q" by simp}], [ |
354 @{lemma "(!!x. P x == Q) ==> EX x. P x == Q" by simp}], [ |
373 @{lemma "(!!x. P x == Q x) ==> ALL x. P x == ALL x. Q x" by simp}, |
355 @{lemma "(!!x. P x == Q x) ==> ALL x. P x == ALL x. Q x" by simp}, |
414 |
396 |
415 (* |- t = t *) |
397 (* |- t = t *) |
416 fun refl ct = MetaEq (Thm.reflexive (Thm.dest_arg (Thm.dest_arg ct))) |
398 fun refl ct = MetaEq (Thm.reflexive (Thm.dest_arg (Thm.dest_arg ct))) |
417 |
399 |
418 |
400 |
419 |
|
420 (* s = t ==> t = s *) |
401 (* s = t ==> t = s *) |
421 local |
402 local |
422 val symm_rule = @{lemma "s = t ==> t == s" by simp} |
403 val symm_rule = @{lemma "s = t ==> t == s" by simp} |
423 in |
404 in |
424 fun symm (MetaEq thm) = MetaEq (Thm.symmetric thm) |
405 fun symm (MetaEq thm) = MetaEq (Thm.symmetric thm) |
425 | symm p = MetaEq (thm_of p COMP symm_rule) |
406 | symm p = MetaEq (thm_of p COMP symm_rule) |
426 end |
407 end |
427 |
|
428 |
408 |
429 |
409 |
430 (* s = t ==> t = u ==> s = u *) |
410 (* s = t ==> t = u ==> s = u *) |
431 local |
411 local |
432 val trans1 = @{lemma "s == t ==> t = u ==> s == u" by simp} |
412 val trans1 = @{lemma "s == t ==> t = u ==> s == u" by simp} |
436 fun trans (MetaEq thm1) (MetaEq thm2) = MetaEq (Thm.transitive thm1 thm2) |
416 fun trans (MetaEq thm1) (MetaEq thm2) = MetaEq (Thm.transitive thm1 thm2) |
437 | trans (MetaEq thm) q = MetaEq (thm_of q COMP (thm COMP trans1)) |
417 | trans (MetaEq thm) q = MetaEq (thm_of q COMP (thm COMP trans1)) |
438 | trans p (MetaEq thm) = MetaEq (thm COMP (thm_of p COMP trans2)) |
418 | trans p (MetaEq thm) = MetaEq (thm COMP (thm_of p COMP trans2)) |
439 | trans p q = MetaEq (thm_of q COMP (thm_of p COMP trans3)) |
419 | trans p q = MetaEq (thm_of q COMP (thm_of p COMP trans3)) |
440 end |
420 end |
441 |
|
442 |
421 |
443 |
422 |
444 (* t1 = s1 ==> ... ==> tn = sn ==> f t1 ... tn = f s1 .. sn |
423 (* t1 = s1 ==> ... ==> tn = sn ==> f t1 ... tn = f s1 .. sn |
445 (reflexive antecendents are droppped) *) |
424 (reflexive antecendents are droppped) *) |
446 local |
425 local |
494 val cp = Thm.dest_binop (Thm.dest_arg ct) |
473 val cp = Thm.dest_binop (Thm.dest_arg ct) |
495 in MetaEq (prove_eq_exn lookup cp handle MONO => mono lookup cp) end |
474 in MetaEq (prove_eq_exn lookup cp handle MONO => mono lookup cp) end |
496 end |
475 end |
497 |
476 |
498 |
477 |
499 |
|
500 (* |- f a b = f b a (where f is equality) *) |
478 (* |- f a b = f b a (where f is equality) *) |
501 local |
479 local |
502 val rule = @{lemma "a = b == b = a" by (atomize(full)) (rule eq_commute)} |
480 val rule = @{lemma "a = b == b = a" by (atomize(full)) (rule eq_commute)} |
503 in |
481 in |
504 fun commutativity ct = MetaEq (T.match_instantiate I (T.as_meta_eq ct) rule) |
482 fun commutativity ct = MetaEq (T.match_instantiate I (T.as_meta_eq ct) rule) |
522 val cu = T.as_meta_eq ct |
500 val cu = T.as_meta_eq ct |
523 in MetaEq (T.by_tac (REPEAT_ALL_NEW (Tactic.match_tac rules')) cu) end |
501 in MetaEq (T.by_tac (REPEAT_ALL_NEW (Tactic.match_tac rules')) cu) end |
524 end |
502 end |
525 |
503 |
526 |
504 |
527 |
|
528 (* |- ((ALL x. P x) | Q) = (ALL x. P x | Q) *) |
505 (* |- ((ALL x. P x) | Q) = (ALL x. P x | Q) *) |
529 fun pull_quant ctxt = Thm o try_apply ctxt [] [ |
506 fun pull_quant ctxt = Thm o try_apply ctxt [] [ |
530 named ctxt "fast" (T.by_tac (Classical.fast_tac HOL_cs))] |
507 named ctxt "fast" (T.by_tac (Classical.fast_tac HOL_cs))] |
531 (* FIXME: not very well tested *) |
508 (* FIXME: not very well tested *) |
532 |
509 |
533 |
510 |
534 |
|
535 (* |- (ALL x. P x & Q x) = ((ALL x. P x) & (ALL x. Q x)) *) |
511 (* |- (ALL x. P x & Q x) = ((ALL x. P x) & (ALL x. Q x)) *) |
536 fun push_quant ctxt = Thm o try_apply ctxt [] [ |
512 fun push_quant ctxt = Thm o try_apply ctxt [] [ |
537 named ctxt "fast" (T.by_tac (Classical.fast_tac HOL_cs))] |
513 named ctxt "fast" (T.by_tac (Classical.fast_tac HOL_cs))] |
538 (* FIXME: not very well tested *) |
514 (* FIXME: not very well tested *) |
539 |
515 |
540 |
516 |
541 |
|
542 (* |- (ALL x1 ... xn y1 ... yn. P x1 ... xn) = (ALL x1 ... xn. P x1 ... xn) *) |
517 (* |- (ALL x1 ... xn y1 ... yn. P x1 ... xn) = (ALL x1 ... xn. P x1 ... xn) *) |
543 local |
518 local |
544 val elim_all = @{lemma "(ALL x. P) == P" by simp} |
519 val elim_all = @{lemma "(ALL x. P) == P" by simp} |
545 val elim_ex = @{lemma "(EX x. P) == P" by simp} |
520 val elim_ex = @{lemma "(EX x. P) == P" by simp} |
546 |
521 |
555 in |
530 in |
556 fun elim_unused_vars ctxt = Thm o T.by_tac (elim_unused_tac ctxt) |
531 fun elim_unused_vars ctxt = Thm o T.by_tac (elim_unused_tac ctxt) |
557 end |
532 end |
558 |
533 |
559 |
534 |
560 |
|
561 (* |- (ALL x1 ... xn. ~(x1 = t1 & ... xn = tn) | P x1 ... xn) = P t1 ... tn *) |
535 (* |- (ALL x1 ... xn. ~(x1 = t1 & ... xn = tn) | P x1 ... xn) = P t1 ... tn *) |
562 fun dest_eq_res ctxt = Thm o try_apply ctxt [] [ |
536 fun dest_eq_res ctxt = Thm o try_apply ctxt [] [ |
563 named ctxt "fast" (T.by_tac (Classical.fast_tac HOL_cs))] |
537 named ctxt "fast" (T.by_tac (Classical.fast_tac HOL_cs))] |
564 (* FIXME: not very well tested *) |
538 (* FIXME: not very well tested *) |
565 |
539 |
566 |
540 |
567 |
|
568 (* |- ~(ALL x1...xn. P x1...xn) | P a1...an *) |
541 (* |- ~(ALL x1...xn. P x1...xn) | P a1...an *) |
569 local |
542 local |
570 val rule = @{lemma "~ P x | Q ==> ~(ALL x. P x) | Q" by fast} |
543 val rule = @{lemma "~ P x | Q ==> ~(ALL x. P x) | Q" by fast} |
571 in |
544 in |
572 val quant_inst = Thm o T.by_tac ( |
545 val quant_inst = Thm o T.by_tac ( |
573 REPEAT_ALL_NEW (Tactic.match_tac [rule]) |
546 REPEAT_ALL_NEW (Tactic.match_tac [rule]) |
574 THEN' Tactic.rtac @{thm excluded_middle}) |
547 THEN' Tactic.rtac @{thm excluded_middle}) |
575 end |
548 end |
576 |
|
577 |
549 |
578 |
550 |
579 (* c = SOME x. P x |- (EX x. P x) = P c |
551 (* c = SOME x. P x |- (EX x. P x) = P c |
580 c = SOME x. ~ P x |- ~(ALL x. P x) = ~ P c *) |
552 c = SOME x. ~ P x |- ~(ALL x. P x) = ~ P c *) |
581 local |
553 local |
643 |>> MetaEq o snd |
615 |>> MetaEq o snd |
644 end |
616 end |
645 end |
617 end |
646 |
618 |
647 |
619 |
648 |
|
649 (** theory proof rules **) |
620 (** theory proof rules **) |
650 |
621 |
651 (* theory lemmas: linear arithmetic, arrays *) |
622 (* theory lemmas: linear arithmetic, arrays *) |
652 |
|
653 fun th_lemma ctxt simpset thms = Thm o try_apply ctxt thms [ |
623 fun th_lemma ctxt simpset thms = Thm o try_apply ctxt thms [ |
654 T.by_abstraction (false, true) ctxt thms (fn ctxt' => T.by_tac ( |
624 T.by_abstraction (false, true) ctxt thms (fn ctxt' => T.by_tac ( |
655 NAMED ctxt' "arith" (Arith_Data.arith_tac ctxt') |
625 NAMED ctxt' "arith" (Arith_Data.arith_tac ctxt') |
656 ORELSE' NAMED ctxt' "simp+arith" (Simplifier.simp_tac simpset THEN_ALL_NEW |
626 ORELSE' NAMED ctxt' "simp+arith" (Simplifier.simp_tac simpset THEN_ALL_NEW |
657 Arith_Data.arith_tac ctxt')))] |
627 Arith_Data.arith_tac ctxt')))] |
658 |
|
659 |
628 |
660 |
629 |
661 (* rewriting: prove equalities: |
630 (* rewriting: prove equalities: |
662 * ACI of conjunction/disjunction |
631 * ACI of conjunction/disjunction |
663 * contradiction, excluded middle |
632 * contradiction, excluded middle |
717 |
686 |
718 end |
687 end |
719 |
688 |
720 |
689 |
721 |
690 |
722 (** proof reconstruction **) |
691 (* proof reconstruction *) |
723 |
692 |
724 (* tracing and checking *) |
693 (** tracing and checking **) |
725 |
694 |
726 local |
695 fun trace_before ctxt idx = SMT_Config.trace_msg ctxt (fn r => |
727 fun count_rules ptab = |
696 "Z3: #" ^ string_of_int idx ^ ": " ^ P.string_of_rule r) |
728 let |
697 |
729 fun count (_, Unproved _) (solved, total) = (solved, total + 1) |
698 fun check_after idx r ps ct (p, (ctxt, _)) = |
730 | count (_, Proved _) (solved, total) = (solved + 1, total + 1) |
699 if not (Config.get ctxt SMT_Config.trace) then () |
731 in Inttab.fold count ptab (0, 0) end |
700 else |
732 |
|
733 fun header idx r (solved, total) = |
|
734 "Z3: #" ^ string_of_int idx ^ ": " ^ P.string_of_rule r ^ " (goal " ^ |
|
735 string_of_int (solved + 1) ^ " of " ^ string_of_int total ^ ")" |
|
736 |
|
737 fun check ctxt idx r ps ct p = |
|
738 let val thm = thm_of p |> tap (Thm.join_proofs o single) |
701 let val thm = thm_of p |> tap (Thm.join_proofs o single) |
739 in |
702 in |
740 if (Thm.cprop_of thm) aconvc ct then () |
703 if (Thm.cprop_of thm) aconvc ct then () |
741 else z3_exn (Pretty.string_of (Pretty.big_list ("proof step failed: " ^ |
704 else z3_exn (Pretty.string_of (Pretty.big_list ("proof step failed: " ^ |
742 quote (P.string_of_rule r) ^ " (#" ^ string_of_int idx ^ ")") |
705 quote (P.string_of_rule r) ^ " (#" ^ string_of_int idx ^ ")") |
743 (pretty_goal ctxt (map (thm_of o fst) ps) (Thm.prop_of thm) @ |
706 (pretty_goal ctxt (map (thm_of o fst) ps) (Thm.prop_of thm) @ |
744 [Pretty.block [Pretty.str "expected: ", |
707 [Pretty.block [Pretty.str "expected: ", |
745 Syntax.pretty_term ctxt (Thm.term_of ct)]]))) |
708 Syntax.pretty_term ctxt (Thm.term_of ct)]]))) |
746 end |
709 end |
747 in |
710 |
748 fun trace_rule idx prove r ps ct (cxp as (ctxt, ptab)) = |
711 |
749 let |
712 (** overall reconstruction procedure **) |
750 val _ = SMT_Config.trace_msg ctxt (header idx r o count_rules) ptab |
|
751 val result as (p, (ctxt', _)) = prove r ps ct cxp |
|
752 val _ = if not (Config.get ctxt' SMT_Config.trace) then () |
|
753 else check ctxt' idx r ps ct p |
|
754 in result end |
|
755 end |
|
756 |
|
757 |
|
758 (* overall reconstruction procedure *) |
|
759 |
713 |
760 local |
714 local |
761 fun not_supported r = raise Fail ("Z3: proof rule not implemented: " ^ |
715 fun not_supported r = raise Fail ("Z3: proof rule not implemented: " ^ |
762 quote (P.string_of_rule r)) |
716 quote (P.string_of_rule r)) |
763 |
717 |
764 fun step assms simpset vars r ps ct (cxp as (cx, ptab)) = |
718 fun prove_step assms simpset vars r ps ct (cxp as (cx, ptab)) = |
765 (case (r, ps) of |
719 (case (r, ps) of |
766 (* core rules *) |
720 (* core rules *) |
767 (P.TrueAxiom, _) => (Thm L.true_thm, cxp) |
721 (P.True_Axiom, _) => (Thm L.true_thm, cxp) |
768 | (P.Asserted, _) => (asserted cx assms ct, cxp) |
722 | (P.Asserted, _) => (asserted cx assms ct, cxp) |
769 | (P.Goal, _) => (asserted cx assms ct, cxp) |
723 | (P.Goal, _) => (asserted cx assms ct, cxp) |
770 | (P.ModusPonens, [(p, _), (q, _)]) => (mp q (thm_of p), cxp) |
724 | (P.Modus_Ponens, [(p, _), (q, _)]) => (mp q (thm_of p), cxp) |
771 | (P.ModusPonensOeq, [(p, _), (q, _)]) => (mp q (thm_of p), cxp) |
725 | (P.Modus_Ponens_Oeq, [(p, _), (q, _)]) => (mp q (thm_of p), cxp) |
772 | (P.AndElim, [(p, i)]) => and_elim (p, i) ct ptab ||> pair cx |
726 | (P.And_Elim, [(p, i)]) => and_elim (p, i) ct ptab ||> pair cx |
773 | (P.NotOrElim, [(p, i)]) => not_or_elim (p, i) ct ptab ||> pair cx |
727 | (P.Not_Or_Elim, [(p, i)]) => not_or_elim (p, i) ct ptab ||> pair cx |
774 | (P.Hypothesis, _) => (Thm (Thm.assume ct), cxp) |
728 | (P.Hypothesis, _) => (Thm (Thm.assume ct), cxp) |
775 | (P.Lemma, [(p, _)]) => (lemma (thm_of p) ct, cxp) |
729 | (P.Lemma, [(p, _)]) => (lemma (thm_of p) ct, cxp) |
776 | (P.UnitResolution, (p, _) :: ps) => |
730 | (P.Unit_Resolution, (p, _) :: ps) => |
777 (unit_resolution (thm_of p) (map (thm_of o fst) ps) ct, cxp) |
731 (unit_resolution (thm_of p) (map (thm_of o fst) ps) ct, cxp) |
778 | (P.IffTrue, [(p, _)]) => (iff_true (thm_of p), cxp) |
732 | (P.Iff_True, [(p, _)]) => (iff_true (thm_of p), cxp) |
779 | (P.IffFalse, [(p, _)]) => (iff_false (thm_of p), cxp) |
733 | (P.Iff_False, [(p, _)]) => (iff_false (thm_of p), cxp) |
780 | (P.Distributivity, _) => (distributivity cx ct, cxp) |
734 | (P.Distributivity, _) => (distributivity cx ct, cxp) |
781 | (P.DefAxiom, _) => (def_axiom cx ct, cxp) |
735 | (P.Def_Axiom, _) => (def_axiom cx ct, cxp) |
782 | (P.IntroDef, _) => intro_def ct cx ||> rpair ptab |
736 | (P.Intro_Def, _) => intro_def ct cx ||> rpair ptab |
783 | (P.ApplyDef, [(p, _)]) => (apply_def (thm_of p), cxp) |
737 | (P.Apply_Def, [(p, _)]) => (apply_def (thm_of p), cxp) |
784 | (P.IffOeq, [(p, _)]) => (p, cxp) |
738 | (P.Iff_Oeq, [(p, _)]) => (p, cxp) |
785 | (P.NnfPos, _) => (nnf cx vars (map fst ps) ct, cxp) |
739 | (P.Nnf_Pos, _) => (nnf cx vars (map fst ps) ct, cxp) |
786 | (P.NnfNeg, _) => (nnf cx vars (map fst ps) ct, cxp) |
740 | (P.Nnf_Neg, _) => (nnf cx vars (map fst ps) ct, cxp) |
787 |
741 |
788 (* equality rules *) |
742 (* equality rules *) |
789 | (P.Reflexivity, _) => (refl ct, cxp) |
743 | (P.Reflexivity, _) => (refl ct, cxp) |
790 | (P.Symmetry, [(p, _)]) => (symm p, cxp) |
744 | (P.Symmetry, [(p, _)]) => (symm p, cxp) |
791 | (P.Transitivity, [(p, _), (q, _)]) => (trans p q, cxp) |
745 | (P.Transitivity, [(p, _), (q, _)]) => (trans p q, cxp) |
792 | (P.Monotonicity, _) => (monotonicity (map fst ps) ct, cxp) |
746 | (P.Monotonicity, _) => (monotonicity (map fst ps) ct, cxp) |
793 | (P.Commutativity, _) => (commutativity ct, cxp) |
747 | (P.Commutativity, _) => (commutativity ct, cxp) |
794 |
748 |
795 (* quantifier rules *) |
749 (* quantifier rules *) |
796 | (P.QuantIntro, [(p, _)]) => (quant_intro vars p ct, cxp) |
750 | (P.Quant_Intro, [(p, _)]) => (quant_intro vars p ct, cxp) |
797 | (P.PullQuant, _) => (pull_quant cx ct, cxp) |
751 | (P.Pull_Quant, _) => (pull_quant cx ct, cxp) |
798 | (P.PushQuant, _) => (push_quant cx ct, cxp) |
752 | (P.Push_Quant, _) => (push_quant cx ct, cxp) |
799 | (P.ElimUnusedVars, _) => (elim_unused_vars cx ct, cxp) |
753 | (P.Elim_Unused_Vars, _) => (elim_unused_vars cx ct, cxp) |
800 | (P.DestEqRes, _) => (dest_eq_res cx ct, cxp) |
754 | (P.Dest_Eq_Res, _) => (dest_eq_res cx ct, cxp) |
801 | (P.QuantInst, _) => (quant_inst ct, cxp) |
755 | (P.Quant_Inst, _) => (quant_inst ct, cxp) |
802 | (P.Skolemize, _) => skolemize ct cx ||> rpair ptab |
756 | (P.Skolemize, _) => skolemize ct cx ||> rpair ptab |
803 |
757 |
804 (* theory rules *) |
758 (* theory rules *) |
805 | (P.ThLemma _, _) => (* FIXME: use arguments *) |
759 | (P.Th_Lemma _, _) => (* FIXME: use arguments *) |
806 (th_lemma cx simpset (map (thm_of o fst) ps) ct, cxp) |
760 (th_lemma cx simpset (map (thm_of o fst) ps) ct, cxp) |
807 | (P.Rewrite, _) => rewrite simpset [] ct cx ||> rpair ptab |
761 | (P.Rewrite, _) => rewrite simpset [] ct cx ||> rpair ptab |
808 | (P.RewriteStar, ps) => rewrite simpset (map fst ps) ct cx ||> rpair ptab |
762 | (P.Rewrite_Star, ps) => rewrite simpset (map fst ps) ct cx ||> rpair ptab |
809 |
763 |
810 | (P.NnfStar, _) => not_supported r |
764 | (P.Nnf_Star, _) => not_supported r |
811 | (P.CnfStar, _) => not_supported r |
765 | (P.Cnf_Star, _) => not_supported r |
812 | (P.TransitivityStar, _) => not_supported r |
766 | (P.Transitivity_Star, _) => not_supported r |
813 | (P.PullQuantStar, _) => not_supported r |
767 | (P.Pull_Quant_Star, _) => not_supported r |
814 |
768 |
815 | _ => raise Fail ("Z3: proof rule " ^ quote (P.string_of_rule r) ^ |
769 | _ => raise Fail ("Z3: proof rule " ^ quote (P.string_of_rule r) ^ |
816 " has an unexpected number of arguments.")) |
770 " has an unexpected number of arguments.")) |
817 |
771 |
818 fun prove ctxt assms vars = |
772 fun lookup_proof ptab idx = |
773 (case Inttab.lookup ptab idx of |
|
774 SOME p => (p, idx) |
|
775 | NONE => z3_exn ("unknown proof id: " ^ quote (string_of_int idx))) |
|
776 |
|
777 fun prove assms simpset vars (idx, step) (_, cxp as (ctxt, ptab)) = |
|
819 let |
778 let |
820 val simpset = T.make_simpset ctxt (Z3_Simps.get ctxt) |
779 val P.Proof_Step {rule=r, prems, prop, ...} = step |
821 |
780 val ps = map (lookup_proof ptab) prems |
822 fun conclude idx rule prop (ps, cxp) = |
781 val _ = trace_before ctxt idx r |
823 trace_rule idx (step assms simpset vars) rule ps prop cxp |
782 val (thm, (ctxt', ptab')) = |
824 |-> (fn p => apsnd (Inttab.update (idx, Proved p)) #> pair p) |
783 cxp |
825 |
784 |> prove_step assms simpset vars r ps prop |
826 fun lookup idx (cxp as (_, ptab)) = |
785 |> tap (check_after idx r ps prop) |
827 (case Inttab.lookup ptab idx of |
786 in (thm, (ctxt', Inttab.update (idx, thm) ptab')) end |
828 SOME (Unproved (P.Proof_Step {rule, prems, prop})) => |
|
829 fold_map lookup prems cxp |
|
830 |>> map2 rpair prems |
|
831 |> conclude idx rule prop |
|
832 | SOME (Proved p) => (p, cxp) |
|
833 | NONE => z3_exn ("unknown proof id: " ^ quote (string_of_int idx))) |
|
834 |
|
835 fun result (p, (cx, _)) = (thm_of p, cx) |
|
836 in |
|
837 (fn idx => result o lookup idx o pair ctxt o Inttab.map (K Unproved)) |
|
838 end |
|
839 |
787 |
840 val disch_rules = map (pair false) |
788 val disch_rules = map (pair false) |
841 [@{thm allI}, @{thm refl}, @{thm reflexive}] |
789 [@{thm allI}, @{thm refl}, @{thm reflexive}] |
842 |
790 |
843 fun disch_assm thm = |
791 fun disch_assm thm = |
845 else |
793 else |
846 (case Seq.pull (Thm.biresolution false disch_rules 1 thm) of |
794 (case Seq.pull (Thm.biresolution false disch_rules 1 thm) of |
847 SOME (thm', _) => disch_assm thm' |
795 SOME (thm', _) => disch_assm thm' |
848 | NONE => raise THM ("failed to discharge premise", 1, [thm])) |
796 | NONE => raise THM ("failed to discharge premise", 1, [thm])) |
849 |
797 |
850 fun discharge outer_ctxt (thm, inner_ctxt) = |
798 fun discharge outer_ctxt (p, (inner_ctxt, _)) = |
851 thm |
799 thm_of p |
852 |> singleton (ProofContext.export inner_ctxt outer_ctxt) |
800 |> singleton (ProofContext.export inner_ctxt outer_ctxt) |
853 |> tap (tracing o prefix "final goal: " o PolyML.makestring) |
|
854 |> disch_assm |
801 |> disch_assm |
855 |
802 |
856 fun filter_assms ctxt assms ptab = |
803 fun filter_assms ctxt assms = |
857 let |
804 let |
858 fun step r ct = |
805 fun add_assm r ct = |
859 (case r of |
806 (case r of |
860 P.Asserted => insert (op =) (find_assm ctxt assms ct) |
807 P.Asserted => insert (op =) (find_assm ctxt assms ct) |
861 | P.Goal => insert (op =) (find_assm ctxt assms ct) |
808 | P.Goal => insert (op =) (find_assm ctxt assms ct) |
862 | _ => I) |
809 | _ => I) |
863 |
810 in fold (fn (_, P.Proof_Step {rule, prop, ...}) => add_assm rule prop) end |
864 fun lookup idx = |
|
865 (case Inttab.lookup ptab idx of |
|
866 SOME (P.Proof_Step {rule, prems, prop}) => |
|
867 fold lookup prems #> step rule prop |
|
868 | NONE => z3_exn ("unknown proof id: " ^ quote (string_of_int idx))) |
|
869 in lookup end |
|
870 in |
811 in |
871 |
812 |
872 fun reconstruct outer_ctxt recon output = |
813 fun reconstruct outer_ctxt recon output = |
873 let |
814 let |
874 val {context=ctxt, typs, terms, rewrite_rules, assms} = recon |
815 val {context=ctxt, typs, terms, rewrite_rules, assms} = recon |
875 val (idx, (ptab, vars, ctxt')) = P.parse ctxt typs terms output |
816 val (steps, vars, ctxt') = P.parse ctxt typs terms output |
876 val assms' = prepare_assms ctxt' rewrite_rules assms |
817 val assms' = prepare_assms ctxt' rewrite_rules assms |
818 val simpset = T.make_simpset ctxt' (Z3_Simps.get ctxt') |
|
877 in |
819 in |
878 if Config.get ctxt' SMT_Config.filter_only_facts then |
820 if Config.get ctxt' SMT_Config.filter_only_facts then |
879 (filter_assms ctxt' assms' ptab idx [], @{thm TrueI}) |
821 (filter_assms ctxt' assms' steps [], @{thm TrueI}) |
880 else |
822 else |
881 prove ctxt' assms' vars idx ptab |
823 (Thm @{thm TrueI}, (ctxt', Inttab.empty)) |
824 |> fold (prove assms' simpset vars) steps |
|
882 |> discharge outer_ctxt |
825 |> discharge outer_ctxt |
883 |> pair [] |
826 |> pair [] |
884 end |
827 end |
885 |
828 |
886 end |
829 end |