src/HOL/Tools/SMT/z3_proof_reconstruction.ML
changeset 41130 130771a48c70
parent 41127 2ea84c8535c6
child 41131 fc9d503c3d67
equal deleted inserted replaced
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