boehmes@36890
|
1 |
(* Title: HOL/Tools/SMT/z3_proof_reconstruction.ML
|
boehmes@36890
|
2 |
Author: Sascha Boehme, TU Muenchen
|
boehmes@36890
|
3 |
|
boehmes@36890
|
4 |
Proof reconstruction for proofs found by Z3.
|
boehmes@36890
|
5 |
*)
|
boehmes@36890
|
6 |
|
boehmes@36890
|
7 |
signature Z3_PROOF_RECONSTRUCTION =
|
boehmes@36890
|
8 |
sig
|
boehmes@36891
|
9 |
val add_z3_rule: thm -> Context.generic -> Context.generic
|
boehmes@40403
|
10 |
val reconstruct: Proof.context -> SMT_Translate.recon -> string list ->
|
boehmes@41375
|
11 |
int list * thm
|
boehmes@36890
|
12 |
val setup: theory -> theory
|
boehmes@36890
|
13 |
end
|
boehmes@36890
|
14 |
|
boehmes@36890
|
15 |
structure Z3_Proof_Reconstruction: Z3_PROOF_RECONSTRUCTION =
|
boehmes@36890
|
16 |
struct
|
boehmes@36890
|
17 |
|
boehmes@36890
|
18 |
|
boehmes@40651
|
19 |
fun z3_exn msg = raise SMT_Failure.SMT (SMT_Failure.Other_Failure
|
boehmes@40403
|
20 |
("Z3 proof reconstruction: " ^ msg))
|
boehmes@36890
|
21 |
|
boehmes@36890
|
22 |
|
boehmes@36890
|
23 |
|
boehmes@41378
|
24 |
(* net of schematic rules *)
|
boehmes@36890
|
25 |
|
boehmes@36890
|
26 |
val z3_ruleN = "z3_rule"
|
boehmes@36890
|
27 |
|
boehmes@36890
|
28 |
local
|
boehmes@36890
|
29 |
val description = "declaration of Z3 proof rules"
|
boehmes@36890
|
30 |
|
boehmes@36890
|
31 |
val eq = Thm.eq_thm
|
boehmes@36890
|
32 |
|
boehmes@36890
|
33 |
structure Z3_Rules = Generic_Data
|
boehmes@36890
|
34 |
(
|
boehmes@36890
|
35 |
type T = thm Net.net
|
boehmes@36890
|
36 |
val empty = Net.empty
|
boehmes@36890
|
37 |
val extend = I
|
boehmes@36890
|
38 |
val merge = Net.merge eq
|
boehmes@36890
|
39 |
)
|
boehmes@36890
|
40 |
|
boehmes@41576
|
41 |
val prep =
|
boehmes@41576
|
42 |
`Thm.prop_of o Simplifier.rewrite_rule [Z3_Proof_Literals.rewrite_true]
|
boehmes@36890
|
43 |
|
boehmes@36890
|
44 |
fun ins thm net = Net.insert_term eq (prep thm) net handle Net.INSERT => net
|
boehmes@36890
|
45 |
fun del thm net = Net.delete_term eq (prep thm) net handle Net.DELETE => net
|
boehmes@36890
|
46 |
|
boehmes@36890
|
47 |
val add = Thm.declaration_attribute (Z3_Rules.map o ins)
|
boehmes@36890
|
48 |
val del = Thm.declaration_attribute (Z3_Rules.map o del)
|
boehmes@36890
|
49 |
in
|
boehmes@36890
|
50 |
|
boehmes@36891
|
51 |
val add_z3_rule = Z3_Rules.map o ins
|
boehmes@36890
|
52 |
|
boehmes@36890
|
53 |
fun by_schematic_rule ctxt ct =
|
boehmes@41576
|
54 |
the (Z3_Proof_Tools.net_instance (Z3_Rules.get (Context.Proof ctxt)) ct)
|
boehmes@36890
|
55 |
|
boehmes@36890
|
56 |
val z3_rules_setup =
|
boehmes@36890
|
57 |
Attrib.setup (Binding.name z3_ruleN) (Attrib.add_del add del) description #>
|
wenzelm@39814
|
58 |
Global_Theory.add_thms_dynamic (Binding.name z3_ruleN, Net.content o Z3_Rules.get)
|
boehmes@36890
|
59 |
|
boehmes@36890
|
60 |
end
|
boehmes@36890
|
61 |
|
boehmes@36890
|
62 |
|
boehmes@36890
|
63 |
|
boehmes@41378
|
64 |
(* proof tools *)
|
boehmes@36890
|
65 |
|
boehmes@36890
|
66 |
fun named ctxt name prover ct =
|
boehmes@40651
|
67 |
let val _ = SMT_Config.trace_msg ctxt I ("Z3: trying " ^ name ^ " ...")
|
boehmes@36890
|
68 |
in prover ct end
|
boehmes@36890
|
69 |
|
boehmes@36890
|
70 |
fun NAMED ctxt name tac i st =
|
boehmes@40651
|
71 |
let val _ = SMT_Config.trace_msg ctxt I ("Z3: trying " ^ name ^ " ...")
|
boehmes@36890
|
72 |
in tac i st end
|
boehmes@36890
|
73 |
|
boehmes@36890
|
74 |
fun pretty_goal ctxt thms t =
|
boehmes@36890
|
75 |
[Pretty.block [Pretty.str "proposition: ", Syntax.pretty_term ctxt t]]
|
boehmes@36890
|
76 |
|> not (null thms) ? cons (Pretty.big_list "assumptions:"
|
boehmes@36890
|
77 |
(map (Display.pretty_thm ctxt) thms))
|
boehmes@36890
|
78 |
|
boehmes@36890
|
79 |
fun try_apply ctxt thms =
|
boehmes@36890
|
80 |
let
|
boehmes@36890
|
81 |
fun try_apply_err ct = Pretty.string_of (Pretty.chunks [
|
boehmes@36890
|
82 |
Pretty.big_list ("Z3 found a proof," ^
|
boehmes@36890
|
83 |
" but proof reconstruction failed at the following subgoal:")
|
boehmes@36890
|
84 |
(pretty_goal ctxt thms (Thm.term_of ct)),
|
boehmes@36890
|
85 |
Pretty.str ("Adding a rule to the lemma group " ^ quote z3_ruleN ^
|
boehmes@36890
|
86 |
" might solve this problem.")])
|
boehmes@36890
|
87 |
|
boehmes@36890
|
88 |
fun apply [] ct = error (try_apply_err ct)
|
boehmes@36890
|
89 |
| apply (prover :: provers) ct =
|
boehmes@36890
|
90 |
(case try prover ct of
|
boehmes@40651
|
91 |
SOME thm => (SMT_Config.trace_msg ctxt I "Z3: succeeded"; thm)
|
boehmes@36890
|
92 |
| NONE => apply provers ct)
|
boehmes@36890
|
93 |
|
boehmes@44764
|
94 |
fun schematic_label full = "schematic rules" |> full ? suffix " (full)"
|
boehmes@44764
|
95 |
fun schematic ctxt full ct =
|
boehmes@44764
|
96 |
ct
|
boehmes@44764
|
97 |
|> full ? fold_rev (curry Drule.mk_implies o Thm.cprop_of) thms
|
boehmes@44764
|
98 |
|> named ctxt (schematic_label full) (by_schematic_rule ctxt)
|
boehmes@44764
|
99 |
|> fold Thm.elim_implies thms
|
boehmes@44764
|
100 |
|
boehmes@44764
|
101 |
in apply o cons (schematic ctxt false) o cons (schematic ctxt true) end
|
boehmes@36890
|
102 |
|
boehmes@36891
|
103 |
local
|
boehmes@36891
|
104 |
val rewr_if =
|
boehmes@36891
|
105 |
@{lemma "(if P then Q1 else Q2) = ((P --> Q1) & (~P --> Q2))" by simp}
|
boehmes@36891
|
106 |
in
|
wenzelm@43665
|
107 |
|
wenzelm@43665
|
108 |
fun HOL_fast_tac ctxt =
|
wenzelm@43665
|
109 |
Classical.fast_tac (put_claset HOL_cs ctxt)
|
wenzelm@43665
|
110 |
|
wenzelm@43665
|
111 |
fun simp_fast_tac ctxt =
|
boehmes@36891
|
112 |
Simplifier.simp_tac (HOL_ss addsimps [rewr_if])
|
wenzelm@43665
|
113 |
THEN_ALL_NEW HOL_fast_tac ctxt
|
wenzelm@43665
|
114 |
|
boehmes@36891
|
115 |
end
|
boehmes@36891
|
116 |
|
boehmes@36890
|
117 |
|
boehmes@36890
|
118 |
|
boehmes@41378
|
119 |
(* theorems and proofs *)
|
boehmes@36890
|
120 |
|
boehmes@41378
|
121 |
(** theorem incarnations **)
|
boehmes@36890
|
122 |
|
boehmes@36890
|
123 |
datatype theorem =
|
boehmes@36890
|
124 |
Thm of thm | (* theorem without special features *)
|
boehmes@36890
|
125 |
MetaEq of thm | (* meta equality "t == s" *)
|
boehmes@41576
|
126 |
Literals of thm * Z3_Proof_Literals.littab
|
boehmes@36890
|
127 |
(* "P1 & ... & Pn" and table of all literals P1, ..., Pn *)
|
boehmes@36890
|
128 |
|
boehmes@36890
|
129 |
fun thm_of (Thm thm) = thm
|
boehmes@36890
|
130 |
| thm_of (MetaEq thm) = thm COMP @{thm meta_eq_to_obj_eq}
|
boehmes@36890
|
131 |
| thm_of (Literals (thm, _)) = thm
|
boehmes@36890
|
132 |
|
boehmes@36890
|
133 |
fun meta_eq_of (MetaEq thm) = thm
|
boehmes@36890
|
134 |
| meta_eq_of p = mk_meta_eq (thm_of p)
|
boehmes@36890
|
135 |
|
boehmes@36890
|
136 |
fun literals_of (Literals (_, lits)) = lits
|
boehmes@41576
|
137 |
| literals_of p = Z3_Proof_Literals.make_littab [thm_of p]
|
boehmes@36890
|
138 |
|
boehmes@36890
|
139 |
|
boehmes@36890
|
140 |
|
boehmes@36890
|
141 |
(** core proof rules **)
|
boehmes@36890
|
142 |
|
boehmes@36890
|
143 |
(* assumption *)
|
boehmes@41379
|
144 |
|
boehmes@36890
|
145 |
local
|
boehmes@41379
|
146 |
val remove_trigger = mk_meta_eq @{thm SMT.trigger_def}
|
boehmes@41379
|
147 |
val remove_weight = mk_meta_eq @{thm SMT.weight_def}
|
boehmes@41379
|
148 |
val remove_fun_app = mk_meta_eq @{thm SMT.fun_app_def}
|
boehmes@36890
|
149 |
|
boehmes@36890
|
150 |
fun rewrite_conv ctxt eqs = Simplifier.full_rewrite
|
boehmes@36890
|
151 |
(Simplifier.context ctxt Simplifier.empty_ss addsimps eqs)
|
boehmes@36890
|
152 |
|
boehmes@41379
|
153 |
val prep_rules = [@{thm Let_def}, remove_trigger, remove_weight,
|
boehmes@41576
|
154 |
remove_fun_app, Z3_Proof_Literals.rewrite_true]
|
boehmes@41379
|
155 |
|
boehmes@41379
|
156 |
fun rewrite ctxt eqs = Conv.fconv_rule (rewrite_conv ctxt eqs)
|
boehmes@36890
|
157 |
|
boehmes@40405
|
158 |
fun burrow_snd_option f (i, thm) = Option.map (pair i) (f thm)
|
boehmes@41379
|
159 |
|
boehmes@41379
|
160 |
fun lookup_assm assms_net ct =
|
boehmes@41576
|
161 |
Z3_Proof_Tools.net_instance' burrow_snd_option assms_net ct
|
boehmes@41379
|
162 |
|> Option.map (fn ithm as (_, thm) => (ithm, Thm.cprop_of thm aconvc ct))
|
boehmes@36890
|
163 |
in
|
boehmes@41379
|
164 |
|
boehmes@41379
|
165 |
fun add_asserted outer_ctxt rewrite_rules assms asserted ctxt =
|
boehmes@36890
|
166 |
let
|
boehmes@41576
|
167 |
val eqs = map (rewrite ctxt [Z3_Proof_Literals.rewrite_true]) rewrite_rules
|
boehmes@41379
|
168 |
val eqs' = union Thm.eq_thm eqs prep_rules
|
boehmes@41379
|
169 |
|
boehmes@41379
|
170 |
val assms_net =
|
boehmes@41375
|
171 |
assms
|
boehmes@41379
|
172 |
|> map (apsnd (rewrite ctxt eqs'))
|
boehmes@41375
|
173 |
|> map (apsnd (Conv.fconv_rule Thm.eta_conversion))
|
boehmes@41576
|
174 |
|> Z3_Proof_Tools.thm_net_of snd
|
boehmes@36890
|
175 |
|
boehmes@41379
|
176 |
fun revert_conv ctxt = rewrite_conv ctxt eqs' then_conv Thm.eta_conversion
|
boehmes@40405
|
177 |
|
boehmes@41379
|
178 |
fun assume thm ctxt =
|
boehmes@41379
|
179 |
let
|
boehmes@41379
|
180 |
val ct = Thm.cprem_of thm 1
|
boehmes@41379
|
181 |
val (thm', ctxt') = yield_singleton Assumption.add_assumes ct ctxt
|
boehmes@41379
|
182 |
in (Thm.implies_elim thm thm', ctxt') end
|
boehmes@41379
|
183 |
|
boehmes@41379
|
184 |
fun add (idx, ct) ((is, thms), (ctxt, ptab)) =
|
boehmes@41379
|
185 |
let
|
boehmes@41379
|
186 |
val thm1 =
|
boehmes@41379
|
187 |
Thm.trivial ct
|
boehmes@41379
|
188 |
|> Conv.fconv_rule (Conv.arg1_conv (revert_conv outer_ctxt))
|
boehmes@41379
|
189 |
val thm2 = singleton (Variable.export ctxt outer_ctxt) thm1
|
boehmes@41379
|
190 |
in
|
boehmes@41379
|
191 |
(case lookup_assm assms_net (Thm.cprem_of thm2 1) of
|
boehmes@41379
|
192 |
NONE =>
|
boehmes@41379
|
193 |
let val (thm, ctxt') = assume thm1 ctxt
|
boehmes@41379
|
194 |
in ((is, thms), (ctxt', Inttab.update (idx, Thm thm) ptab)) end
|
boehmes@41379
|
195 |
| SOME ((i, th), exact) =>
|
boehmes@41379
|
196 |
let
|
boehmes@41379
|
197 |
val (thm, ctxt') =
|
boehmes@41379
|
198 |
if exact then (Thm.implies_elim thm1 th, ctxt)
|
boehmes@41379
|
199 |
else assume thm1 ctxt
|
boehmes@41379
|
200 |
val thms' = if exact then thms else th :: thms
|
boehmes@41379
|
201 |
in
|
boehmes@41379
|
202 |
((insert (op =) i is, thms'),
|
boehmes@41379
|
203 |
(ctxt', Inttab.update (idx, Thm thm) ptab))
|
boehmes@41379
|
204 |
end)
|
boehmes@41379
|
205 |
end
|
boehmes@41379
|
206 |
in fold add asserted (([], []), (ctxt, Inttab.empty)) end
|
boehmes@41379
|
207 |
|
boehmes@36890
|
208 |
end
|
boehmes@36890
|
209 |
|
boehmes@36890
|
210 |
|
boehmes@36890
|
211 |
(* P = Q ==> P ==> Q or P --> Q ==> P ==> Q *)
|
boehmes@36890
|
212 |
local
|
boehmes@41576
|
213 |
val precomp = Z3_Proof_Tools.precompose2
|
boehmes@41576
|
214 |
val comp = Z3_Proof_Tools.compose
|
boehmes@41576
|
215 |
|
boehmes@36890
|
216 |
val meta_iffD1 = @{lemma "P == Q ==> P ==> (Q::bool)" by simp}
|
boehmes@41576
|
217 |
val meta_iffD1_c = precomp Thm.dest_binop meta_iffD1
|
boehmes@36890
|
218 |
|
boehmes@41576
|
219 |
val iffD1_c = precomp (Thm.dest_binop o Thm.dest_arg) @{thm iffD1}
|
boehmes@41576
|
220 |
val mp_c = precomp (Thm.dest_binop o Thm.dest_arg) @{thm mp}
|
boehmes@36890
|
221 |
in
|
boehmes@41576
|
222 |
fun mp (MetaEq thm) p = Thm (Thm.implies_elim (comp meta_iffD1_c thm) p)
|
boehmes@36890
|
223 |
| mp p_q p =
|
boehmes@36890
|
224 |
let
|
boehmes@36890
|
225 |
val pq = thm_of p_q
|
boehmes@41576
|
226 |
val thm = comp iffD1_c pq handle THM _ => comp mp_c pq
|
boehmes@36890
|
227 |
in Thm (Thm.implies_elim thm p) end
|
boehmes@36890
|
228 |
end
|
boehmes@36890
|
229 |
|
boehmes@36890
|
230 |
|
boehmes@36890
|
231 |
(* and_elim: P1 & ... & Pn ==> Pi *)
|
boehmes@36890
|
232 |
(* not_or_elim: ~(P1 | ... | Pn) ==> ~Pi *)
|
boehmes@36890
|
233 |
local
|
boehmes@41576
|
234 |
fun is_sublit conj t = Z3_Proof_Literals.exists_lit conj (fn u => u aconv t)
|
boehmes@36890
|
235 |
|
boehmes@36890
|
236 |
fun derive conj t lits idx ptab =
|
boehmes@36890
|
237 |
let
|
boehmes@41576
|
238 |
val lit = the (Z3_Proof_Literals.get_first_lit (is_sublit conj t) lits)
|
boehmes@41576
|
239 |
val ls = Z3_Proof_Literals.explode conj false false [t] lit
|
boehmes@41576
|
240 |
val lits' = fold Z3_Proof_Literals.insert_lit ls
|
boehmes@41576
|
241 |
(Z3_Proof_Literals.delete_lit lit lits)
|
boehmes@36890
|
242 |
|
boehmes@41378
|
243 |
fun upd thm = Literals (thm_of thm, lits')
|
boehmes@41576
|
244 |
val ptab' = Inttab.map_entry idx upd ptab
|
boehmes@41576
|
245 |
in (the (Z3_Proof_Literals.lookup_lit lits' t), ptab') end
|
boehmes@36890
|
246 |
|
boehmes@36890
|
247 |
fun lit_elim conj (p, idx) ct ptab =
|
boehmes@36890
|
248 |
let val lits = literals_of p
|
boehmes@36890
|
249 |
in
|
boehmes@41576
|
250 |
(case Z3_Proof_Literals.lookup_lit lits (SMT_Utils.term_of ct) of
|
boehmes@36890
|
251 |
SOME lit => (Thm lit, ptab)
|
boehmes@41576
|
252 |
| NONE => apfst Thm (derive conj (SMT_Utils.term_of ct) lits idx ptab))
|
boehmes@36890
|
253 |
end
|
boehmes@36890
|
254 |
in
|
boehmes@36890
|
255 |
val and_elim = lit_elim true
|
boehmes@36890
|
256 |
val not_or_elim = lit_elim false
|
boehmes@36890
|
257 |
end
|
boehmes@36890
|
258 |
|
boehmes@36890
|
259 |
|
boehmes@36890
|
260 |
(* P1, ..., Pn |- False ==> |- ~P1 | ... | ~Pn *)
|
boehmes@36890
|
261 |
local
|
boehmes@36890
|
262 |
fun step lit thm =
|
boehmes@36890
|
263 |
Thm.implies_elim (Thm.implies_intr (Thm.cprop_of lit) thm) lit
|
boehmes@41576
|
264 |
val explode_disj = Z3_Proof_Literals.explode false false false
|
boehmes@36890
|
265 |
fun intro hyps thm th = fold step (explode_disj hyps th) thm
|
boehmes@36890
|
266 |
|
boehmes@36890
|
267 |
fun dest_ccontr ct = [Thm.dest_arg (Thm.dest_arg (Thm.dest_arg1 ct))]
|
boehmes@41576
|
268 |
val ccontr = Z3_Proof_Tools.precompose dest_ccontr @{thm ccontr}
|
boehmes@36890
|
269 |
in
|
boehmes@36890
|
270 |
fun lemma thm ct =
|
boehmes@36890
|
271 |
let
|
boehmes@41576
|
272 |
val cu = Z3_Proof_Literals.negate (Thm.dest_arg ct)
|
boehmes@36890
|
273 |
val hyps = map_filter (try HOLogic.dest_Trueprop) (#hyps (Thm.rep_thm thm))
|
boehmes@41576
|
274 |
val th = Z3_Proof_Tools.under_assumption (intro hyps thm) cu
|
boehmes@41576
|
275 |
in Thm (Z3_Proof_Tools.compose ccontr th) end
|
boehmes@36890
|
276 |
end
|
boehmes@36890
|
277 |
|
boehmes@36890
|
278 |
|
boehmes@36890
|
279 |
(* \/{P1, ..., Pn, Q1, ..., Qn}, ~P1, ..., ~Pn ==> \/{Q1, ..., Qn} *)
|
boehmes@36890
|
280 |
local
|
boehmes@41576
|
281 |
val explode_disj = Z3_Proof_Literals.explode false true false
|
boehmes@41576
|
282 |
val join_disj = Z3_Proof_Literals.join false
|
boehmes@36890
|
283 |
fun unit thm thms th =
|
boehmes@41576
|
284 |
let
|
boehmes@41576
|
285 |
val t = @{const Not} $ SMT_Utils.prop_of thm
|
boehmes@41576
|
286 |
val ts = map SMT_Utils.prop_of thms
|
boehmes@41576
|
287 |
in
|
boehmes@41576
|
288 |
join_disj (Z3_Proof_Literals.make_littab (thms @ explode_disj ts th)) t
|
boehmes@41576
|
289 |
end
|
boehmes@36890
|
290 |
|
boehmes@36890
|
291 |
fun dest_arg2 ct = Thm.dest_arg (Thm.dest_arg ct)
|
boehmes@36890
|
292 |
fun dest ct = pairself dest_arg2 (Thm.dest_binop ct)
|
boehmes@41576
|
293 |
val contrapos =
|
boehmes@41576
|
294 |
Z3_Proof_Tools.precompose2 dest @{lemma "(~P ==> ~Q) ==> Q ==> P" by fast}
|
boehmes@36890
|
295 |
in
|
boehmes@36890
|
296 |
fun unit_resolution thm thms ct =
|
boehmes@41576
|
297 |
Z3_Proof_Literals.negate (Thm.dest_arg ct)
|
boehmes@41576
|
298 |
|> Z3_Proof_Tools.under_assumption (unit thm thms)
|
boehmes@41576
|
299 |
|> Thm o Z3_Proof_Tools.discharge thm o Z3_Proof_Tools.compose contrapos
|
boehmes@36890
|
300 |
end
|
boehmes@36890
|
301 |
|
boehmes@36890
|
302 |
|
boehmes@36890
|
303 |
(* P ==> P == True or P ==> P == False *)
|
boehmes@36890
|
304 |
local
|
boehmes@36890
|
305 |
val iff1 = @{lemma "P ==> P == (~ False)" by simp}
|
boehmes@36890
|
306 |
val iff2 = @{lemma "~P ==> P == False" by simp}
|
boehmes@36890
|
307 |
in
|
boehmes@36890
|
308 |
fun iff_true thm = MetaEq (thm COMP iff1)
|
boehmes@36890
|
309 |
fun iff_false thm = MetaEq (thm COMP iff2)
|
boehmes@36890
|
310 |
end
|
boehmes@36890
|
311 |
|
boehmes@36890
|
312 |
|
boehmes@36890
|
313 |
(* distributivity of | over & *)
|
boehmes@36890
|
314 |
fun distributivity ctxt = Thm o try_apply ctxt [] [
|
wenzelm@43665
|
315 |
named ctxt "fast" (Z3_Proof_Tools.by_tac (HOL_fast_tac ctxt))]
|
boehmes@36890
|
316 |
(* FIXME: not very well tested *)
|
boehmes@36890
|
317 |
|
boehmes@36890
|
318 |
|
boehmes@36890
|
319 |
(* Tseitin-like axioms *)
|
boehmes@36890
|
320 |
local
|
boehmes@36890
|
321 |
val disjI1 = @{lemma "(P ==> Q) ==> ~P | Q" by fast}
|
boehmes@36890
|
322 |
val disjI2 = @{lemma "(~P ==> Q) ==> P | Q" by fast}
|
boehmes@36890
|
323 |
val disjI3 = @{lemma "(~Q ==> P) ==> P | Q" by fast}
|
boehmes@36890
|
324 |
val disjI4 = @{lemma "(Q ==> P) ==> P | ~Q" by fast}
|
boehmes@36890
|
325 |
|
boehmes@36890
|
326 |
fun prove' conj1 conj2 ct2 thm =
|
boehmes@41576
|
327 |
let
|
boehmes@41576
|
328 |
val littab =
|
boehmes@41576
|
329 |
Z3_Proof_Literals.explode conj1 true (conj1 <> conj2) [] thm
|
boehmes@41576
|
330 |
|> cons Z3_Proof_Literals.true_thm
|
boehmes@41576
|
331 |
|> Z3_Proof_Literals.make_littab
|
boehmes@41576
|
332 |
in Z3_Proof_Literals.join conj2 littab (Thm.term_of ct2) end
|
boehmes@36890
|
333 |
|
boehmes@36890
|
334 |
fun prove rule (ct1, conj1) (ct2, conj2) =
|
boehmes@41576
|
335 |
Z3_Proof_Tools.under_assumption (prove' conj1 conj2 ct2) ct1 COMP rule
|
boehmes@36890
|
336 |
|
boehmes@36890
|
337 |
fun prove_def_axiom ct =
|
boehmes@36890
|
338 |
let val (ct1, ct2) = Thm.dest_binop (Thm.dest_arg ct)
|
boehmes@36890
|
339 |
in
|
boehmes@36890
|
340 |
(case Thm.term_of ct1 of
|
boehmes@40817
|
341 |
@{const Not} $ (@{const HOL.conj} $ _ $ _) =>
|
boehmes@36890
|
342 |
prove disjI1 (Thm.dest_arg ct1, true) (ct2, true)
|
boehmes@40817
|
343 |
| @{const HOL.conj} $ _ $ _ =>
|
boehmes@41576
|
344 |
prove disjI3 (Z3_Proof_Literals.negate ct2, false) (ct1, true)
|
boehmes@40817
|
345 |
| @{const Not} $ (@{const HOL.disj} $ _ $ _) =>
|
boehmes@41576
|
346 |
prove disjI3 (Z3_Proof_Literals.negate ct2, false) (ct1, false)
|
boehmes@40817
|
347 |
| @{const HOL.disj} $ _ $ _ =>
|
boehmes@41576
|
348 |
prove disjI2 (Z3_Proof_Literals.negate ct1, false) (ct2, true)
|
boehmes@40929
|
349 |
| Const (@{const_name distinct}, _) $ _ =>
|
boehmes@36890
|
350 |
let
|
boehmes@36890
|
351 |
fun dis_conv cv = Conv.arg_conv (Conv.arg1_conv cv)
|
boehmes@41576
|
352 |
val unfold_dis_conv = dis_conv Z3_Proof_Tools.unfold_distinct_conv
|
boehmes@36890
|
353 |
fun prv cu =
|
boehmes@36890
|
354 |
let val (cu1, cu2) = Thm.dest_binop (Thm.dest_arg cu)
|
boehmes@36890
|
355 |
in prove disjI4 (Thm.dest_arg cu2, true) (cu1, true) end
|
boehmes@41576
|
356 |
in Z3_Proof_Tools.with_conv unfold_dis_conv prv ct end
|
boehmes@40929
|
357 |
| @{const Not} $ (Const (@{const_name distinct}, _) $ _) =>
|
boehmes@36890
|
358 |
let
|
boehmes@36890
|
359 |
fun dis_conv cv = Conv.arg_conv (Conv.arg1_conv (Conv.arg_conv cv))
|
boehmes@41576
|
360 |
val unfold_dis_conv = dis_conv Z3_Proof_Tools.unfold_distinct_conv
|
boehmes@36890
|
361 |
fun prv cu =
|
boehmes@36890
|
362 |
let val (cu1, cu2) = Thm.dest_binop (Thm.dest_arg cu)
|
boehmes@36890
|
363 |
in prove disjI1 (Thm.dest_arg cu1, true) (cu2, true) end
|
boehmes@41576
|
364 |
in Z3_Proof_Tools.with_conv unfold_dis_conv prv ct end
|
boehmes@36890
|
365 |
| _ => raise CTERM ("prove_def_axiom", [ct]))
|
boehmes@36890
|
366 |
end
|
boehmes@36890
|
367 |
in
|
boehmes@36890
|
368 |
fun def_axiom ctxt = Thm o try_apply ctxt [] [
|
boehmes@36890
|
369 |
named ctxt "conj/disj/distinct" prove_def_axiom,
|
boehmes@43833
|
370 |
Z3_Proof_Tools.by_abstraction 0 (true, false) ctxt [] (fn ctxt' =>
|
wenzelm@43665
|
371 |
named ctxt' "simp+fast" (Z3_Proof_Tools.by_tac (simp_fast_tac ctxt')))]
|
boehmes@36890
|
372 |
end
|
boehmes@36890
|
373 |
|
boehmes@36890
|
374 |
|
boehmes@36890
|
375 |
(* local definitions *)
|
boehmes@36890
|
376 |
local
|
boehmes@36890
|
377 |
val intro_rules = [
|
boehmes@36890
|
378 |
@{lemma "n == P ==> (~n | P) & (n | ~P)" by simp},
|
boehmes@36890
|
379 |
@{lemma "n == (if P then s else t) ==> (~P | n = s) & (P | n = t)"
|
boehmes@36890
|
380 |
by simp},
|
boehmes@36890
|
381 |
@{lemma "n == P ==> n = P" by (rule meta_eq_to_obj_eq)} ]
|
boehmes@36890
|
382 |
|
boehmes@36890
|
383 |
val apply_rules = [
|
boehmes@36890
|
384 |
@{lemma "(~n | P) & (n | ~P) ==> P == n" by (atomize(full)) fast},
|
boehmes@36890
|
385 |
@{lemma "(~P | n = s) & (P | n = t) ==> (if P then s else t) == n"
|
boehmes@36890
|
386 |
by (atomize(full)) fastsimp} ]
|
boehmes@36890
|
387 |
|
boehmes@41576
|
388 |
val inst_rule = Z3_Proof_Tools.match_instantiate Thm.dest_arg
|
boehmes@36890
|
389 |
|
boehmes@36890
|
390 |
fun apply_rule ct =
|
boehmes@36890
|
391 |
(case get_first (try (inst_rule ct)) intro_rules of
|
boehmes@36890
|
392 |
SOME thm => thm
|
boehmes@36890
|
393 |
| NONE => raise CTERM ("intro_def", [ct]))
|
boehmes@36890
|
394 |
in
|
boehmes@41576
|
395 |
fun intro_def ct = Z3_Proof_Tools.make_hyp_def (apply_rule ct) #>> Thm
|
boehmes@36890
|
396 |
|
boehmes@36890
|
397 |
fun apply_def thm =
|
boehmes@36890
|
398 |
get_first (try (fn rule => MetaEq (thm COMP rule))) apply_rules
|
boehmes@36890
|
399 |
|> the_default (Thm thm)
|
boehmes@36890
|
400 |
end
|
boehmes@36890
|
401 |
|
boehmes@36890
|
402 |
|
boehmes@36890
|
403 |
(* negation normal form *)
|
boehmes@36890
|
404 |
local
|
boehmes@36890
|
405 |
val quant_rules1 = ([
|
boehmes@36890
|
406 |
@{lemma "(!!x. P x == Q) ==> ALL x. P x == Q" by simp},
|
boehmes@36890
|
407 |
@{lemma "(!!x. P x == Q) ==> EX x. P x == Q" by simp}], [
|
boehmes@36890
|
408 |
@{lemma "(!!x. P x == Q x) ==> ALL x. P x == ALL x. Q x" by simp},
|
boehmes@36890
|
409 |
@{lemma "(!!x. P x == Q x) ==> EX x. P x == EX x. Q x" by simp}])
|
boehmes@36890
|
410 |
|
boehmes@36890
|
411 |
val quant_rules2 = ([
|
boehmes@36890
|
412 |
@{lemma "(!!x. ~P x == Q) ==> ~(ALL x. P x) == Q" by simp},
|
boehmes@36890
|
413 |
@{lemma "(!!x. ~P x == Q) ==> ~(EX x. P x) == Q" by simp}], [
|
boehmes@36890
|
414 |
@{lemma "(!!x. ~P x == Q x) ==> ~(ALL x. P x) == EX x. Q x" by simp},
|
boehmes@36890
|
415 |
@{lemma "(!!x. ~P x == Q x) ==> ~(EX x. P x) == ALL x. Q x" by simp}])
|
boehmes@36890
|
416 |
|
boehmes@36890
|
417 |
fun nnf_quant_tac thm (qs as (qs1, qs2)) i st = (
|
boehmes@36890
|
418 |
Tactic.rtac thm ORELSE'
|
boehmes@36890
|
419 |
(Tactic.match_tac qs1 THEN' nnf_quant_tac thm qs) ORELSE'
|
boehmes@36890
|
420 |
(Tactic.match_tac qs2 THEN' nnf_quant_tac thm qs)) i st
|
boehmes@36890
|
421 |
|
boehmes@41576
|
422 |
fun nnf_quant_tac_varified vars eq =
|
boehmes@41576
|
423 |
nnf_quant_tac (Z3_Proof_Tools.varify vars eq)
|
boehmes@41576
|
424 |
|
boehmes@36890
|
425 |
fun nnf_quant vars qs p ct =
|
boehmes@41576
|
426 |
Z3_Proof_Tools.as_meta_eq ct
|
boehmes@41576
|
427 |
|> Z3_Proof_Tools.by_tac (nnf_quant_tac_varified vars (meta_eq_of p) qs)
|
boehmes@36890
|
428 |
|
boehmes@36890
|
429 |
fun prove_nnf ctxt = try_apply ctxt [] [
|
boehmes@41576
|
430 |
named ctxt "conj/disj" Z3_Proof_Literals.prove_conj_disj_eq,
|
boehmes@43833
|
431 |
Z3_Proof_Tools.by_abstraction 0 (true, false) ctxt [] (fn ctxt' =>
|
wenzelm@43665
|
432 |
named ctxt' "simp+fast" (Z3_Proof_Tools.by_tac (simp_fast_tac ctxt')))]
|
boehmes@36890
|
433 |
in
|
boehmes@36890
|
434 |
fun nnf ctxt vars ps ct =
|
boehmes@41576
|
435 |
(case SMT_Utils.term_of ct of
|
boehmes@36890
|
436 |
_ $ (l as Const _ $ Abs _) $ (r as Const _ $ Abs _) =>
|
boehmes@36890
|
437 |
if l aconv r
|
boehmes@36890
|
438 |
then MetaEq (Thm.reflexive (Thm.dest_arg (Thm.dest_arg ct)))
|
boehmes@36890
|
439 |
else MetaEq (nnf_quant vars quant_rules1 (hd ps) ct)
|
boehmes@40817
|
440 |
| _ $ (@{const Not} $ (Const _ $ Abs _)) $ (Const _ $ Abs _) =>
|
boehmes@36890
|
441 |
MetaEq (nnf_quant vars quant_rules2 (hd ps) ct)
|
boehmes@36890
|
442 |
| _ =>
|
boehmes@36890
|
443 |
let
|
boehmes@36890
|
444 |
val nnf_rewr_conv = Conv.arg_conv (Conv.arg_conv
|
boehmes@41576
|
445 |
(Z3_Proof_Tools.unfold_eqs ctxt
|
boehmes@41576
|
446 |
(map (Thm.symmetric o meta_eq_of) ps)))
|
boehmes@41576
|
447 |
in Thm (Z3_Proof_Tools.with_conv nnf_rewr_conv (prove_nnf ctxt) ct) end)
|
boehmes@36890
|
448 |
end
|
boehmes@36890
|
449 |
|
boehmes@36890
|
450 |
|
boehmes@36890
|
451 |
|
boehmes@36890
|
452 |
(** equality proof rules **)
|
boehmes@36890
|
453 |
|
boehmes@36890
|
454 |
(* |- t = t *)
|
boehmes@36890
|
455 |
fun refl ct = MetaEq (Thm.reflexive (Thm.dest_arg (Thm.dest_arg ct)))
|
boehmes@36890
|
456 |
|
boehmes@36890
|
457 |
|
boehmes@36890
|
458 |
(* s = t ==> t = s *)
|
boehmes@36890
|
459 |
local
|
boehmes@36890
|
460 |
val symm_rule = @{lemma "s = t ==> t == s" by simp}
|
boehmes@36890
|
461 |
in
|
boehmes@36890
|
462 |
fun symm (MetaEq thm) = MetaEq (Thm.symmetric thm)
|
boehmes@36890
|
463 |
| symm p = MetaEq (thm_of p COMP symm_rule)
|
boehmes@36890
|
464 |
end
|
boehmes@36890
|
465 |
|
boehmes@36890
|
466 |
|
boehmes@36890
|
467 |
(* s = t ==> t = u ==> s = u *)
|
boehmes@36890
|
468 |
local
|
boehmes@36890
|
469 |
val trans1 = @{lemma "s == t ==> t = u ==> s == u" by simp}
|
boehmes@36890
|
470 |
val trans2 = @{lemma "s = t ==> t == u ==> s == u" by simp}
|
boehmes@36890
|
471 |
val trans3 = @{lemma "s = t ==> t = u ==> s == u" by simp}
|
boehmes@36890
|
472 |
in
|
boehmes@36890
|
473 |
fun trans (MetaEq thm1) (MetaEq thm2) = MetaEq (Thm.transitive thm1 thm2)
|
boehmes@36890
|
474 |
| trans (MetaEq thm) q = MetaEq (thm_of q COMP (thm COMP trans1))
|
boehmes@36890
|
475 |
| trans p (MetaEq thm) = MetaEq (thm COMP (thm_of p COMP trans2))
|
boehmes@36890
|
476 |
| trans p q = MetaEq (thm_of q COMP (thm_of p COMP trans3))
|
boehmes@36890
|
477 |
end
|
boehmes@36890
|
478 |
|
boehmes@36890
|
479 |
|
boehmes@36890
|
480 |
(* t1 = s1 ==> ... ==> tn = sn ==> f t1 ... tn = f s1 .. sn
|
boehmes@36890
|
481 |
(reflexive antecendents are droppped) *)
|
boehmes@36890
|
482 |
local
|
boehmes@36890
|
483 |
exception MONO
|
boehmes@36890
|
484 |
|
boehmes@36890
|
485 |
fun prove_refl (ct, _) = Thm.reflexive ct
|
boehmes@36890
|
486 |
fun prove_comb f g cp =
|
boehmes@36890
|
487 |
let val ((ct1, ct2), (cu1, cu2)) = pairself Thm.dest_comb cp
|
boehmes@36890
|
488 |
in Thm.combination (f (ct1, cu1)) (g (ct2, cu2)) end
|
boehmes@36890
|
489 |
fun prove_arg f = prove_comb prove_refl f
|
boehmes@36890
|
490 |
|
boehmes@36890
|
491 |
fun prove f cp = prove_comb (prove f) f cp handle CTERM _ => prove_refl cp
|
boehmes@36890
|
492 |
|
boehmes@36890
|
493 |
fun prove_nary is_comb f =
|
boehmes@36890
|
494 |
let
|
boehmes@36890
|
495 |
fun prove (cp as (ct, _)) = f cp handle MONO =>
|
boehmes@36890
|
496 |
if is_comb (Thm.term_of ct)
|
boehmes@36890
|
497 |
then prove_comb (prove_arg prove) prove cp
|
boehmes@36890
|
498 |
else prove_refl cp
|
boehmes@36890
|
499 |
in prove end
|
boehmes@36890
|
500 |
|
boehmes@36890
|
501 |
fun prove_list f n cp =
|
boehmes@36890
|
502 |
if n = 0 then prove_refl cp
|
boehmes@36890
|
503 |
else prove_comb (prove_arg f) (prove_list f (n-1)) cp
|
boehmes@36890
|
504 |
|
boehmes@36890
|
505 |
fun with_length f (cp as (cl, _)) =
|
boehmes@36890
|
506 |
f (length (HOLogic.dest_list (Thm.term_of cl))) cp
|
boehmes@36890
|
507 |
|
boehmes@36890
|
508 |
fun prove_distinct f = prove_arg (with_length (prove_list f))
|
boehmes@36890
|
509 |
|
boehmes@36890
|
510 |
fun prove_eq exn lookup cp =
|
boehmes@36890
|
511 |
(case lookup (Logic.mk_equals (pairself Thm.term_of cp)) of
|
boehmes@36890
|
512 |
SOME eq => eq
|
boehmes@36890
|
513 |
| NONE => if exn then raise MONO else prove_refl cp)
|
boehmes@36890
|
514 |
|
boehmes@41576
|
515 |
val prove_exn = prove_eq true
|
boehmes@41576
|
516 |
and prove_safe = prove_eq false
|
boehmes@36890
|
517 |
|
boehmes@36890
|
518 |
fun mono f (cp as (cl, _)) =
|
boehmes@36890
|
519 |
(case Term.head_of (Thm.term_of cl) of
|
boehmes@41576
|
520 |
@{const HOL.conj} => prove_nary Z3_Proof_Literals.is_conj (prove_exn f)
|
boehmes@41576
|
521 |
| @{const HOL.disj} => prove_nary Z3_Proof_Literals.is_disj (prove_exn f)
|
boehmes@41576
|
522 |
| Const (@{const_name distinct}, _) => prove_distinct (prove_safe f)
|
boehmes@41576
|
523 |
| _ => prove (prove_safe f)) cp
|
boehmes@36890
|
524 |
in
|
boehmes@36890
|
525 |
fun monotonicity eqs ct =
|
boehmes@36890
|
526 |
let
|
boehmes@40928
|
527 |
fun and_symmetric (t, thm) = [(t, thm), (t, Thm.symmetric thm)]
|
boehmes@40928
|
528 |
val teqs = maps (and_symmetric o `Thm.prop_of o meta_eq_of) eqs
|
boehmes@40928
|
529 |
val lookup = AList.lookup (op aconv) teqs
|
boehmes@36890
|
530 |
val cp = Thm.dest_binop (Thm.dest_arg ct)
|
boehmes@41576
|
531 |
in MetaEq (prove_exn lookup cp handle MONO => mono lookup cp) end
|
boehmes@36890
|
532 |
end
|
boehmes@36890
|
533 |
|
boehmes@36890
|
534 |
|
boehmes@36890
|
535 |
(* |- f a b = f b a (where f is equality) *)
|
boehmes@36890
|
536 |
local
|
boehmes@36890
|
537 |
val rule = @{lemma "a = b == b = a" by (atomize(full)) (rule eq_commute)}
|
boehmes@36890
|
538 |
in
|
boehmes@41576
|
539 |
fun commutativity ct =
|
boehmes@41576
|
540 |
MetaEq (Z3_Proof_Tools.match_instantiate I
|
boehmes@41576
|
541 |
(Z3_Proof_Tools.as_meta_eq ct) rule)
|
boehmes@36890
|
542 |
end
|
boehmes@36890
|
543 |
|
boehmes@36890
|
544 |
|
boehmes@36890
|
545 |
|
boehmes@36890
|
546 |
(** quantifier proof rules **)
|
boehmes@36890
|
547 |
|
boehmes@36890
|
548 |
(* P ?x = Q ?x ==> (ALL x. P x) = (ALL x. Q x)
|
boehmes@36890
|
549 |
P ?x = Q ?x ==> (EX x. P x) = (EX x. Q x) *)
|
boehmes@36890
|
550 |
local
|
boehmes@36890
|
551 |
val rules = [
|
boehmes@36890
|
552 |
@{lemma "(!!x. P x == Q x) ==> (ALL x. P x) == (ALL x. Q x)" by simp},
|
boehmes@36890
|
553 |
@{lemma "(!!x. P x == Q x) ==> (EX x. P x) == (EX x. Q x)" by simp}]
|
boehmes@36890
|
554 |
in
|
boehmes@36890
|
555 |
fun quant_intro vars p ct =
|
boehmes@36890
|
556 |
let
|
boehmes@36890
|
557 |
val thm = meta_eq_of p
|
boehmes@41576
|
558 |
val rules' = Z3_Proof_Tools.varify vars thm :: rules
|
boehmes@41576
|
559 |
val cu = Z3_Proof_Tools.as_meta_eq ct
|
boehmes@41576
|
560 |
val tac = REPEAT_ALL_NEW (Tactic.match_tac rules')
|
boehmes@41576
|
561 |
in MetaEq (Z3_Proof_Tools.by_tac tac cu) end
|
boehmes@36890
|
562 |
end
|
boehmes@36890
|
563 |
|
boehmes@36890
|
564 |
|
boehmes@36890
|
565 |
(* |- ((ALL x. P x) | Q) = (ALL x. P x | Q) *)
|
boehmes@36890
|
566 |
fun pull_quant ctxt = Thm o try_apply ctxt [] [
|
wenzelm@43665
|
567 |
named ctxt "fast" (Z3_Proof_Tools.by_tac (HOL_fast_tac ctxt))]
|
boehmes@36890
|
568 |
(* FIXME: not very well tested *)
|
boehmes@36890
|
569 |
|
boehmes@36890
|
570 |
|
boehmes@36890
|
571 |
(* |- (ALL x. P x & Q x) = ((ALL x. P x) & (ALL x. Q x)) *)
|
boehmes@36890
|
572 |
fun push_quant ctxt = Thm o try_apply ctxt [] [
|
wenzelm@43665
|
573 |
named ctxt "fast" (Z3_Proof_Tools.by_tac (HOL_fast_tac ctxt))]
|
boehmes@36890
|
574 |
(* FIXME: not very well tested *)
|
boehmes@36890
|
575 |
|
boehmes@36890
|
576 |
|
boehmes@36890
|
577 |
(* |- (ALL x1 ... xn y1 ... yn. P x1 ... xn) = (ALL x1 ... xn. P x1 ... xn) *)
|
boehmes@36890
|
578 |
local
|
boehmes@43178
|
579 |
val elim_all = @{lemma "P = Q ==> (ALL x. P) = Q" by fast}
|
boehmes@43178
|
580 |
val elim_ex = @{lemma "P = Q ==> (EX x. P) = Q" by fast}
|
boehmes@36890
|
581 |
|
boehmes@43178
|
582 |
fun elim_unused_tac i st = (
|
boehmes@43178
|
583 |
Tactic.match_tac [@{thm refl}]
|
boehmes@43178
|
584 |
ORELSE' (Tactic.match_tac [elim_all, elim_ex] THEN' elim_unused_tac)
|
boehmes@43178
|
585 |
ORELSE' (
|
boehmes@43178
|
586 |
Tactic.match_tac [@{thm iff_allI}, @{thm iff_exI}]
|
boehmes@43178
|
587 |
THEN' elim_unused_tac)) i st
|
boehmes@43178
|
588 |
in
|
boehmes@36890
|
589 |
|
boehmes@43178
|
590 |
val elim_unused_vars = Thm o Z3_Proof_Tools.by_tac elim_unused_tac
|
boehmes@43178
|
591 |
|
boehmes@36890
|
592 |
end
|
boehmes@36890
|
593 |
|
boehmes@36890
|
594 |
|
boehmes@36890
|
595 |
(* |- (ALL x1 ... xn. ~(x1 = t1 & ... xn = tn) | P x1 ... xn) = P t1 ... tn *)
|
boehmes@36890
|
596 |
fun dest_eq_res ctxt = Thm o try_apply ctxt [] [
|
wenzelm@43665
|
597 |
named ctxt "fast" (Z3_Proof_Tools.by_tac (HOL_fast_tac ctxt))]
|
boehmes@36890
|
598 |
(* FIXME: not very well tested *)
|
boehmes@36890
|
599 |
|
boehmes@36890
|
600 |
|
boehmes@36890
|
601 |
(* |- ~(ALL x1...xn. P x1...xn) | P a1...an *)
|
boehmes@36890
|
602 |
local
|
boehmes@36890
|
603 |
val rule = @{lemma "~ P x | Q ==> ~(ALL x. P x) | Q" by fast}
|
boehmes@36890
|
604 |
in
|
boehmes@41576
|
605 |
val quant_inst = Thm o Z3_Proof_Tools.by_tac (
|
boehmes@36890
|
606 |
REPEAT_ALL_NEW (Tactic.match_tac [rule])
|
boehmes@36890
|
607 |
THEN' Tactic.rtac @{thm excluded_middle})
|
boehmes@36890
|
608 |
end
|
boehmes@36890
|
609 |
|
boehmes@36890
|
610 |
|
boehmes@43067
|
611 |
(* |- (EX x. P x) = P c |- ~(ALL x. P x) = ~ P c *)
|
boehmes@36890
|
612 |
local
|
boehmes@43062
|
613 |
val forall =
|
boehmes@43062
|
614 |
SMT_Utils.mk_const_pat @{theory} @{const_name all}
|
boehmes@43062
|
615 |
(SMT_Utils.destT1 o SMT_Utils.destT1)
|
boehmes@43062
|
616 |
fun mk_forall cv ct =
|
boehmes@43062
|
617 |
Thm.capply (SMT_Utils.instT' cv forall) (Thm.cabs cv ct)
|
boehmes@36890
|
618 |
|
boehmes@43062
|
619 |
fun get_vars f mk pred ctxt t =
|
boehmes@43062
|
620 |
Term.fold_aterms f t []
|
boehmes@43062
|
621 |
|> map_filter (fn v =>
|
boehmes@43062
|
622 |
if pred v then SOME (SMT_Utils.certify ctxt (mk v)) else NONE)
|
boehmes@36890
|
623 |
|
boehmes@43062
|
624 |
fun close vars f ct ctxt =
|
boehmes@43062
|
625 |
let
|
boehmes@43062
|
626 |
val frees_of = get_vars Term.add_frees Free (member (op =) vars o fst)
|
boehmes@43062
|
627 |
val vs = frees_of ctxt (Thm.term_of ct)
|
boehmes@43062
|
628 |
val (thm, ctxt') = f (fold_rev mk_forall vs ct) ctxt
|
boehmes@43062
|
629 |
val vars_of = get_vars Term.add_vars Var (K true) ctxt'
|
boehmes@43062
|
630 |
in (Thm.instantiate ([], vars_of (Thm.prop_of thm) ~~ vs) thm, ctxt') end
|
boehmes@36890
|
631 |
|
boehmes@43062
|
632 |
val sk_rules = @{lemma
|
boehmes@43067
|
633 |
"(EX x. P x) = P (SOME x. P x)" "(~(ALL x. P x)) = (~P (SOME x. ~P x))"
|
boehmes@43062
|
634 |
by (metis someI_ex)+}
|
boehmes@43062
|
635 |
in
|
boehmes@36890
|
636 |
|
boehmes@43062
|
637 |
fun skolemize vars =
|
boehmes@43062
|
638 |
apfst Thm oo close vars (yield_singleton Assumption.add_assumes)
|
boehmes@36890
|
639 |
|
boehmes@43062
|
640 |
fun discharge_sk_tac i st = (
|
boehmes@43067
|
641 |
Tactic.rtac @{thm trans}
|
boehmes@43067
|
642 |
THEN' Tactic.resolve_tac sk_rules
|
boehmes@43067
|
643 |
THEN' (Tactic.rtac @{thm refl} ORELSE' discharge_sk_tac)) i st
|
boehmes@36890
|
644 |
|
boehmes@43062
|
645 |
end
|
boehmes@36890
|
646 |
|
boehmes@36890
|
647 |
|
boehmes@36890
|
648 |
|
boehmes@36890
|
649 |
(** theory proof rules **)
|
boehmes@36890
|
650 |
|
boehmes@36890
|
651 |
(* theory lemmas: linear arithmetic, arrays *)
|
boehmes@36890
|
652 |
fun th_lemma ctxt simpset thms = Thm o try_apply ctxt thms [
|
boehmes@43833
|
653 |
Z3_Proof_Tools.by_abstraction 0 (false, true) ctxt thms (fn ctxt' =>
|
boehmes@41576
|
654 |
Z3_Proof_Tools.by_tac (
|
boehmes@41576
|
655 |
NAMED ctxt' "arith" (Arith_Data.arith_tac ctxt')
|
boehmes@41576
|
656 |
ORELSE' NAMED ctxt' "simp+arith" (
|
boehmes@41576
|
657 |
Simplifier.simp_tac simpset
|
boehmes@41576
|
658 |
THEN_ALL_NEW Arith_Data.arith_tac ctxt')))]
|
boehmes@36890
|
659 |
|
boehmes@36890
|
660 |
|
boehmes@36890
|
661 |
(* rewriting: prove equalities:
|
boehmes@36890
|
662 |
* ACI of conjunction/disjunction
|
boehmes@36890
|
663 |
* contradiction, excluded middle
|
boehmes@36890
|
664 |
* logical rewriting rules (for negation, implication, equivalence,
|
boehmes@36890
|
665 |
distinct)
|
boehmes@36890
|
666 |
* normal forms for polynoms (integer/real arithmetic)
|
boehmes@36890
|
667 |
* quantifier elimination over linear arithmetic
|
boehmes@36890
|
668 |
* ... ? **)
|
boehmes@36890
|
669 |
structure Z3_Simps = Named_Thms
|
boehmes@36890
|
670 |
(
|
boehmes@36890
|
671 |
val name = "z3_simp"
|
boehmes@36890
|
672 |
val description = "simplification rules for Z3 proof reconstruction"
|
boehmes@36890
|
673 |
)
|
boehmes@36890
|
674 |
|
boehmes@36890
|
675 |
local
|
boehmes@36890
|
676 |
fun spec_meta_eq_of thm =
|
boehmes@36890
|
677 |
(case try (fn th => th RS @{thm spec}) thm of
|
boehmes@36890
|
678 |
SOME thm' => spec_meta_eq_of thm'
|
boehmes@36890
|
679 |
| NONE => mk_meta_eq thm)
|
boehmes@36890
|
680 |
|
boehmes@36890
|
681 |
fun prep (Thm thm) = spec_meta_eq_of thm
|
boehmes@36890
|
682 |
| prep (MetaEq thm) = thm
|
boehmes@36890
|
683 |
| prep (Literals (thm, _)) = spec_meta_eq_of thm
|
boehmes@36890
|
684 |
|
boehmes@36890
|
685 |
fun unfold_conv ctxt ths =
|
boehmes@41576
|
686 |
Conv.arg_conv (Conv.binop_conv (Z3_Proof_Tools.unfold_eqs ctxt
|
boehmes@41576
|
687 |
(map prep ths)))
|
boehmes@36890
|
688 |
|
boehmes@36890
|
689 |
fun with_conv _ [] prv = prv
|
boehmes@41576
|
690 |
| with_conv ctxt ths prv =
|
boehmes@41576
|
691 |
Z3_Proof_Tools.with_conv (unfold_conv ctxt ths) prv
|
boehmes@36890
|
692 |
|
boehmes@36890
|
693 |
val unfold_conv =
|
boehmes@41576
|
694 |
Conv.arg_conv (Conv.binop_conv
|
boehmes@41576
|
695 |
(Conv.try_conv Z3_Proof_Tools.unfold_distinct_conv))
|
boehmes@41576
|
696 |
val prove_conj_disj_eq =
|
boehmes@41576
|
697 |
Z3_Proof_Tools.with_conv unfold_conv Z3_Proof_Literals.prove_conj_disj_eq
|
boehmes@40911
|
698 |
|
boehmes@42770
|
699 |
fun declare_hyps ctxt thm =
|
boehmes@42770
|
700 |
(thm, snd (Assumption.add_assumes (#hyps (Thm.crep_thm thm)) ctxt))
|
boehmes@36890
|
701 |
in
|
boehmes@36890
|
702 |
|
boehmes@43833
|
703 |
val abstraction_depth = 3
|
boehmes@43833
|
704 |
(*
|
boehmes@43833
|
705 |
This value was chosen large enough to potentially catch exceptions,
|
boehmes@43833
|
706 |
yet small enough to not cause too much harm. The value might be
|
boehmes@43833
|
707 |
increased in the future, if reconstructing 'rewrite' fails on problems
|
boehmes@43833
|
708 |
that get too much abstracted to be reconstructable.
|
boehmes@43833
|
709 |
*)
|
boehmes@43833
|
710 |
|
boehmes@40911
|
711 |
fun rewrite simpset ths ct ctxt =
|
boehmes@42770
|
712 |
apfst Thm (declare_hyps ctxt (with_conv ctxt ths (try_apply ctxt [] [
|
boehmes@40911
|
713 |
named ctxt "conj/disj/distinct" prove_conj_disj_eq,
|
boehmes@43833
|
714 |
Z3_Proof_Tools.by_abstraction 0 (true, false) ctxt [] (fn ctxt' =>
|
boehmes@41576
|
715 |
Z3_Proof_Tools.by_tac (
|
boehmes@41576
|
716 |
NAMED ctxt' "simp (logic)" (Simplifier.simp_tac simpset)
|
wenzelm@43665
|
717 |
THEN_ALL_NEW NAMED ctxt' "fast (logic)" (fast_tac ctxt'))),
|
boehmes@43833
|
718 |
Z3_Proof_Tools.by_abstraction 0 (false, true) ctxt [] (fn ctxt' =>
|
boehmes@41576
|
719 |
Z3_Proof_Tools.by_tac (
|
boehmes@41576
|
720 |
NAMED ctxt' "simp (theory)" (Simplifier.simp_tac simpset)
|
boehmes@41576
|
721 |
THEN_ALL_NEW (
|
wenzelm@43665
|
722 |
NAMED ctxt' "fast (theory)" (HOL_fast_tac ctxt')
|
boehmes@41576
|
723 |
ORELSE' NAMED ctxt' "arith (theory)" (Arith_Data.arith_tac ctxt')))),
|
boehmes@43833
|
724 |
Z3_Proof_Tools.by_abstraction 0 (true, true) ctxt [] (fn ctxt' =>
|
boehmes@41576
|
725 |
Z3_Proof_Tools.by_tac (
|
boehmes@41576
|
726 |
NAMED ctxt' "simp (full)" (Simplifier.simp_tac simpset)
|
boehmes@41576
|
727 |
THEN_ALL_NEW (
|
wenzelm@43665
|
728 |
NAMED ctxt' "fast (full)" (HOL_fast_tac ctxt')
|
boehmes@41576
|
729 |
ORELSE' NAMED ctxt' "arith (full)" (Arith_Data.arith_tac ctxt')))),
|
boehmes@43833
|
730 |
named ctxt "injectivity" (Z3_Proof_Methods.prove_injectivity ctxt),
|
boehmes@43833
|
731 |
Z3_Proof_Tools.by_abstraction abstraction_depth (true, true) ctxt []
|
boehmes@43833
|
732 |
(fn ctxt' =>
|
boehmes@43833
|
733 |
Z3_Proof_Tools.by_tac (
|
boehmes@43833
|
734 |
NAMED ctxt' "simp (deepen)" (Simplifier.simp_tac simpset)
|
boehmes@43833
|
735 |
THEN_ALL_NEW (
|
boehmes@43833
|
736 |
NAMED ctxt' "fast (deepen)" (HOL_fast_tac ctxt')
|
boehmes@43833
|
737 |
ORELSE' NAMED ctxt' "arith (deepen)" (Arith_Data.arith_tac
|
boehmes@43833
|
738 |
ctxt'))))]) ct))
|
boehmes@36890
|
739 |
|
boehmes@36890
|
740 |
end
|
boehmes@36890
|
741 |
|
boehmes@36890
|
742 |
|
boehmes@36890
|
743 |
|
boehmes@41378
|
744 |
(* proof reconstruction *)
|
boehmes@36890
|
745 |
|
boehmes@41378
|
746 |
(** tracing and checking **)
|
boehmes@36890
|
747 |
|
boehmes@41378
|
748 |
fun trace_before ctxt idx = SMT_Config.trace_msg ctxt (fn r =>
|
boehmes@41576
|
749 |
"Z3: #" ^ string_of_int idx ^ ": " ^ Z3_Proof_Parser.string_of_rule r)
|
boehmes@36890
|
750 |
|
boehmes@41378
|
751 |
fun check_after idx r ps ct (p, (ctxt, _)) =
|
boehmes@41378
|
752 |
if not (Config.get ctxt SMT_Config.trace) then ()
|
boehmes@41378
|
753 |
else
|
boehmes@36890
|
754 |
let val thm = thm_of p |> tap (Thm.join_proofs o single)
|
boehmes@36890
|
755 |
in
|
boehmes@36890
|
756 |
if (Thm.cprop_of thm) aconvc ct then ()
|
boehmes@41576
|
757 |
else
|
boehmes@41576
|
758 |
z3_exn (Pretty.string_of (Pretty.big_list
|
boehmes@41576
|
759 |
("proof step failed: " ^ quote (Z3_Proof_Parser.string_of_rule r) ^
|
boehmes@41576
|
760 |
" (#" ^ string_of_int idx ^ ")")
|
boehmes@36890
|
761 |
(pretty_goal ctxt (map (thm_of o fst) ps) (Thm.prop_of thm) @
|
boehmes@41576
|
762 |
[Pretty.block [Pretty.str "expected: ",
|
boehmes@41576
|
763 |
Syntax.pretty_term ctxt (Thm.term_of ct)]])))
|
boehmes@36890
|
764 |
end
|
boehmes@36890
|
765 |
|
boehmes@36890
|
766 |
|
boehmes@41378
|
767 |
(** overall reconstruction procedure **)
|
boehmes@36890
|
768 |
|
boehmes@40405
|
769 |
local
|
boehmes@40405
|
770 |
fun not_supported r = raise Fail ("Z3: proof rule not implemented: " ^
|
boehmes@41576
|
771 |
quote (Z3_Proof_Parser.string_of_rule r))
|
boehmes@36890
|
772 |
|
boehmes@41379
|
773 |
fun prove_step simpset vars r ps ct (cxp as (cx, ptab)) =
|
boehmes@40405
|
774 |
(case (r, ps) of
|
boehmes@40405
|
775 |
(* core rules *)
|
boehmes@41576
|
776 |
(Z3_Proof_Parser.True_Axiom, _) => (Thm Z3_Proof_Literals.true_thm, cxp)
|
boehmes@41576
|
777 |
| (Z3_Proof_Parser.Asserted, _) => raise Fail "bad assertion"
|
boehmes@41576
|
778 |
| (Z3_Proof_Parser.Goal, _) => raise Fail "bad assertion"
|
boehmes@41576
|
779 |
| (Z3_Proof_Parser.Modus_Ponens, [(p, _), (q, _)]) =>
|
boehmes@41576
|
780 |
(mp q (thm_of p), cxp)
|
boehmes@41576
|
781 |
| (Z3_Proof_Parser.Modus_Ponens_Oeq, [(p, _), (q, _)]) =>
|
boehmes@41576
|
782 |
(mp q (thm_of p), cxp)
|
boehmes@41576
|
783 |
| (Z3_Proof_Parser.And_Elim, [(p, i)]) =>
|
boehmes@41576
|
784 |
and_elim (p, i) ct ptab ||> pair cx
|
boehmes@41576
|
785 |
| (Z3_Proof_Parser.Not_Or_Elim, [(p, i)]) =>
|
boehmes@41576
|
786 |
not_or_elim (p, i) ct ptab ||> pair cx
|
boehmes@41576
|
787 |
| (Z3_Proof_Parser.Hypothesis, _) => (Thm (Thm.assume ct), cxp)
|
boehmes@41576
|
788 |
| (Z3_Proof_Parser.Lemma, [(p, _)]) => (lemma (thm_of p) ct, cxp)
|
boehmes@41576
|
789 |
| (Z3_Proof_Parser.Unit_Resolution, (p, _) :: ps) =>
|
boehmes@40405
|
790 |
(unit_resolution (thm_of p) (map (thm_of o fst) ps) ct, cxp)
|
boehmes@41576
|
791 |
| (Z3_Proof_Parser.Iff_True, [(p, _)]) => (iff_true (thm_of p), cxp)
|
boehmes@41576
|
792 |
| (Z3_Proof_Parser.Iff_False, [(p, _)]) => (iff_false (thm_of p), cxp)
|
boehmes@41576
|
793 |
| (Z3_Proof_Parser.Distributivity, _) => (distributivity cx ct, cxp)
|
boehmes@41576
|
794 |
| (Z3_Proof_Parser.Def_Axiom, _) => (def_axiom cx ct, cxp)
|
boehmes@41576
|
795 |
| (Z3_Proof_Parser.Intro_Def, _) => intro_def ct cx ||> rpair ptab
|
boehmes@41576
|
796 |
| (Z3_Proof_Parser.Apply_Def, [(p, _)]) => (apply_def (thm_of p), cxp)
|
boehmes@41576
|
797 |
| (Z3_Proof_Parser.Iff_Oeq, [(p, _)]) => (p, cxp)
|
boehmes@41576
|
798 |
| (Z3_Proof_Parser.Nnf_Pos, _) => (nnf cx vars (map fst ps) ct, cxp)
|
boehmes@41576
|
799 |
| (Z3_Proof_Parser.Nnf_Neg, _) => (nnf cx vars (map fst ps) ct, cxp)
|
boehmes@40405
|
800 |
|
boehmes@40405
|
801 |
(* equality rules *)
|
boehmes@41576
|
802 |
| (Z3_Proof_Parser.Reflexivity, _) => (refl ct, cxp)
|
boehmes@41576
|
803 |
| (Z3_Proof_Parser.Symmetry, [(p, _)]) => (symm p, cxp)
|
boehmes@41576
|
804 |
| (Z3_Proof_Parser.Transitivity, [(p, _), (q, _)]) => (trans p q, cxp)
|
boehmes@41576
|
805 |
| (Z3_Proof_Parser.Monotonicity, _) => (monotonicity (map fst ps) ct, cxp)
|
boehmes@41576
|
806 |
| (Z3_Proof_Parser.Commutativity, _) => (commutativity ct, cxp)
|
boehmes@40405
|
807 |
|
boehmes@40405
|
808 |
(* quantifier rules *)
|
boehmes@41576
|
809 |
| (Z3_Proof_Parser.Quant_Intro, [(p, _)]) => (quant_intro vars p ct, cxp)
|
boehmes@41576
|
810 |
| (Z3_Proof_Parser.Pull_Quant, _) => (pull_quant cx ct, cxp)
|
boehmes@41576
|
811 |
| (Z3_Proof_Parser.Push_Quant, _) => (push_quant cx ct, cxp)
|
boehmes@43178
|
812 |
| (Z3_Proof_Parser.Elim_Unused_Vars, _) => (elim_unused_vars ct, cxp)
|
boehmes@41576
|
813 |
| (Z3_Proof_Parser.Dest_Eq_Res, _) => (dest_eq_res cx ct, cxp)
|
boehmes@41576
|
814 |
| (Z3_Proof_Parser.Quant_Inst, _) => (quant_inst ct, cxp)
|
boehmes@43062
|
815 |
| (Z3_Proof_Parser.Skolemize, _) => skolemize vars ct cx ||> rpair ptab
|
boehmes@40405
|
816 |
|
boehmes@40405
|
817 |
(* theory rules *)
|
boehmes@41576
|
818 |
| (Z3_Proof_Parser.Th_Lemma _, _) => (* FIXME: use arguments *)
|
boehmes@40405
|
819 |
(th_lemma cx simpset (map (thm_of o fst) ps) ct, cxp)
|
boehmes@41576
|
820 |
| (Z3_Proof_Parser.Rewrite, _) => rewrite simpset [] ct cx ||> rpair ptab
|
boehmes@41576
|
821 |
| (Z3_Proof_Parser.Rewrite_Star, ps) =>
|
boehmes@41576
|
822 |
rewrite simpset (map fst ps) ct cx ||> rpair ptab
|
boehmes@40405
|
823 |
|
boehmes@41576
|
824 |
| (Z3_Proof_Parser.Nnf_Star, _) => not_supported r
|
boehmes@41576
|
825 |
| (Z3_Proof_Parser.Cnf_Star, _) => not_supported r
|
boehmes@41576
|
826 |
| (Z3_Proof_Parser.Transitivity_Star, _) => not_supported r
|
boehmes@41576
|
827 |
| (Z3_Proof_Parser.Pull_Quant_Star, _) => not_supported r
|
boehmes@40405
|
828 |
|
boehmes@41576
|
829 |
| _ => raise Fail ("Z3: proof rule " ^
|
boehmes@41576
|
830 |
quote (Z3_Proof_Parser.string_of_rule r) ^
|
boehmes@41576
|
831 |
" has an unexpected number of arguments."))
|
boehmes@40405
|
832 |
|
boehmes@41378
|
833 |
fun lookup_proof ptab idx =
|
boehmes@41378
|
834 |
(case Inttab.lookup ptab idx of
|
boehmes@41378
|
835 |
SOME p => (p, idx)
|
boehmes@41378
|
836 |
| NONE => z3_exn ("unknown proof id: " ^ quote (string_of_int idx)))
|
boehmes@41378
|
837 |
|
boehmes@41379
|
838 |
fun prove simpset vars (idx, step) (_, cxp as (ctxt, ptab)) =
|
boehmes@40405
|
839 |
let
|
boehmes@41576
|
840 |
val Z3_Proof_Parser.Proof_Step {rule=r, prems, prop, ...} = step
|
boehmes@41378
|
841 |
val ps = map (lookup_proof ptab) prems
|
boehmes@41378
|
842 |
val _ = trace_before ctxt idx r
|
boehmes@41378
|
843 |
val (thm, (ctxt', ptab')) =
|
boehmes@41378
|
844 |
cxp
|
boehmes@41379
|
845 |
|> prove_step simpset vars r ps prop
|
boehmes@41378
|
846 |
|> tap (check_after idx r ps prop)
|
boehmes@41378
|
847 |
in (thm, (ctxt', Inttab.update (idx, thm) ptab')) end
|
boehmes@40405
|
848 |
|
boehmes@43062
|
849 |
fun make_discharge_rules rules = rules @ [@{thm allI}, @{thm refl},
|
boehmes@43062
|
850 |
@{thm reflexive}, Z3_Proof_Literals.true_thm]
|
boehmes@41375
|
851 |
|
boehmes@43062
|
852 |
fun discharge_tac rules =
|
boehmes@43062
|
853 |
Tactic.resolve_tac rules ORELSE' SOLVED' discharge_sk_tac
|
boehmes@43062
|
854 |
|
boehmes@43062
|
855 |
fun discharge_assms rules thm =
|
boehmes@43062
|
856 |
if Thm.nprems_of thm = 0 then Goal.norm_result thm
|
boehmes@41375
|
857 |
else
|
boehmes@43062
|
858 |
(case Seq.pull (discharge_tac rules 1 thm) of
|
boehmes@43062
|
859 |
SOME (thm', _) => discharge_assms rules thm'
|
boehmes@41375
|
860 |
| NONE => raise THM ("failed to discharge premise", 1, [thm]))
|
boehmes@41375
|
861 |
|
boehmes@41379
|
862 |
fun discharge rules outer_ctxt (p, (inner_ctxt, _)) =
|
boehmes@41378
|
863 |
thm_of p
|
wenzelm@43232
|
864 |
|> singleton (Proof_Context.export inner_ctxt outer_ctxt)
|
boehmes@43062
|
865 |
|> discharge_assms (make_discharge_rules rules)
|
boehmes@40405
|
866 |
in
|
boehmes@40405
|
867 |
|
boehmes@41375
|
868 |
fun reconstruct outer_ctxt recon output =
|
boehmes@36890
|
869 |
let
|
boehmes@41375
|
870 |
val {context=ctxt, typs, terms, rewrite_rules, assms} = recon
|
boehmes@41576
|
871 |
val (asserted, steps, vars, ctxt1) =
|
boehmes@41576
|
872 |
Z3_Proof_Parser.parse ctxt typs terms output
|
boehmes@41379
|
873 |
|
boehmes@41576
|
874 |
val simpset = Z3_Proof_Tools.make_simpset ctxt1 (Z3_Simps.get ctxt1)
|
boehmes@41379
|
875 |
|
boehmes@41379
|
876 |
val ((is, rules), cxp as (ctxt2, _)) =
|
boehmes@41379
|
877 |
add_asserted outer_ctxt rewrite_rules assms asserted ctxt1
|
boehmes@36890
|
878 |
in
|
boehmes@41379
|
879 |
if Config.get ctxt2 SMT_Config.filter_only_facts then (is, @{thm TrueI})
|
boehmes@41375
|
880 |
else
|
boehmes@41379
|
881 |
(Thm @{thm TrueI}, cxp)
|
boehmes@41379
|
882 |
|> fold (prove simpset vars) steps
|
boehmes@43062
|
883 |
|> discharge rules outer_ctxt
|
boehmes@41375
|
884 |
|> pair []
|
boehmes@36890
|
885 |
end
|
boehmes@36890
|
886 |
|
boehmes@40405
|
887 |
end
|
boehmes@36890
|
888 |
|
boehmes@40405
|
889 |
val setup = z3_rules_setup #> Z3_Simps.setup
|
boehmes@36890
|
890 |
|
boehmes@36890
|
891 |
end
|