|
1 (* Title: HOL/Library/Old_SMT.thy |
|
2 Author: Sascha Boehme, TU Muenchen |
|
3 *) |
|
4 |
|
5 header {* Old Version of Bindings to Satisfiability Modulo Theories (SMT) solvers *} |
|
6 |
|
7 theory Old_SMT |
|
8 imports "../Real" "../Word/Word" |
|
9 keywords "smt_status" :: diag |
|
10 begin |
|
11 |
|
12 ML_file "Old_SMT/smt_utils.ML" |
|
13 ML_file "Old_SMT/smt_failure.ML" |
|
14 ML_file "Old_SMT/smt_config.ML" |
|
15 |
|
16 |
|
17 subsection {* Triggers for quantifier instantiation *} |
|
18 |
|
19 text {* |
|
20 Some SMT solvers support patterns as a quantifier instantiation |
|
21 heuristics. Patterns may either be positive terms (tagged by "pat") |
|
22 triggering quantifier instantiations -- when the solver finds a |
|
23 term matching a positive pattern, it instantiates the corresponding |
|
24 quantifier accordingly -- or negative terms (tagged by "nopat") |
|
25 inhibiting quantifier instantiations. A list of patterns |
|
26 of the same kind is called a multipattern, and all patterns in a |
|
27 multipattern are considered conjunctively for quantifier instantiation. |
|
28 A list of multipatterns is called a trigger, and their multipatterns |
|
29 act disjunctively during quantifier instantiation. Each multipattern |
|
30 should mention at least all quantified variables of the preceding |
|
31 quantifier block. |
|
32 *} |
|
33 |
|
34 typedecl pattern |
|
35 |
|
36 consts |
|
37 pat :: "'a \<Rightarrow> pattern" |
|
38 nopat :: "'a \<Rightarrow> pattern" |
|
39 |
|
40 definition trigger :: "pattern list list \<Rightarrow> bool \<Rightarrow> bool" where "trigger _ P = P" |
|
41 |
|
42 |
|
43 subsection {* Quantifier weights *} |
|
44 |
|
45 text {* |
|
46 Weight annotations to quantifiers influence the priority of quantifier |
|
47 instantiations. They should be handled with care for solvers, which support |
|
48 them, because incorrect choices of weights might render a problem unsolvable. |
|
49 *} |
|
50 |
|
51 definition weight :: "int \<Rightarrow> bool \<Rightarrow> bool" where "weight _ P = P" |
|
52 |
|
53 text {* |
|
54 Weights must be non-negative. The value @{text 0} is equivalent to providing |
|
55 no weight at all. |
|
56 |
|
57 Weights should only be used at quantifiers and only inside triggers (if the |
|
58 quantifier has triggers). Valid usages of weights are as follows: |
|
59 |
|
60 \begin{itemize} |
|
61 \item |
|
62 @{term "\<forall>x. trigger [[pat (P x)]] (weight 2 (P x))"} |
|
63 \item |
|
64 @{term "\<forall>x. weight 3 (P x)"} |
|
65 \end{itemize} |
|
66 *} |
|
67 |
|
68 |
|
69 subsection {* Higher-order encoding *} |
|
70 |
|
71 text {* |
|
72 Application is made explicit for constants occurring with varying |
|
73 numbers of arguments. This is achieved by the introduction of the |
|
74 following constant. |
|
75 *} |
|
76 |
|
77 definition fun_app where "fun_app f = f" |
|
78 |
|
79 text {* |
|
80 Some solvers support a theory of arrays which can be used to encode |
|
81 higher-order functions. The following set of lemmas specifies the |
|
82 properties of such (extensional) arrays. |
|
83 *} |
|
84 |
|
85 lemmas array_rules = ext fun_upd_apply fun_upd_same fun_upd_other |
|
86 fun_upd_upd fun_app_def |
|
87 |
|
88 |
|
89 subsection {* First-order logic *} |
|
90 |
|
91 text {* |
|
92 Some SMT solvers only accept problems in first-order logic, i.e., |
|
93 where formulas and terms are syntactically separated. When |
|
94 translating higher-order into first-order problems, all |
|
95 uninterpreted constants (those not built-in in the target solver) |
|
96 are treated as function symbols in the first-order sense. Their |
|
97 occurrences as head symbols in atoms (i.e., as predicate symbols) are |
|
98 turned into terms by logically equating such atoms with @{term True}. |
|
99 For technical reasons, @{term True} and @{term False} occurring inside |
|
100 terms are replaced by the following constants. |
|
101 *} |
|
102 |
|
103 definition term_true where "term_true = True" |
|
104 definition term_false where "term_false = False" |
|
105 |
|
106 |
|
107 subsection {* Integer division and modulo for Z3 *} |
|
108 |
|
109 definition z3div :: "int \<Rightarrow> int \<Rightarrow> int" where |
|
110 "z3div k l = (if 0 \<le> l then k div l else -(k div (-l)))" |
|
111 |
|
112 definition z3mod :: "int \<Rightarrow> int \<Rightarrow> int" where |
|
113 "z3mod k l = (if 0 \<le> l then k mod l else k mod (-l))" |
|
114 |
|
115 |
|
116 subsection {* Setup *} |
|
117 |
|
118 ML_file "Old_SMT/smt_builtin.ML" |
|
119 ML_file "Old_SMT/smt_datatypes.ML" |
|
120 ML_file "Old_SMT/smt_normalize.ML" |
|
121 ML_file "Old_SMT/smt_translate.ML" |
|
122 ML_file "Old_SMT/smt_solver.ML" |
|
123 ML_file "Old_SMT/smtlib_interface.ML" |
|
124 ML_file "Old_SMT/z3_interface.ML" |
|
125 ML_file "Old_SMT/z3_proof_parser.ML" |
|
126 ML_file "Old_SMT/z3_proof_tools.ML" |
|
127 ML_file "Old_SMT/z3_proof_literals.ML" |
|
128 ML_file "Old_SMT/z3_proof_methods.ML" |
|
129 named_theorems z3_simp "simplification rules for Z3 proof reconstruction" |
|
130 ML_file "Old_SMT/z3_proof_reconstruction.ML" |
|
131 ML_file "Old_SMT/z3_model.ML" |
|
132 ML_file "Old_SMT/smt_setup_solvers.ML" |
|
133 |
|
134 setup {* |
|
135 SMT_Config.setup #> |
|
136 SMT_Normalize.setup #> |
|
137 SMTLIB_Interface.setup #> |
|
138 Z3_Interface.setup #> |
|
139 SMT_Setup_Solvers.setup |
|
140 *} |
|
141 |
|
142 method_setup smt = {* |
|
143 Scan.optional Attrib.thms [] >> |
|
144 (fn thms => fn ctxt => |
|
145 METHOD (fn facts => HEADGOAL (SMT_Solver.smt_tac ctxt (thms @ facts)))) |
|
146 *} "apply an SMT solver to the current goal" |
|
147 |
|
148 |
|
149 subsection {* Configuration *} |
|
150 |
|
151 text {* |
|
152 The current configuration can be printed by the command |
|
153 @{text smt_status}, which shows the values of most options. |
|
154 *} |
|
155 |
|
156 |
|
157 |
|
158 subsection {* General configuration options *} |
|
159 |
|
160 text {* |
|
161 The option @{text smt_solver} can be used to change the target SMT |
|
162 solver. The possible values can be obtained from the @{text smt_status} |
|
163 command. |
|
164 |
|
165 Due to licensing restrictions, Yices and Z3 are not installed/enabled |
|
166 by default. Z3 is free for non-commercial applications and can be enabled |
|
167 by setting Isabelle system option @{text z3_non_commercial} to @{text yes}. |
|
168 *} |
|
169 |
|
170 declare [[ smt_solver = z3 ]] |
|
171 |
|
172 text {* |
|
173 Since SMT solvers are potentially non-terminating, there is a timeout |
|
174 (given in seconds) to restrict their runtime. A value greater than |
|
175 120 (seconds) is in most cases not advisable. |
|
176 *} |
|
177 |
|
178 declare [[ smt_timeout = 20 ]] |
|
179 |
|
180 text {* |
|
181 SMT solvers apply randomized heuristics. In case a problem is not |
|
182 solvable by an SMT solver, changing the following option might help. |
|
183 *} |
|
184 |
|
185 declare [[ smt_random_seed = 1 ]] |
|
186 |
|
187 text {* |
|
188 In general, the binding to SMT solvers runs as an oracle, i.e, the SMT |
|
189 solvers are fully trusted without additional checks. The following |
|
190 option can cause the SMT solver to run in proof-producing mode, giving |
|
191 a checkable certificate. This is currently only implemented for Z3. |
|
192 *} |
|
193 |
|
194 declare [[ smt_oracle = false ]] |
|
195 |
|
196 text {* |
|
197 Each SMT solver provides several commandline options to tweak its |
|
198 behaviour. They can be passed to the solver by setting the following |
|
199 options. |
|
200 *} |
|
201 |
|
202 declare [[ cvc3_options = "" ]] |
|
203 declare [[ yices_options = "" ]] |
|
204 declare [[ z3_options = "" ]] |
|
205 |
|
206 text {* |
|
207 Enable the following option to use built-in support for datatypes and |
|
208 records. Currently, this is only implemented for Z3 running in oracle |
|
209 mode. |
|
210 *} |
|
211 |
|
212 declare [[ smt_datatypes = false ]] |
|
213 |
|
214 text {* |
|
215 The SMT method provides an inference mechanism to detect simple triggers |
|
216 in quantified formulas, which might increase the number of problems |
|
217 solvable by SMT solvers (note: triggers guide quantifier instantiations |
|
218 in the SMT solver). To turn it on, set the following option. |
|
219 *} |
|
220 |
|
221 declare [[ smt_infer_triggers = false ]] |
|
222 |
|
223 text {* |
|
224 The SMT method monomorphizes the given facts, that is, it tries to |
|
225 instantiate all schematic type variables with fixed types occurring |
|
226 in the problem. This is a (possibly nonterminating) fixed-point |
|
227 construction whose cycles are limited by the following option. |
|
228 *} |
|
229 |
|
230 declare [[ monomorph_max_rounds = 5 ]] |
|
231 |
|
232 text {* |
|
233 In addition, the number of generated monomorphic instances is limited |
|
234 by the following option. |
|
235 *} |
|
236 |
|
237 declare [[ monomorph_max_new_instances = 500 ]] |
|
238 |
|
239 |
|
240 |
|
241 subsection {* Certificates *} |
|
242 |
|
243 text {* |
|
244 By setting the option @{text smt_certificates} to the name of a file, |
|
245 all following applications of an SMT solver a cached in that file. |
|
246 Any further application of the same SMT solver (using the very same |
|
247 configuration) re-uses the cached certificate instead of invoking the |
|
248 solver. An empty string disables caching certificates. |
|
249 |
|
250 The filename should be given as an explicit path. It is good |
|
251 practice to use the name of the current theory (with ending |
|
252 @{text ".certs"} instead of @{text ".thy"}) as the certificates file. |
|
253 Certificate files should be used at most once in a certain theory context, |
|
254 to avoid race conditions with other concurrent accesses. |
|
255 *} |
|
256 |
|
257 declare [[ smt_certificates = "" ]] |
|
258 |
|
259 text {* |
|
260 The option @{text smt_read_only_certificates} controls whether only |
|
261 stored certificates are should be used or invocation of an SMT solver |
|
262 is allowed. When set to @{text true}, no SMT solver will ever be |
|
263 invoked and only the existing certificates found in the configured |
|
264 cache are used; when set to @{text false} and there is no cached |
|
265 certificate for some proposition, then the configured SMT solver is |
|
266 invoked. |
|
267 *} |
|
268 |
|
269 declare [[ smt_read_only_certificates = false ]] |
|
270 |
|
271 |
|
272 |
|
273 subsection {* Tracing *} |
|
274 |
|
275 text {* |
|
276 The SMT method, when applied, traces important information. To |
|
277 make it entirely silent, set the following option to @{text false}. |
|
278 *} |
|
279 |
|
280 declare [[ smt_verbose = true ]] |
|
281 |
|
282 text {* |
|
283 For tracing the generated problem file given to the SMT solver as |
|
284 well as the returned result of the solver, the option |
|
285 @{text smt_trace} should be set to @{text true}. |
|
286 *} |
|
287 |
|
288 declare [[ smt_trace = false ]] |
|
289 |
|
290 text {* |
|
291 From the set of assumptions given to the SMT solver, those assumptions |
|
292 used in the proof are traced when the following option is set to |
|
293 @{term true}. This only works for Z3 when it runs in non-oracle mode |
|
294 (see options @{text smt_solver} and @{text smt_oracle} above). |
|
295 *} |
|
296 |
|
297 declare [[ smt_trace_used_facts = false ]] |
|
298 |
|
299 |
|
300 |
|
301 subsection {* Schematic rules for Z3 proof reconstruction *} |
|
302 |
|
303 text {* |
|
304 Several prof rules of Z3 are not very well documented. There are two |
|
305 lemma groups which can turn failing Z3 proof reconstruction attempts |
|
306 into succeeding ones: the facts in @{text z3_rule} are tried prior to |
|
307 any implemented reconstruction procedure for all uncertain Z3 proof |
|
308 rules; the facts in @{text z3_simp} are only fed to invocations of |
|
309 the simplifier when reconstructing theory-specific proof steps. |
|
310 *} |
|
311 |
|
312 lemmas [z3_rule] = |
|
313 refl eq_commute conj_commute disj_commute simp_thms nnf_simps |
|
314 ring_distribs field_simps times_divide_eq_right times_divide_eq_left |
|
315 if_True if_False not_not |
|
316 |
|
317 lemma [z3_rule]: |
|
318 "(P \<and> Q) = (\<not>(\<not>P \<or> \<not>Q))" |
|
319 "(P \<and> Q) = (\<not>(\<not>Q \<or> \<not>P))" |
|
320 "(\<not>P \<and> Q) = (\<not>(P \<or> \<not>Q))" |
|
321 "(\<not>P \<and> Q) = (\<not>(\<not>Q \<or> P))" |
|
322 "(P \<and> \<not>Q) = (\<not>(\<not>P \<or> Q))" |
|
323 "(P \<and> \<not>Q) = (\<not>(Q \<or> \<not>P))" |
|
324 "(\<not>P \<and> \<not>Q) = (\<not>(P \<or> Q))" |
|
325 "(\<not>P \<and> \<not>Q) = (\<not>(Q \<or> P))" |
|
326 by auto |
|
327 |
|
328 lemma [z3_rule]: |
|
329 "(P \<longrightarrow> Q) = (Q \<or> \<not>P)" |
|
330 "(\<not>P \<longrightarrow> Q) = (P \<or> Q)" |
|
331 "(\<not>P \<longrightarrow> Q) = (Q \<or> P)" |
|
332 "(True \<longrightarrow> P) = P" |
|
333 "(P \<longrightarrow> True) = True" |
|
334 "(False \<longrightarrow> P) = True" |
|
335 "(P \<longrightarrow> P) = True" |
|
336 by auto |
|
337 |
|
338 lemma [z3_rule]: |
|
339 "((P = Q) \<longrightarrow> R) = (R | (Q = (\<not>P)))" |
|
340 by auto |
|
341 |
|
342 lemma [z3_rule]: |
|
343 "(\<not>True) = False" |
|
344 "(\<not>False) = True" |
|
345 "(x = x) = True" |
|
346 "(P = True) = P" |
|
347 "(True = P) = P" |
|
348 "(P = False) = (\<not>P)" |
|
349 "(False = P) = (\<not>P)" |
|
350 "((\<not>P) = P) = False" |
|
351 "(P = (\<not>P)) = False" |
|
352 "((\<not>P) = (\<not>Q)) = (P = Q)" |
|
353 "\<not>(P = (\<not>Q)) = (P = Q)" |
|
354 "\<not>((\<not>P) = Q) = (P = Q)" |
|
355 "(P \<noteq> Q) = (Q = (\<not>P))" |
|
356 "(P = Q) = ((\<not>P \<or> Q) \<and> (P \<or> \<not>Q))" |
|
357 "(P \<noteq> Q) = ((\<not>P \<or> \<not>Q) \<and> (P \<or> Q))" |
|
358 by auto |
|
359 |
|
360 lemma [z3_rule]: |
|
361 "(if P then P else \<not>P) = True" |
|
362 "(if \<not>P then \<not>P else P) = True" |
|
363 "(if P then True else False) = P" |
|
364 "(if P then False else True) = (\<not>P)" |
|
365 "(if P then Q else True) = ((\<not>P) \<or> Q)" |
|
366 "(if P then Q else True) = (Q \<or> (\<not>P))" |
|
367 "(if P then Q else \<not>Q) = (P = Q)" |
|
368 "(if P then Q else \<not>Q) = (Q = P)" |
|
369 "(if P then \<not>Q else Q) = (P = (\<not>Q))" |
|
370 "(if P then \<not>Q else Q) = ((\<not>Q) = P)" |
|
371 "(if \<not>P then x else y) = (if P then y else x)" |
|
372 "(if P then (if Q then x else y) else x) = (if P \<and> (\<not>Q) then y else x)" |
|
373 "(if P then (if Q then x else y) else x) = (if (\<not>Q) \<and> P then y else x)" |
|
374 "(if P then (if Q then x else y) else y) = (if P \<and> Q then x else y)" |
|
375 "(if P then (if Q then x else y) else y) = (if Q \<and> P then x else y)" |
|
376 "(if P then x else if P then y else z) = (if P then x else z)" |
|
377 "(if P then x else if Q then x else y) = (if P \<or> Q then x else y)" |
|
378 "(if P then x else if Q then x else y) = (if Q \<or> P then x else y)" |
|
379 "(if P then x = y else x = z) = (x = (if P then y else z))" |
|
380 "(if P then x = y else y = z) = (y = (if P then x else z))" |
|
381 "(if P then x = y else z = y) = (y = (if P then x else z))" |
|
382 by auto |
|
383 |
|
384 lemma [z3_rule]: |
|
385 "0 + (x::int) = x" |
|
386 "x + 0 = x" |
|
387 "x + x = 2 * x" |
|
388 "0 * x = 0" |
|
389 "1 * x = x" |
|
390 "x + y = y + x" |
|
391 by auto |
|
392 |
|
393 lemma [z3_rule]: (* for def-axiom *) |
|
394 "P = Q \<or> P \<or> Q" |
|
395 "P = Q \<or> \<not>P \<or> \<not>Q" |
|
396 "(\<not>P) = Q \<or> \<not>P \<or> Q" |
|
397 "(\<not>P) = Q \<or> P \<or> \<not>Q" |
|
398 "P = (\<not>Q) \<or> \<not>P \<or> Q" |
|
399 "P = (\<not>Q) \<or> P \<or> \<not>Q" |
|
400 "P \<noteq> Q \<or> P \<or> \<not>Q" |
|
401 "P \<noteq> Q \<or> \<not>P \<or> Q" |
|
402 "P \<noteq> (\<not>Q) \<or> P \<or> Q" |
|
403 "(\<not>P) \<noteq> Q \<or> P \<or> Q" |
|
404 "P \<or> Q \<or> P \<noteq> (\<not>Q)" |
|
405 "P \<or> Q \<or> (\<not>P) \<noteq> Q" |
|
406 "P \<or> \<not>Q \<or> P \<noteq> Q" |
|
407 "\<not>P \<or> Q \<or> P \<noteq> Q" |
|
408 "P \<or> y = (if P then x else y)" |
|
409 "P \<or> (if P then x else y) = y" |
|
410 "\<not>P \<or> x = (if P then x else y)" |
|
411 "\<not>P \<or> (if P then x else y) = x" |
|
412 "P \<or> R \<or> \<not>(if P then Q else R)" |
|
413 "\<not>P \<or> Q \<or> \<not>(if P then Q else R)" |
|
414 "\<not>(if P then Q else R) \<or> \<not>P \<or> Q" |
|
415 "\<not>(if P then Q else R) \<or> P \<or> R" |
|
416 "(if P then Q else R) \<or> \<not>P \<or> \<not>Q" |
|
417 "(if P then Q else R) \<or> P \<or> \<not>R" |
|
418 "(if P then \<not>Q else R) \<or> \<not>P \<or> Q" |
|
419 "(if P then Q else \<not>R) \<or> P \<or> R" |
|
420 by auto |
|
421 |
|
422 ML_file "Old_SMT/smt_real.ML" |
|
423 setup SMT_Real.setup |
|
424 |
|
425 ML_file "Old_SMT/smt_word.ML" |
|
426 setup SMT_Word.setup |
|
427 |
|
428 hide_type (open) pattern |
|
429 hide_const fun_app term_true term_false z3div z3mod |
|
430 hide_const (open) trigger pat nopat weight |
|
431 |
|
432 end |