src/HOL/SMT/Tools/z3_proof_tools.ML
author boehmes
Wed, 12 May 2010 23:53:59 +0200
changeset 36887 a96f9793d9c5
child 36888 c030819254d3
permissions -rw-r--r--
split monolithic Z3 proof reconstruction structure into separate structures, use one set of schematic theorems for all uncertain proof rules (to extend proof reconstruction by missing cases), added several schematic theorems, improved abstraction of goals (abstract all uninterpreted sub-terms, only leave builtin symbols)
     1 (*  Title:      HOL/SMT/Tools/z3_proof_tools.ML
     2     Author:     Sascha Boehme, TU Muenchen
     3 
     4 Helper functions required for Z3 proof reconstruction.
     5 *)
     6 
     7 signature Z3_PROOF_TOOLS =
     8 sig
     9   (* accessing and modifying terms *)
    10   val term_of: cterm -> term
    11   val prop_of: thm -> term
    12   val mk_prop: cterm -> cterm
    13   val as_meta_eq: cterm -> cterm
    14 
    15   (* theorem nets *)
    16   val thm_net_of: thm list -> thm Net.net
    17   val net_instance: thm Net.net -> cterm -> thm option
    18 
    19   (* proof combinators *)
    20   val under_assumption: (thm -> thm) -> cterm -> thm
    21   val with_conv: conv -> (cterm -> thm) -> cterm -> thm
    22   val discharge: thm -> thm -> thm
    23   val varify: string list -> thm -> thm
    24   val unfold_eqs: Proof.context -> thm list -> conv
    25   val match_instantiate: (cterm -> cterm) -> cterm -> thm -> thm
    26   val by_tac: (int -> tactic) -> cterm -> thm
    27   val make_hyp_def: thm -> cterm list * thm
    28   val by_abstraction: Proof.context -> thm list -> (Proof.context -> cterm ->
    29     thm) -> cterm -> thm
    30 
    31   (* a faster COMP *)
    32   type compose_data
    33   val precompose: (cterm -> cterm list) -> thm -> compose_data
    34   val precompose2: (cterm -> cterm * cterm) -> thm -> compose_data
    35   val compose: compose_data -> thm -> thm
    36 
    37   (* unfolding of 'distinct' *)
    38   val unfold_distinct_conv: conv
    39 
    40   (* simpset *)
    41   val make_simpset: Proof.context -> thm list -> simpset
    42 end
    43 
    44 structure Z3_Proof_Tools: Z3_PROOF_TOOLS =
    45 struct
    46 
    47 
    48 
    49 (* accessing terms *)
    50 
    51 val dest_prop = (fn @{term Trueprop} $ t => t | t => t)
    52 
    53 fun term_of ct = dest_prop (Thm.term_of ct)
    54 fun prop_of thm = dest_prop (Thm.prop_of thm)
    55 
    56 val mk_prop = Thm.capply @{cterm Trueprop}
    57 
    58 val (eqT, eq) = `(hd o Thm.dest_ctyp o Thm.ctyp_of_term) @{cpat "op =="}
    59 fun mk_meta_eq_cterm ct cu =
    60   let val inst = ([(eqT, Thm.ctyp_of_term ct)], [])
    61   in Thm.mk_binop (Thm.instantiate_cterm inst eq) ct cu end
    62 
    63 fun as_meta_eq ct = uncurry mk_meta_eq_cterm (Thm.dest_binop (Thm.dest_arg ct))
    64 
    65 
    66 
    67 (* theorem nets *)
    68 
    69 fun thm_net_of thms =
    70   let fun insert thm = Net.insert_term (K false) (Thm.prop_of thm, thm)
    71   in fold insert thms Net.empty end
    72 
    73 fun maybe_instantiate ct thm =
    74   try Thm.first_order_match (Thm.cprop_of thm, ct)
    75   |> Option.map (fn inst => Thm.instantiate inst thm)
    76 
    77 fun first_of thms ct = get_first (maybe_instantiate ct) thms
    78 fun net_instance net ct = first_of (Net.match_term net (Thm.term_of ct)) ct
    79 
    80 
    81 
    82 (* proof combinators *)
    83 
    84 fun under_assumption f ct =
    85   let val ct' = mk_prop ct
    86   in Thm.implies_intr ct' (f (Thm.assume ct')) end
    87 
    88 fun with_conv conv prove ct =
    89   let val eq = Thm.symmetric (conv ct)
    90   in Thm.equal_elim eq (prove (Thm.lhs_of eq)) end
    91 
    92 fun discharge p pq = Thm.implies_elim pq p
    93 
    94 fun varify vars = Drule.generalize ([], vars)
    95 
    96 fun unfold_eqs _ [] = Conv.all_conv
    97   | unfold_eqs ctxt eqs =
    98       More_Conv.top_sweep_conv (K (More_Conv.rewrs_conv eqs)) ctxt
    99 
   100 fun match_instantiate f ct thm =
   101   Thm.instantiate (Thm.match (f (Thm.cprop_of thm), ct)) thm
   102 
   103 fun by_tac tac ct = Goal.norm_result (Goal.prove_internal [] ct (K (tac 1)))
   104 
   105 (* |- c x == t x ==> P (c x)  ~~>  c == t |- P (c x) *) 
   106 fun make_hyp_def thm =
   107   let
   108     val (lhs, rhs) = Thm.dest_binop (Thm.cprem_of thm 1)
   109     val (cf, cvs) = Drule.strip_comb lhs
   110     val eq = mk_meta_eq_cterm cf (fold_rev Thm.cabs cvs rhs)
   111     fun apply cv th =
   112       Thm.combination th (Thm.reflexive cv)
   113       |> Conv.fconv_rule (Conv.arg_conv (Thm.beta_conversion false))
   114   in ([eq], Thm.implies_elim thm (fold apply cvs (Thm.assume eq))) end
   115 
   116 
   117 
   118 (* abstraction *)
   119 
   120 local
   121 
   122 fun typ_of ct = #T (Thm.rep_cterm ct)
   123 fun certify ctxt = Thm.cterm_of (ProofContext.theory_of ctxt)
   124 
   125 fun abs_context ctxt = (ctxt, Termtab.empty, 1, false)
   126 
   127 fun context_of (ctxt, _, _, _) = ctxt
   128 
   129 fun replace (cv, ct) = Thm.forall_elim ct o Thm.forall_intr cv
   130 
   131 fun abs_instantiate (_, tab, _, beta_norm) =
   132   fold replace (map snd (Termtab.dest tab)) #>
   133   beta_norm ? Conv.fconv_rule (Thm.beta_conversion true)
   134 
   135 fun generalize cvs =
   136   let
   137     val no_name = ""
   138 
   139     fun dest (Free (n, _)) = n
   140       | dest _ = no_name
   141 
   142     fun gen vs (t as Free (n, _)) =
   143           let val i = find_index (equal n) vs
   144           in
   145             if i >= 0 then insert (op aconvc) (nth cvs i) #> pair (Bound i)
   146             else pair t
   147           end
   148       | gen vs (t $ u) = gen vs t ##>> gen vs u #>> (op $)
   149       | gen vs (Abs (n, T, t)) =
   150           gen (no_name :: vs) t #>> (fn u => Abs (n, T, u))
   151       | gen _ t = pair t
   152 
   153   in (fn ct => gen (map (dest o Thm.term_of) cvs) (Thm.term_of ct) []) end
   154 
   155 fun fresh_abstraction cvs ct (cx as (ctxt, tab, idx, beta_norm)) =
   156   let val (t, cvs') = generalize cvs ct
   157   in
   158     (case Termtab.lookup tab t of
   159       SOME (cv, _) => (cv, cx)
   160     | NONE =>
   161         let
   162           val (n, ctxt') = yield_singleton Variable.variant_fixes "x" ctxt
   163           val cv = certify ctxt (Free (n, map typ_of cvs' ---> typ_of ct))
   164           val cv' = Drule.list_comb (cv, cvs')
   165           val e = (t, (cv, fold_rev Thm.cabs cvs' ct))
   166           val beta_norm' = beta_norm orelse not (null cvs')
   167         in (cv', (ctxt', Termtab.update e tab, idx + 1, beta_norm')) end)
   168   end
   169 
   170 fun abs_arg f cvs ct =
   171   let val (cf, cu) = Thm.dest_comb ct
   172   in f cvs cu #>> Thm.capply cf end
   173 
   174 fun abs_comb f g cvs ct =
   175   let val (cf, cu) = Thm.dest_comb ct
   176   in f cvs cf ##>> g cvs cu #>> uncurry Thm.capply end
   177 
   178 fun abs_list f g cvs ct =
   179   (case Thm.term_of ct of
   180     Const (@{const_name Nil}, _) => pair ct
   181   | Const (@{const_name Cons}, _) $ _ $ _ =>
   182       abs_comb (abs_arg f) (abs_list f g) cvs ct
   183   | _ => g cvs ct)
   184 
   185 fun abs_abs f cvs ct =
   186   let val (cv, cu) = Thm.dest_abs NONE ct
   187   in f (cv :: cvs) cu #>> Thm.cabs cv end
   188 
   189 val is_atomic = (fn _ $ _ => false | Abs _ => false | _ => true)
   190 val is_arithT = (fn @{typ int} => true | @{typ real} => true | _ => false)
   191 fun is_number t =
   192   (case try HOLogic.dest_number t of
   193     SOME (T, _) => is_arithT T
   194   | NONE => false)
   195 
   196 val abstract =
   197   let (* FIXME: provide an option to avoid abstraction of If/distinct/All/Ex *)
   198     fun abstr1 cvs ct = abs_arg abstr cvs ct
   199     and abstr2 cvs ct = abs_comb abstr1 abstr cvs ct
   200     and abstr3 cvs ct = abs_comb abstr2 abstr cvs ct
   201     and abstr_abs cvs ct = abs_arg (abs_abs abstr) cvs ct
   202 
   203     and abstr cvs ct =
   204       (case Thm.term_of ct of
   205         @{term Trueprop} $ _ => abstr1 cvs ct
   206       | @{term "op ==>"} $ _ $ _ => abstr2 cvs ct
   207       | @{term True} => pair ct
   208       | @{term False} => pair ct
   209       | @{term Not} $ _ => abstr1 cvs ct
   210       | @{term "op &"} $ _ $ _ => abstr2 cvs ct
   211       | @{term "op |"} $ _ $ _ => abstr2 cvs ct
   212       | @{term "op -->"} $ _ $ _ => abstr2 cvs ct
   213       | Const (@{const_name "op ="}, _) $ _ $ _ => abstr2 cvs ct
   214       | Const (@{const_name distinct}, _) $ _ =>
   215           abs_arg (abs_list abstr fresh_abstraction) cvs ct
   216       | Const (@{const_name If}, _) $ _ $ _ $ _ => abstr3 cvs ct
   217       | Const (@{const_name All}, _) $ _ => abstr_abs cvs ct
   218       | Const (@{const_name Ex}, _) $ _ => abstr_abs cvs ct
   219       | @{term "uminus :: int => _"} $ _ => abstr1 cvs ct
   220       | @{term "uminus :: real => _"} $ _ => abstr1 cvs ct
   221       | @{term "op + :: int => _"} $ _ $ _ => abstr2 cvs ct
   222       | @{term "op + :: real => _"} $ _ $ _ => abstr2 cvs ct
   223       | @{term "op - :: int => _"} $ _ $ _ => abstr2 cvs ct
   224       | @{term "op - :: real => _"} $ _ $ _ => abstr2 cvs ct
   225       | @{term "op * :: int => _"} $ _ $ _ => abstr2 cvs ct
   226       | @{term "op * :: real => _"} $ _ $ _ => abstr2 cvs ct
   227       | @{term "op div :: int => _"} $ _ $ _ => abstr2 cvs ct
   228       | @{term "op mod :: int => _"} $ _ $ _ => abstr2 cvs ct
   229       | @{term "op / :: real => _"} $ _ $ _ => abstr2 cvs ct
   230       | @{term "op < :: int => _"} $ _ $ _ => abstr2 cvs ct
   231       | @{term "op < :: real => _"} $ _ $ _ => abstr2 cvs ct
   232       | @{term "op <= :: int => _"} $ _ $ _ => abstr2 cvs ct
   233       | @{term "op <= :: real => _"} $ _ $ _ => abstr2 cvs ct
   234       | Const (@{const_name apply}, _) $ _ $ _ => abstr2 cvs ct
   235       | Const (@{const_name fun_upd}, _) $ _ $ _ $ _ => abstr3 cvs ct
   236       | t =>
   237           if is_atomic t orelse is_number t then pair ct
   238           else fresh_abstraction cvs ct)
   239   in abstr [] end
   240 
   241 fun with_prems thms f ct =
   242   fold_rev (Thm.mk_binop @{cterm "op ==>"} o Thm.cprop_of) thms ct
   243   |> f
   244   |> fold (fn prem => fn th => Thm.implies_elim th prem) thms
   245 
   246 in
   247 
   248 fun by_abstraction ctxt thms prove = with_prems thms (fn ct =>
   249   let val (cu, cx) = abstract ct (abs_context ctxt)
   250   in abs_instantiate cx (prove (context_of cx) cu) end)
   251 
   252 end
   253 
   254 
   255 
   256 (* a faster COMP *)
   257 
   258 type compose_data = cterm list * (cterm -> cterm list) * thm
   259 
   260 fun list2 (x, y) = [x, y]
   261 
   262 fun precompose f rule = (f (Thm.cprem_of rule 1), f, rule)
   263 fun precompose2 f rule = precompose (list2 o f) rule
   264 
   265 fun compose (cvs, f, rule) thm =
   266   discharge thm (Thm.instantiate ([], cvs ~~ f (Thm.cprop_of thm)) rule)
   267 
   268 
   269 
   270 (* unfolding of 'distinct' *)
   271 
   272 local
   273   val set1 = @{lemma "x ~: set [] == ~False" by simp}
   274   val set2 = @{lemma "x ~: set [x] == False" by simp}
   275   val set3 = @{lemma "x ~: set [y] == x ~= y" by simp}
   276   val set4 = @{lemma "x ~: set (x # ys) == False" by simp}
   277   val set5 = @{lemma "x ~: set (y # ys) == x ~= y & x ~: set ys" by simp}
   278 
   279   fun set_conv ct =
   280     (More_Conv.rewrs_conv [set1, set2, set3, set4] else_conv
   281     (Conv.rewr_conv set5 then_conv Conv.arg_conv set_conv)) ct
   282 
   283   val dist1 = @{lemma "distinct [] == ~False" by simp}
   284   val dist2 = @{lemma "distinct [x] == ~False" by simp}
   285   val dist3 = @{lemma "distinct (x # xs) == x ~: set xs & distinct xs"
   286     by simp}
   287 
   288   fun binop_conv cv1 cv2 = Conv.combination_conv (Conv.arg_conv cv1) cv2
   289 in
   290 fun unfold_distinct_conv ct =
   291   (More_Conv.rewrs_conv [dist1, dist2] else_conv
   292   (Conv.rewr_conv dist3 then_conv binop_conv set_conv unfold_distinct_conv)) ct
   293 end
   294 
   295 
   296 
   297 (* simpset *)
   298 
   299 local
   300   val antisym_le1 = mk_meta_eq @{thm order_class.antisym_conv}
   301   val antisym_le2 = mk_meta_eq @{thm linorder_class.antisym_conv2}
   302   val antisym_less1 = mk_meta_eq @{thm linorder_class.antisym_conv1}
   303   val antisym_less2 = mk_meta_eq @{thm linorder_class.antisym_conv3}
   304 
   305   fun eq_prop t thm = HOLogic.mk_Trueprop t aconv Thm.prop_of thm
   306   fun dest_binop ((c as Const _) $ t $ u) = (c, t, u)
   307     | dest_binop t = raise TERM ("dest_binop", [t])
   308 
   309   fun prove_antisym_le ss t =
   310     let
   311       val (le, r, s) = dest_binop t
   312       val less = Const (@{const_name less}, Term.fastype_of le)
   313       val prems = Simplifier.prems_of_ss ss
   314     in
   315       (case find_first (eq_prop (le $ s $ r)) prems of
   316         NONE =>
   317           find_first (eq_prop (HOLogic.mk_not (less $ r $ s))) prems
   318           |> Option.map (fn thm => thm RS antisym_less1)
   319       | SOME thm => SOME (thm RS antisym_le1))
   320     end
   321     handle THM _ => NONE
   322 
   323   fun prove_antisym_less ss t =
   324     let
   325       val (less, r, s) = dest_binop (HOLogic.dest_not t)
   326       val le = Const (@{const_name less_eq}, Term.fastype_of less)
   327       val prems = prems_of_ss ss
   328     in
   329       (case find_first (eq_prop (le $ r $ s)) prems of
   330         NONE =>
   331           find_first (eq_prop (HOLogic.mk_not (less $ s $ r))) prems
   332           |> Option.map (fn thm => thm RS antisym_less2)
   333       | SOME thm => SOME (thm RS antisym_le2))
   334   end
   335   handle THM _ => NONE
   336 in
   337 
   338 fun make_simpset ctxt rules = Simplifier.context ctxt (HOL_ss
   339   addsimps @{thms ring_distribs} addsimps @{thms field_simps}
   340   addsimps [@{thm times_divide_eq_right}, @{thm times_divide_eq_left}]
   341   addsimps @{thms arith_special} addsimps @{thms less_bin_simps}
   342   addsimps @{thms le_bin_simps} addsimps @{thms eq_bin_simps}
   343   addsimps @{thms add_bin_simps} addsimps @{thms succ_bin_simps}
   344   addsimps @{thms minus_bin_simps} addsimps @{thms pred_bin_simps}
   345   addsimps @{thms mult_bin_simps} addsimps @{thms iszero_simps}
   346   addsimps @{thms array_rules}
   347   addsimprocs [
   348     Simplifier.simproc @{theory} "fast_int_arith" [
   349       "(m::int) < n", "(m::int) <= n", "(m::int) = n"] (K Lin_Arith.simproc),
   350     Simplifier.simproc @{theory} "fast_real_arith" [
   351       "(m::real) < n", "(m::real) <= n", "(m::real) = n"]
   352       (K Lin_Arith.simproc),
   353     Simplifier.simproc @{theory} "antisym_le" ["(x::'a::order) <= y"]
   354       (K prove_antisym_le),
   355     Simplifier.simproc @{theory} "antisym_less" ["~ (x::'a::linorder) < y"]
   356       (K prove_antisym_less)]
   357   addsimps rules)
   358 
   359 end
   360 
   361 end