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
4 Helper functions required for Z3 proof reconstruction.
7 signature Z3_PROOF_TOOLS =
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
16 val thm_net_of: thm list -> thm Net.net
17 val net_instance: thm Net.net -> cterm -> thm option
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 ->
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
37 (* unfolding of 'distinct' *)
38 val unfold_distinct_conv: conv
41 val make_simpset: Proof.context -> thm list -> simpset
44 structure Z3_Proof_Tools: Z3_PROOF_TOOLS =
51 val dest_prop = (fn @{term Trueprop} $ t => t | t => t)
53 fun term_of ct = dest_prop (Thm.term_of ct)
54 fun prop_of thm = dest_prop (Thm.prop_of thm)
56 val mk_prop = Thm.capply @{cterm Trueprop}
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
63 fun as_meta_eq ct = uncurry mk_meta_eq_cterm (Thm.dest_binop (Thm.dest_arg ct))
70 let fun insert thm = Net.insert_term (K false) (Thm.prop_of thm, thm)
71 in fold insert thms Net.empty end
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)
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
82 (* proof combinators *)
84 fun under_assumption f ct =
85 let val ct' = mk_prop ct
86 in Thm.implies_intr ct' (f (Thm.assume ct')) end
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
92 fun discharge p pq = Thm.implies_elim pq p
94 fun varify vars = Drule.generalize ([], vars)
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
100 fun match_instantiate f ct thm =
101 Thm.instantiate (Thm.match (f (Thm.cprop_of thm), ct)) thm
103 fun by_tac tac ct = Goal.norm_result (Goal.prove_internal [] ct (K (tac 1)))
105 (* |- c x == t x ==> P (c x) ~~> c == t |- P (c x) *)
106 fun make_hyp_def thm =
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)
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
122 fun typ_of ct = #T (Thm.rep_cterm ct)
123 fun certify ctxt = Thm.cterm_of (ProofContext.theory_of ctxt)
125 fun abs_context ctxt = (ctxt, Termtab.empty, 1, false)
127 fun context_of (ctxt, _, _, _) = ctxt
129 fun replace (cv, ct) = Thm.forall_elim ct o Thm.forall_intr cv
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)
139 fun dest (Free (n, _)) = n
142 fun gen vs (t as Free (n, _)) =
143 let val i = find_index (equal n) vs
145 if i >= 0 then insert (op aconvc) (nth cvs i) #> pair (Bound i)
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))
153 in (fn ct => gen (map (dest o Thm.term_of) cvs) (Thm.term_of ct) []) end
155 fun fresh_abstraction cvs ct (cx as (ctxt, tab, idx, beta_norm)) =
156 let val (t, cvs') = generalize cvs ct
158 (case Termtab.lookup tab t of
159 SOME (cv, _) => (cv, cx)
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)
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
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
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
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
189 val is_atomic = (fn _ $ _ => false | Abs _ => false | _ => true)
190 val is_arithT = (fn @{typ int} => true | @{typ real} => true | _ => false)
192 (case try HOLogic.dest_number t of
193 SOME (T, _) => is_arithT T
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
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
237 if is_atomic t orelse is_number t then pair ct
238 else fresh_abstraction cvs ct)
241 fun with_prems thms f ct =
242 fold_rev (Thm.mk_binop @{cterm "op ==>"} o Thm.cprop_of) thms ct
244 |> fold (fn prem => fn th => Thm.implies_elim th prem) thms
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)
258 type compose_data = cterm list * (cterm -> cterm list) * thm
260 fun list2 (x, y) = [x, y]
262 fun precompose f rule = (f (Thm.cprem_of rule 1), f, rule)
263 fun precompose2 f rule = precompose (list2 o f) rule
265 fun compose (cvs, f, rule) thm =
266 discharge thm (Thm.instantiate ([], cvs ~~ f (Thm.cprop_of thm)) rule)
270 (* unfolding of 'distinct' *)
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}
280 (More_Conv.rewrs_conv [set1, set2, set3, set4] else_conv
281 (Conv.rewr_conv set5 then_conv Conv.arg_conv set_conv)) ct
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"
288 fun binop_conv cv1 cv2 = Conv.combination_conv (Conv.arg_conv cv1) cv2
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
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}
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])
309 fun prove_antisym_le ss t =
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
315 (case find_first (eq_prop (le $ s $ r)) prems of
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))
323 fun prove_antisym_less ss t =
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
329 (case find_first (eq_prop (le $ r $ s)) prems of
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))
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}
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)]