boehmes@36890
|
1 |
(* Title: HOL/Tools/SMT/smtlib_interface.ML
|
boehmes@36890
|
2 |
Author: Sascha Boehme, TU Muenchen
|
boehmes@36890
|
3 |
|
boehmes@36890
|
4 |
Interface to SMT solvers based on the SMT-LIB format.
|
boehmes@36890
|
5 |
*)
|
boehmes@36890
|
6 |
|
boehmes@36890
|
7 |
signature SMTLIB_INTERFACE =
|
boehmes@36890
|
8 |
sig
|
boehmes@36891
|
9 |
type builtins = {
|
boehmes@36891
|
10 |
builtin_typ: typ -> string option,
|
boehmes@36891
|
11 |
builtin_num: typ -> int -> string option,
|
boehmes@36891
|
12 |
builtin_func: string * typ -> term list -> (string * term list) option,
|
boehmes@36891
|
13 |
builtin_pred: string * typ -> term list -> (string * term list) option,
|
boehmes@36891
|
14 |
is_builtin_pred: string -> typ -> bool }
|
boehmes@36891
|
15 |
val add_builtins: builtins -> Context.generic -> Context.generic
|
boehmes@36891
|
16 |
val add_logic: (term list -> string option) -> Context.generic ->
|
boehmes@36891
|
17 |
Context.generic
|
boehmes@36890
|
18 |
val interface: SMT_Solver.interface
|
boehmes@36890
|
19 |
end
|
boehmes@36890
|
20 |
|
boehmes@36890
|
21 |
structure SMTLIB_Interface: SMTLIB_INTERFACE =
|
boehmes@36890
|
22 |
struct
|
boehmes@36890
|
23 |
|
boehmes@36890
|
24 |
structure N = SMT_Normalize
|
boehmes@36890
|
25 |
structure T = SMT_Translate
|
boehmes@36890
|
26 |
|
boehmes@36890
|
27 |
|
boehmes@36890
|
28 |
|
boehmes@36890
|
29 |
(** facts about uninterpreted constants **)
|
boehmes@36890
|
30 |
|
boehmes@36890
|
31 |
infix 2 ??
|
boehmes@36890
|
32 |
fun (ex ?? f) thms = if exists (ex o Thm.prop_of) thms then f thms else thms
|
boehmes@36890
|
33 |
|
boehmes@36890
|
34 |
|
boehmes@36890
|
35 |
(* pairs *)
|
boehmes@36890
|
36 |
|
boehmes@36890
|
37 |
val pair_rules = [@{thm fst_conv}, @{thm snd_conv}, @{thm pair_collapse}]
|
boehmes@36890
|
38 |
|
haftmann@37678
|
39 |
val pair_type = (fn Type (@{type_name Product_Type.prod}, _) => true | _ => false)
|
boehmes@36890
|
40 |
val exists_pair_type = Term.exists_type (Term.exists_subtype pair_type)
|
boehmes@36890
|
41 |
|
boehmes@36890
|
42 |
val add_pair_rules = exists_pair_type ?? append pair_rules
|
boehmes@36890
|
43 |
|
boehmes@36890
|
44 |
|
boehmes@36890
|
45 |
(* function update *)
|
boehmes@36890
|
46 |
|
boehmes@36890
|
47 |
val fun_upd_rules = [@{thm fun_upd_same}, @{thm fun_upd_apply}]
|
boehmes@36890
|
48 |
|
boehmes@36890
|
49 |
val is_fun_upd = (fn Const (@{const_name fun_upd}, _) => true | _ => false)
|
boehmes@36890
|
50 |
val exists_fun_upd = Term.exists_subterm is_fun_upd
|
boehmes@36890
|
51 |
|
boehmes@36890
|
52 |
val add_fun_upd_rules = exists_fun_upd ?? append fun_upd_rules
|
boehmes@36890
|
53 |
|
boehmes@36890
|
54 |
|
boehmes@36890
|
55 |
(* abs/min/max *)
|
boehmes@36890
|
56 |
|
boehmes@36890
|
57 |
val exists_abs_min_max = Term.exists_subterm (fn
|
boehmes@36890
|
58 |
Const (@{const_name abs}, _) => true
|
boehmes@36890
|
59 |
| Const (@{const_name min}, _) => true
|
boehmes@36890
|
60 |
| Const (@{const_name max}, _) => true
|
boehmes@36890
|
61 |
| _ => false)
|
boehmes@36890
|
62 |
|
boehmes@36890
|
63 |
val unfold_abs_conv = Conv.rewr_conv @{thm abs_if[THEN eq_reflection]}
|
boehmes@36890
|
64 |
val unfold_min_conv = Conv.rewr_conv @{thm min_def[THEN eq_reflection]}
|
boehmes@36890
|
65 |
val unfold_max_conv = Conv.rewr_conv @{thm max_def[THEN eq_reflection]}
|
boehmes@36890
|
66 |
|
boehmes@36890
|
67 |
fun expand_conv cv = N.eta_expand_conv (K cv)
|
boehmes@36890
|
68 |
fun expand2_conv cv = N.eta_expand_conv (N.eta_expand_conv (K cv))
|
boehmes@36890
|
69 |
|
boehmes@36890
|
70 |
fun unfold_def_conv ctxt ct =
|
boehmes@36890
|
71 |
(case Thm.term_of ct of
|
boehmes@36890
|
72 |
Const (@{const_name abs}, _) $ _ => unfold_abs_conv
|
boehmes@36890
|
73 |
| Const (@{const_name abs}, _) => expand_conv unfold_abs_conv ctxt
|
boehmes@36890
|
74 |
| Const (@{const_name min}, _) $ _ $ _ => unfold_min_conv
|
boehmes@36890
|
75 |
| Const (@{const_name min}, _) $ _ => expand_conv unfold_min_conv ctxt
|
boehmes@36890
|
76 |
| Const (@{const_name min}, _) => expand2_conv unfold_min_conv ctxt
|
boehmes@36890
|
77 |
| Const (@{const_name max}, _) $ _ $ _ => unfold_max_conv
|
boehmes@36890
|
78 |
| Const (@{const_name max}, _) $ _ => expand_conv unfold_max_conv ctxt
|
boehmes@36890
|
79 |
| Const (@{const_name max}, _) => expand2_conv unfold_max_conv ctxt
|
boehmes@36890
|
80 |
| _ => Conv.all_conv) ct
|
boehmes@36890
|
81 |
|
boehmes@36890
|
82 |
fun unfold_abs_min_max_defs ctxt thm =
|
boehmes@36890
|
83 |
if exists_abs_min_max (Thm.prop_of thm)
|
wenzelm@36938
|
84 |
then Conv.fconv_rule (Conv.top_conv unfold_def_conv ctxt) thm
|
boehmes@36890
|
85 |
else thm
|
boehmes@36890
|
86 |
|
boehmes@36890
|
87 |
|
boehmes@36890
|
88 |
(* include additional facts *)
|
boehmes@36890
|
89 |
|
boehmes@36890
|
90 |
fun extra_norm thms ctxt =
|
boehmes@36890
|
91 |
thms
|
boehmes@36890
|
92 |
|> add_pair_rules
|
boehmes@36890
|
93 |
|> add_fun_upd_rules
|
boehmes@36890
|
94 |
|> map (unfold_abs_min_max_defs ctxt)
|
boehmes@36890
|
95 |
|> rpair ctxt
|
boehmes@36890
|
96 |
|
boehmes@36890
|
97 |
|
boehmes@36890
|
98 |
|
boehmes@36890
|
99 |
(** builtins **)
|
boehmes@36890
|
100 |
|
boehmes@36891
|
101 |
(* additional builtins *)
|
boehmes@36890
|
102 |
|
boehmes@36891
|
103 |
type builtins = {
|
boehmes@36891
|
104 |
builtin_typ: typ -> string option,
|
boehmes@36891
|
105 |
builtin_num: typ -> int -> string option,
|
boehmes@36891
|
106 |
builtin_func: string * typ -> term list -> (string * term list) option,
|
boehmes@36891
|
107 |
builtin_pred: string * typ -> term list -> (string * term list) option,
|
boehmes@36891
|
108 |
is_builtin_pred: string -> typ -> bool }
|
boehmes@36890
|
109 |
|
boehmes@36891
|
110 |
fun chained _ [] = NONE
|
boehmes@36891
|
111 |
| chained f (b :: bs) = (case f b of SOME y => SOME y | NONE => chained f bs)
|
boehmes@36890
|
112 |
|
boehmes@36891
|
113 |
fun chained' _ [] = false
|
boehmes@36891
|
114 |
| chained' f (b :: bs) = f b orelse chained' f bs
|
boehmes@36890
|
115 |
|
boehmes@36891
|
116 |
fun chained_builtin_typ bs T =
|
boehmes@36891
|
117 |
chained (fn {builtin_typ, ...} : builtins => builtin_typ T) bs
|
boehmes@36890
|
118 |
|
boehmes@36891
|
119 |
fun chained_builtin_num bs T i =
|
boehmes@36891
|
120 |
chained (fn {builtin_num, ...} : builtins => builtin_num T i) bs
|
boehmes@36890
|
121 |
|
boehmes@36891
|
122 |
fun chained_builtin_func bs c ts =
|
boehmes@36891
|
123 |
chained (fn {builtin_func, ...} : builtins => builtin_func c ts) bs
|
boehmes@36890
|
124 |
|
boehmes@36891
|
125 |
fun chained_builtin_pred bs c ts =
|
boehmes@36891
|
126 |
chained (fn {builtin_pred, ...} : builtins => builtin_pred c ts) bs
|
boehmes@36890
|
127 |
|
boehmes@36891
|
128 |
fun chained_is_builtin_pred bs n T =
|
boehmes@36891
|
129 |
chained' (fn {is_builtin_pred, ...} : builtins => is_builtin_pred n T) bs
|
boehmes@36890
|
130 |
|
boehmes@36891
|
131 |
fun fst_int_ord ((s1, _), (s2, _)) = int_ord (s1, s2)
|
boehmes@36890
|
132 |
|
boehmes@36891
|
133 |
structure Builtins = Generic_Data
|
boehmes@36891
|
134 |
(
|
boehmes@36891
|
135 |
type T = (int * builtins) list
|
boehmes@36891
|
136 |
val empty = []
|
boehmes@36891
|
137 |
val extend = I
|
boehmes@36891
|
138 |
fun merge (bs1, bs2) = OrdList.union fst_int_ord bs2 bs1
|
boehmes@36891
|
139 |
)
|
boehmes@36890
|
140 |
|
boehmes@36891
|
141 |
fun add_builtins bs = Builtins.map (OrdList.insert fst_int_ord (serial (), bs))
|
boehmes@36891
|
142 |
|
boehmes@36891
|
143 |
fun get_builtins ctxt = map snd (Builtins.get (Context.Proof ctxt))
|
boehmes@36891
|
144 |
|
boehmes@36891
|
145 |
|
boehmes@36891
|
146 |
(* basic builtins combined with additional builtins *)
|
boehmes@36891
|
147 |
|
boehmes@36891
|
148 |
fun builtin_typ _ @{typ int} = SOME "Int"
|
boehmes@36891
|
149 |
| builtin_typ ctxt T = chained_builtin_typ (get_builtins ctxt) T
|
boehmes@36891
|
150 |
|
boehmes@36891
|
151 |
fun builtin_num _ @{typ int} i = SOME (string_of_int i)
|
boehmes@36891
|
152 |
| builtin_num ctxt T i = chained_builtin_num (get_builtins ctxt) T i
|
boehmes@36891
|
153 |
|
boehmes@36891
|
154 |
fun if_int_type T n =
|
boehmes@36891
|
155 |
(case try Term.domain_type T of
|
boehmes@36891
|
156 |
SOME @{typ int} => SOME n
|
boehmes@36890
|
157 |
| _ => NONE)
|
boehmes@36890
|
158 |
|
boehmes@36890
|
159 |
fun conn @{const_name True} = SOME "true"
|
boehmes@36890
|
160 |
| conn @{const_name False} = SOME "false"
|
boehmes@36890
|
161 |
| conn @{const_name Not} = SOME "not"
|
boehmes@36890
|
162 |
| conn @{const_name "op &"} = SOME "and"
|
boehmes@36890
|
163 |
| conn @{const_name "op |"} = SOME "or"
|
boehmes@36890
|
164 |
| conn @{const_name "op -->"} = SOME "implies"
|
boehmes@36890
|
165 |
| conn @{const_name "op ="} = SOME "iff"
|
boehmes@36890
|
166 |
| conn @{const_name If} = SOME "if_then_else"
|
boehmes@36890
|
167 |
| conn _ = NONE
|
boehmes@36890
|
168 |
|
boehmes@36890
|
169 |
fun pred @{const_name distinct} _ = SOME "distinct"
|
boehmes@36890
|
170 |
| pred @{const_name "op ="} _ = SOME "="
|
boehmes@36890
|
171 |
| pred @{const_name term_eq} _ = SOME "="
|
boehmes@36891
|
172 |
| pred @{const_name less} T = if_int_type T "<"
|
boehmes@36891
|
173 |
| pred @{const_name less_eq} T = if_int_type T "<="
|
boehmes@36890
|
174 |
| pred _ _ = NONE
|
boehmes@36890
|
175 |
|
boehmes@36891
|
176 |
fun func @{const_name If} _ = SOME "ite"
|
boehmes@36891
|
177 |
| func @{const_name uminus} T = if_int_type T "~"
|
boehmes@36891
|
178 |
| func @{const_name plus} T = if_int_type T "+"
|
boehmes@36891
|
179 |
| func @{const_name minus} T = if_int_type T "-"
|
boehmes@36891
|
180 |
| func @{const_name times} T = if_int_type T "*"
|
boehmes@36891
|
181 |
| func _ _ = NONE
|
boehmes@36891
|
182 |
|
boehmes@36891
|
183 |
val is_propT = (fn @{typ prop} => true | _ => false)
|
boehmes@36891
|
184 |
fun is_connT T = Term.strip_type T |> (fn (Us, U) => forall is_propT (U :: Us))
|
boehmes@36891
|
185 |
fun is_predT T = is_propT (Term.body_type T)
|
boehmes@36890
|
186 |
|
boehmes@36890
|
187 |
fun is_builtin_conn (n, T) = is_connT T andalso is_some (conn n)
|
boehmes@36891
|
188 |
fun is_builtin_pred ctxt (n, T) = is_predT T andalso
|
boehmes@36891
|
189 |
(is_some (pred n T) orelse chained_is_builtin_pred (get_builtins ctxt) n T)
|
boehmes@36890
|
190 |
|
boehmes@36891
|
191 |
fun builtin_fun ctxt (c as (n, T)) ts =
|
boehmes@36891
|
192 |
let
|
boehmes@36891
|
193 |
val builtin_func' = chained_builtin_func (get_builtins ctxt)
|
boehmes@36891
|
194 |
val builtin_pred' = chained_builtin_pred (get_builtins ctxt)
|
boehmes@36891
|
195 |
in
|
boehmes@36891
|
196 |
if is_connT T then conn n |> Option.map (rpair ts)
|
boehmes@36891
|
197 |
else if is_predT T then
|
boehmes@36891
|
198 |
(case pred n T of SOME c' => SOME (c', ts) | NONE => builtin_pred' c ts)
|
boehmes@36891
|
199 |
else
|
boehmes@36891
|
200 |
(case func n T of SOME c' => SOME (c', ts) | NONE => builtin_func' c ts)
|
boehmes@36891
|
201 |
end
|
boehmes@36890
|
202 |
|
boehmes@36890
|
203 |
|
boehmes@36890
|
204 |
|
boehmes@36890
|
205 |
(** serialization **)
|
boehmes@36890
|
206 |
|
boehmes@36891
|
207 |
(* header *)
|
boehmes@36891
|
208 |
|
boehmes@36891
|
209 |
structure Logics = Generic_Data
|
boehmes@36891
|
210 |
(
|
boehmes@36891
|
211 |
type T = (int * (term list -> string option)) list
|
boehmes@36891
|
212 |
val empty = []
|
boehmes@36891
|
213 |
val extend = I
|
boehmes@36891
|
214 |
fun merge (bs1, bs2) = OrdList.union fst_int_ord bs2 bs1
|
boehmes@36891
|
215 |
)
|
boehmes@36891
|
216 |
|
boehmes@36891
|
217 |
fun add_logic l = Logics.map (OrdList.insert fst_int_ord (serial (), l))
|
boehmes@36891
|
218 |
|
boehmes@36891
|
219 |
fun choose_logic ctxt ts =
|
boehmes@36891
|
220 |
let
|
boehmes@36891
|
221 |
fun choose [] = "AUFLIA"
|
boehmes@36891
|
222 |
| choose ((_, l) :: ls) = (case l ts of SOME s => s | NONE => choose ls)
|
boehmes@36891
|
223 |
in [":logic " ^ choose (rev (Logics.get (Context.Proof ctxt)))] end
|
boehmes@36891
|
224 |
|
boehmes@36891
|
225 |
|
boehmes@36891
|
226 |
(* serialization *)
|
boehmes@36891
|
227 |
|
boehmes@36890
|
228 |
val add = Buffer.add
|
boehmes@36890
|
229 |
fun sep f = add " " #> f
|
boehmes@36890
|
230 |
fun enclose l r f = sep (add l #> f #> add r)
|
boehmes@36890
|
231 |
val par = enclose "(" ")"
|
boehmes@36890
|
232 |
fun app n f = (fn [] => sep (add n) | xs => par (add n #> fold f xs))
|
boehmes@36890
|
233 |
fun line f = f #> add "\n"
|
boehmes@36890
|
234 |
|
boehmes@36890
|
235 |
fun var i = add "?v" #> add (string_of_int i)
|
boehmes@36890
|
236 |
|
boehmes@36890
|
237 |
fun sterm l (T.SVar i) = sep (var (l - i - 1))
|
boehmes@36890
|
238 |
| sterm l (T.SApp (n, ts)) = app n (sterm l) ts
|
boehmes@36890
|
239 |
| sterm _ (T.SLet _) = raise Fail "SMT-LIB: unsupported let expression"
|
boehmes@36890
|
240 |
| sterm l (T.SQua (q, ss, ps, t)) =
|
boehmes@36890
|
241 |
let
|
boehmes@36890
|
242 |
val quant = add o (fn T.SForall => "forall" | T.SExists => "exists")
|
boehmes@36890
|
243 |
val vs = map_index (apfst (Integer.add l)) ss
|
boehmes@36890
|
244 |
fun var_decl (i, s) = par (var i #> sep (add s))
|
boehmes@36890
|
245 |
val sub = sterm (l + length ss)
|
boehmes@36890
|
246 |
fun pat kind ts = sep (add kind #> enclose "{" " }" (fold sub ts))
|
boehmes@36890
|
247 |
fun pats (T.SPat ts) = pat ":pat" ts
|
boehmes@36890
|
248 |
| pats (T.SNoPat ts) = pat ":nopat" ts
|
boehmes@36890
|
249 |
in par (quant q #> fold var_decl vs #> sub t #> fold pats ps) end
|
boehmes@36890
|
250 |
|
boehmes@37150
|
251 |
fun ssort sorts = sort fast_string_ord sorts
|
boehmes@37150
|
252 |
fun fsort funcs = sort (prod_ord fast_string_ord (K EQUAL)) funcs
|
boehmes@37150
|
253 |
|
boehmes@36891
|
254 |
fun serialize comments {header, sorts, funcs} ts =
|
boehmes@36890
|
255 |
Buffer.empty
|
boehmes@36890
|
256 |
|> line (add "(benchmark Isabelle")
|
boehmes@36890
|
257 |
|> line (add ":status unknown")
|
boehmes@36891
|
258 |
|> fold (line o add) header
|
boehmes@36890
|
259 |
|> length sorts > 0 ?
|
boehmes@37150
|
260 |
line (add ":extrasorts" #> par (fold (sep o add) (ssort sorts)))
|
boehmes@36890
|
261 |
|> length funcs > 0 ? (
|
boehmes@36890
|
262 |
line (add ":extrafuns" #> add " (") #>
|
boehmes@36890
|
263 |
fold (fn (f, (ss, s)) =>
|
boehmes@37150
|
264 |
line (sep (app f (sep o add) (ss @ [s])))) (fsort funcs) #>
|
boehmes@36890
|
265 |
line (add ")"))
|
boehmes@36890
|
266 |
|> fold (fn t => line (add ":assumption" #> sterm 0 t)) ts
|
boehmes@36890
|
267 |
|> line (add ":formula true)")
|
boehmes@36890
|
268 |
|> fold (fn str => line (add "; " #> add str)) comments
|
boehmes@36890
|
269 |
|> Buffer.content
|
boehmes@36890
|
270 |
|
boehmes@36890
|
271 |
|
boehmes@36890
|
272 |
|
boehmes@36891
|
273 |
(** interfaces **)
|
boehmes@36890
|
274 |
|
boehmes@36890
|
275 |
val interface = {
|
boehmes@36890
|
276 |
extra_norm = extra_norm,
|
boehmes@36890
|
277 |
translate = {
|
boehmes@36890
|
278 |
prefixes = {
|
boehmes@36890
|
279 |
sort_prefix = "S",
|
boehmes@36890
|
280 |
func_prefix = "f"},
|
boehmes@36891
|
281 |
header = choose_logic,
|
boehmes@36890
|
282 |
strict = SOME {
|
boehmes@36890
|
283 |
is_builtin_conn = is_builtin_conn,
|
boehmes@36890
|
284 |
is_builtin_pred = is_builtin_pred,
|
boehmes@36890
|
285 |
is_builtin_distinct = true},
|
boehmes@36890
|
286 |
builtins = {
|
boehmes@36890
|
287 |
builtin_typ = builtin_typ,
|
boehmes@36890
|
288 |
builtin_num = builtin_num,
|
boehmes@36890
|
289 |
builtin_fun = builtin_fun},
|
boehmes@36890
|
290 |
serialize = serialize}}
|
boehmes@36890
|
291 |
|
boehmes@36890
|
292 |
end
|