boehmes@36890
|
1 |
(* Title: HOL/Tools/SMT/z3_interface.ML
|
boehmes@36890
|
2 |
Author: Sascha Boehme, TU Muenchen
|
boehmes@36890
|
3 |
|
boehmes@36890
|
4 |
Interface to Z3 based on a relaxed version of SMT-LIB.
|
boehmes@36890
|
5 |
*)
|
boehmes@36890
|
6 |
|
boehmes@36890
|
7 |
signature Z3_INTERFACE =
|
boehmes@36890
|
8 |
sig
|
boehmes@41307
|
9 |
val smtlib_z3C: SMT_Config.class
|
boehmes@41307
|
10 |
val setup: theory -> theory
|
boehmes@40403
|
11 |
val interface: SMT_Solver.interface
|
boehmes@36890
|
12 |
|
boehmes@36891
|
13 |
datatype sym = Sym of string * sym list
|
boehmes@36891
|
14 |
type mk_builtins = {
|
boehmes@36891
|
15 |
mk_builtin_typ: sym -> typ option,
|
boehmes@36891
|
16 |
mk_builtin_num: theory -> int -> typ -> cterm option,
|
boehmes@36891
|
17 |
mk_builtin_fun: theory -> sym -> cterm list -> cterm option }
|
boehmes@36891
|
18 |
val add_mk_builtins: mk_builtins -> Context.generic -> Context.generic
|
boehmes@36891
|
19 |
val mk_builtin_typ: Proof.context -> sym -> typ option
|
boehmes@36891
|
20 |
val mk_builtin_num: Proof.context -> int -> typ -> cterm option
|
boehmes@36891
|
21 |
val mk_builtin_fun: Proof.context -> sym -> cterm list -> cterm option
|
boehmes@36891
|
22 |
|
boehmes@36891
|
23 |
val is_builtin_theory_term: Proof.context -> term -> bool
|
boehmes@36890
|
24 |
end
|
boehmes@36890
|
25 |
|
boehmes@36890
|
26 |
structure Z3_Interface: Z3_INTERFACE =
|
boehmes@36890
|
27 |
struct
|
boehmes@36890
|
28 |
|
boehmes@40910
|
29 |
structure U = SMT_Utils
|
boehmes@41307
|
30 |
structure B = SMT_Builtin
|
boehmes@40910
|
31 |
|
boehmes@41307
|
32 |
val smtlib_z3C = SMTLIB_Interface.smtlibC @ ["z3"]
|
boehmes@36890
|
33 |
|
boehmes@36890
|
34 |
|
boehmes@36891
|
35 |
|
boehmes@41307
|
36 |
(* interface *)
|
boehmes@36891
|
37 |
|
boehmes@36891
|
38 |
local
|
boehmes@41307
|
39 |
val {translate, extra_norm, ...} = SMTLIB_Interface.interface
|
boehmes@41307
|
40 |
val {prefixes, is_fol, header, serialize, ...} = translate
|
boehmes@36891
|
41 |
|
boehmes@40817
|
42 |
fun is_int_div_mod @{const div (int)} = true
|
boehmes@40817
|
43 |
| is_int_div_mod @{const mod (int)} = true
|
boehmes@37146
|
44 |
| is_int_div_mod _ = false
|
boehmes@37146
|
45 |
|
boehmes@40402
|
46 |
fun add_div_mod irules =
|
boehmes@40402
|
47 |
if exists (Term.exists_subterm is_int_div_mod o Thm.prop_of o snd) irules
|
boehmes@40402
|
48 |
then [(~1, @{thm div_by_z3div}), (~1, @{thm mod_by_z3mod})] @ irules
|
boehmes@40402
|
49 |
else irules
|
boehmes@37146
|
50 |
|
boehmes@41307
|
51 |
fun extra_norm' has_datatypes = extra_norm has_datatypes o add_div_mod
|
boehmes@36891
|
52 |
in
|
boehmes@36891
|
53 |
|
boehmes@41307
|
54 |
val setup =
|
boehmes@41307
|
55 |
B.add_builtin_fun' smtlib_z3C (@{const z3div}, "div") #>
|
boehmes@41307
|
56 |
B.add_builtin_fun' smtlib_z3C (@{const z3mod}, "mod")
|
boehmes@36890
|
57 |
|
boehmes@40403
|
58 |
val interface = {
|
boehmes@41307
|
59 |
class = smtlib_z3C,
|
boehmes@40403
|
60 |
extra_norm = extra_norm',
|
boehmes@36890
|
61 |
translate = {
|
boehmes@36890
|
62 |
prefixes = prefixes,
|
boehmes@41307
|
63 |
is_fol = is_fol,
|
boehmes@36891
|
64 |
header = header,
|
boehmes@41307
|
65 |
has_datatypes = true,
|
boehmes@36890
|
66 |
serialize = serialize}}
|
boehmes@36890
|
67 |
|
boehmes@36890
|
68 |
end
|
boehmes@36891
|
69 |
|
boehmes@36891
|
70 |
|
boehmes@36891
|
71 |
|
boehmes@41307
|
72 |
(* constructors *)
|
boehmes@36891
|
73 |
|
boehmes@36891
|
74 |
datatype sym = Sym of string * sym list
|
boehmes@36891
|
75 |
|
boehmes@36891
|
76 |
|
boehmes@41307
|
77 |
(** additional constructors **)
|
boehmes@36891
|
78 |
|
boehmes@36891
|
79 |
type mk_builtins = {
|
boehmes@36891
|
80 |
mk_builtin_typ: sym -> typ option,
|
boehmes@36891
|
81 |
mk_builtin_num: theory -> int -> typ -> cterm option,
|
boehmes@36891
|
82 |
mk_builtin_fun: theory -> sym -> cterm list -> cterm option }
|
boehmes@36891
|
83 |
|
boehmes@36891
|
84 |
fun chained _ [] = NONE
|
boehmes@36891
|
85 |
| chained f (b :: bs) = (case f b of SOME y => SOME y | NONE => chained f bs)
|
boehmes@36891
|
86 |
|
boehmes@36891
|
87 |
fun chained_mk_builtin_typ bs sym =
|
boehmes@36891
|
88 |
chained (fn {mk_builtin_typ=mk, ...} : mk_builtins => mk sym) bs
|
boehmes@36891
|
89 |
|
boehmes@36891
|
90 |
fun chained_mk_builtin_num ctxt bs i T =
|
boehmes@36891
|
91 |
let val thy = ProofContext.theory_of ctxt
|
boehmes@36891
|
92 |
in chained (fn {mk_builtin_num=mk, ...} : mk_builtins => mk thy i T) bs end
|
boehmes@36891
|
93 |
|
boehmes@36891
|
94 |
fun chained_mk_builtin_fun ctxt bs s cts =
|
boehmes@36891
|
95 |
let val thy = ProofContext.theory_of ctxt
|
boehmes@36891
|
96 |
in chained (fn {mk_builtin_fun=mk, ...} : mk_builtins => mk thy s cts) bs end
|
boehmes@36891
|
97 |
|
boehmes@41307
|
98 |
fun fst_int_ord ((i1, _), (i2, _)) = int_ord (i1, i2)
|
boehmes@41307
|
99 |
|
boehmes@36891
|
100 |
structure Mk_Builtins = Generic_Data
|
boehmes@36891
|
101 |
(
|
boehmes@36891
|
102 |
type T = (int * mk_builtins) list
|
boehmes@36891
|
103 |
val empty = []
|
boehmes@36891
|
104 |
val extend = I
|
wenzelm@39935
|
105 |
fun merge (bs1, bs2) = Ord_List.union fst_int_ord bs2 bs1
|
boehmes@36891
|
106 |
)
|
boehmes@36891
|
107 |
|
boehmes@36891
|
108 |
fun add_mk_builtins mk =
|
wenzelm@39935
|
109 |
Mk_Builtins.map (Ord_List.insert fst_int_ord (serial (), mk))
|
boehmes@36891
|
110 |
|
boehmes@36891
|
111 |
fun get_mk_builtins ctxt = map snd (Mk_Builtins.get (Context.Proof ctxt))
|
boehmes@36891
|
112 |
|
boehmes@36891
|
113 |
|
boehmes@41307
|
114 |
(** basic and additional constructors **)
|
boehmes@36891
|
115 |
|
boehmes@36891
|
116 |
fun mk_builtin_typ _ (Sym ("bool", _)) = SOME @{typ bool}
|
boehmes@40760
|
117 |
| mk_builtin_typ _ (Sym ("Int", _)) = SOME @{typ int}
|
boehmes@40760
|
118 |
| mk_builtin_typ _ (Sym ("int", _)) = SOME @{typ int} (*FIXME: delete*)
|
boehmes@36891
|
119 |
| mk_builtin_typ ctxt sym = chained_mk_builtin_typ (get_mk_builtins ctxt) sym
|
boehmes@36891
|
120 |
|
boehmes@36891
|
121 |
fun mk_builtin_num _ i @{typ int} = SOME (Numeral.mk_cnumber @{ctyp int} i)
|
boehmes@36891
|
122 |
| mk_builtin_num ctxt i T =
|
boehmes@36891
|
123 |
chained_mk_builtin_num ctxt (get_mk_builtins ctxt) i T
|
boehmes@36891
|
124 |
|
boehmes@40817
|
125 |
val mk_true = Thm.cterm_of @{theory} (@{const Not} $ @{const False})
|
boehmes@40817
|
126 |
val mk_false = Thm.cterm_of @{theory} @{const False}
|
boehmes@40817
|
127 |
val mk_not = Thm.capply (Thm.cterm_of @{theory} @{const Not})
|
boehmes@40817
|
128 |
val mk_implies = Thm.mk_binop (Thm.cterm_of @{theory} @{const HOL.implies})
|
boehmes@40817
|
129 |
val mk_iff = Thm.mk_binop (Thm.cterm_of @{theory} @{const HOL.eq (bool)})
|
boehmes@40817
|
130 |
val conj = Thm.cterm_of @{theory} @{const HOL.conj}
|
boehmes@40817
|
131 |
val disj = Thm.cterm_of @{theory} @{const HOL.disj}
|
boehmes@36891
|
132 |
|
boehmes@36891
|
133 |
fun mk_nary _ cu [] = cu
|
boehmes@36891
|
134 |
| mk_nary ct _ cts = uncurry (fold_rev (Thm.mk_binop ct)) (split_last cts)
|
boehmes@36891
|
135 |
|
boehmes@40910
|
136 |
val eq = U.mk_const_pat @{theory} @{const_name HOL.eq} U.destT1
|
boehmes@40910
|
137 |
fun mk_eq ct cu = Thm.mk_binop (U.instT' ct eq) ct cu
|
boehmes@36891
|
138 |
|
boehmes@40910
|
139 |
val if_term = U.mk_const_pat @{theory} @{const_name If} (U.destT1 o U.destT2)
|
boehmes@40910
|
140 |
fun mk_if cc ct cu = Thm.mk_binop (Thm.capply (U.instT' ct if_term) cc) ct cu
|
boehmes@36891
|
141 |
|
boehmes@40910
|
142 |
val nil_term = U.mk_const_pat @{theory} @{const_name Nil} U.destT1
|
boehmes@40910
|
143 |
val cons_term = U.mk_const_pat @{theory} @{const_name Cons} U.destT1
|
boehmes@36891
|
144 |
fun mk_list cT cts =
|
boehmes@40910
|
145 |
fold_rev (Thm.mk_binop (U.instT cT cons_term)) cts (U.instT cT nil_term)
|
boehmes@36891
|
146 |
|
boehmes@40929
|
147 |
val distinct = U.mk_const_pat @{theory} @{const_name distinct}
|
boehmes@40910
|
148 |
(U.destT1 o U.destT1)
|
boehmes@36891
|
149 |
fun mk_distinct [] = mk_true
|
boehmes@36891
|
150 |
| mk_distinct (cts as (ct :: _)) =
|
boehmes@40910
|
151 |
Thm.capply (U.instT' ct distinct) (mk_list (Thm.ctyp_of_term ct) cts)
|
boehmes@36891
|
152 |
|
boehmes@40910
|
153 |
val access = U.mk_const_pat @{theory} @{const_name fun_app}
|
boehmes@40910
|
154 |
(Thm.dest_ctyp o U.destT1)
|
boehmes@36891
|
155 |
fun mk_access array index =
|
boehmes@36891
|
156 |
let val cTs = Thm.dest_ctyp (Thm.ctyp_of_term array)
|
boehmes@40910
|
157 |
in Thm.mk_binop (U.instTs cTs access) array index end
|
boehmes@36891
|
158 |
|
boehmes@40910
|
159 |
val update = U.mk_const_pat @{theory} @{const_name fun_upd}
|
boehmes@40910
|
160 |
(Thm.dest_ctyp o U.destT1)
|
boehmes@36891
|
161 |
fun mk_update array index value =
|
boehmes@36891
|
162 |
let val cTs = Thm.dest_ctyp (Thm.ctyp_of_term array)
|
boehmes@40910
|
163 |
in Thm.capply (Thm.mk_binop (U.instTs cTs update) array index) value end
|
boehmes@36891
|
164 |
|
boehmes@40817
|
165 |
val mk_uminus = Thm.capply (Thm.cterm_of @{theory} @{const uminus (int)})
|
boehmes@40817
|
166 |
val mk_add = Thm.mk_binop (Thm.cterm_of @{theory} @{const plus (int)})
|
boehmes@40817
|
167 |
val mk_sub = Thm.mk_binop (Thm.cterm_of @{theory} @{const minus (int)})
|
boehmes@40817
|
168 |
val mk_mul = Thm.mk_binop (Thm.cterm_of @{theory} @{const times (int)})
|
boehmes@40817
|
169 |
val mk_div = Thm.mk_binop (Thm.cterm_of @{theory} @{const z3div})
|
boehmes@40817
|
170 |
val mk_mod = Thm.mk_binop (Thm.cterm_of @{theory} @{const z3mod})
|
boehmes@40817
|
171 |
val mk_lt = Thm.mk_binop (Thm.cterm_of @{theory} @{const less (int)})
|
boehmes@40817
|
172 |
val mk_le = Thm.mk_binop (Thm.cterm_of @{theory} @{const less_eq (int)})
|
boehmes@36891
|
173 |
|
boehmes@36891
|
174 |
fun mk_builtin_fun ctxt sym cts =
|
boehmes@36891
|
175 |
(case (sym, cts) of
|
boehmes@36891
|
176 |
(Sym ("true", _), []) => SOME mk_true
|
boehmes@36891
|
177 |
| (Sym ("false", _), []) => SOME mk_false
|
boehmes@36891
|
178 |
| (Sym ("not", _), [ct]) => SOME (mk_not ct)
|
boehmes@40817
|
179 |
| (Sym ("and", _), _) => SOME (mk_nary conj mk_true cts)
|
boehmes@40817
|
180 |
| (Sym ("or", _), _) => SOME (mk_nary disj mk_false cts)
|
boehmes@36891
|
181 |
| (Sym ("implies", _), [ct, cu]) => SOME (mk_implies ct cu)
|
boehmes@36891
|
182 |
| (Sym ("iff", _), [ct, cu]) => SOME (mk_iff ct cu)
|
boehmes@36891
|
183 |
| (Sym ("~", _), [ct, cu]) => SOME (mk_iff ct cu)
|
boehmes@36891
|
184 |
| (Sym ("xor", _), [ct, cu]) => SOME (mk_not (mk_iff ct cu))
|
boehmes@36891
|
185 |
| (Sym ("ite", _), [ct1, ct2, ct3]) => SOME (mk_if ct1 ct2 ct3)
|
boehmes@36891
|
186 |
| (Sym ("=", _), [ct, cu]) => SOME (mk_eq ct cu)
|
boehmes@36891
|
187 |
| (Sym ("distinct", _), _) => SOME (mk_distinct cts)
|
boehmes@36891
|
188 |
| (Sym ("select", _), [ca, ck]) => SOME (mk_access ca ck)
|
boehmes@36891
|
189 |
| (Sym ("store", _), [ca, ck, cv]) => SOME (mk_update ca ck cv)
|
boehmes@36891
|
190 |
| _ =>
|
boehmes@36891
|
191 |
(case (sym, try (#T o Thm.rep_cterm o hd) cts, cts) of
|
boehmes@36891
|
192 |
(Sym ("+", _), SOME @{typ int}, [ct, cu]) => SOME (mk_add ct cu)
|
boehmes@36891
|
193 |
| (Sym ("-", _), SOME @{typ int}, [ct]) => SOME (mk_uminus ct)
|
boehmes@36891
|
194 |
| (Sym ("-", _), SOME @{typ int}, [ct, cu]) => SOME (mk_sub ct cu)
|
boehmes@36891
|
195 |
| (Sym ("*", _), SOME @{typ int}, [ct, cu]) => SOME (mk_mul ct cu)
|
boehmes@37146
|
196 |
| (Sym ("div", _), SOME @{typ int}, [ct, cu]) => SOME (mk_div ct cu)
|
boehmes@37146
|
197 |
| (Sym ("mod", _), SOME @{typ int}, [ct, cu]) => SOME (mk_mod ct cu)
|
boehmes@36891
|
198 |
| (Sym ("<", _), SOME @{typ int}, [ct, cu]) => SOME (mk_lt ct cu)
|
boehmes@36891
|
199 |
| (Sym ("<=", _), SOME @{typ int}, [ct, cu]) => SOME (mk_le ct cu)
|
boehmes@36891
|
200 |
| (Sym (">", _), SOME @{typ int}, [ct, cu]) => SOME (mk_lt cu ct)
|
boehmes@36891
|
201 |
| (Sym (">=", _), SOME @{typ int}, [ct, cu]) => SOME (mk_le cu ct)
|
boehmes@36891
|
202 |
| _ => chained_mk_builtin_fun ctxt (get_mk_builtins ctxt) sym cts))
|
boehmes@36891
|
203 |
|
boehmes@36891
|
204 |
|
boehmes@36891
|
205 |
|
boehmes@41307
|
206 |
(* abstraction *)
|
boehmes@36891
|
207 |
|
boehmes@36891
|
208 |
fun is_builtin_theory_term ctxt t =
|
boehmes@41307
|
209 |
if B.is_builtin_num ctxt t then true
|
boehmes@41307
|
210 |
else
|
boehmes@41307
|
211 |
(case Term.strip_comb t of
|
boehmes@41307
|
212 |
(Const c, ts) => B.is_builtin_fun ctxt c ts
|
boehmes@41307
|
213 |
| _ => false)
|
boehmes@36891
|
214 |
|
boehmes@36891
|
215 |
end
|