boehmes@32618
|
1 |
(* Title: HOL/SMT/Tools/smt_translate.ML
|
boehmes@32618
|
2 |
Author: Sascha Boehme, TU Muenchen
|
boehmes@32618
|
3 |
|
boehmes@32618
|
4 |
Translate theorems into an SMT intermediate format and serialize them,
|
boehmes@32618
|
5 |
depending on an SMT interface.
|
boehmes@32618
|
6 |
*)
|
boehmes@32618
|
7 |
|
boehmes@32618
|
8 |
signature SMT_TRANSLATE =
|
boehmes@32618
|
9 |
sig
|
boehmes@32618
|
10 |
(* intermediate term structure *)
|
boehmes@32618
|
11 |
datatype sym =
|
boehmes@32618
|
12 |
SConst of string * typ |
|
boehmes@32618
|
13 |
SFree of string * typ |
|
boehmes@32618
|
14 |
SNum of int * typ
|
boehmes@32618
|
15 |
datatype squant = SForall | SExists
|
boehmes@32618
|
16 |
datatype 'a spattern = SPat of 'a list | SNoPat of 'a list
|
boehmes@32618
|
17 |
datatype ('a, 'b) sterm =
|
boehmes@32618
|
18 |
SVar of int |
|
boehmes@32618
|
19 |
SApp of 'a * ('a, 'b) sterm list |
|
boehmes@32618
|
20 |
SLet of (string * 'b) * ('a, 'b) sterm * ('a, 'b) sterm |
|
boehmes@32618
|
21 |
SQuant of squant * (string * 'b) list * ('a, 'b) sterm spattern list *
|
boehmes@32618
|
22 |
('a, 'b) sterm
|
boehmes@32618
|
23 |
|
boehmes@32618
|
24 |
(* table for built-in symbols *)
|
boehmes@32618
|
25 |
type builtin_fun = typ -> (sym, typ) sterm list ->
|
boehmes@32618
|
26 |
(string * (sym, typ) sterm list) option
|
boehmes@32618
|
27 |
type builtin_table = (typ * builtin_fun) list Symtab.table
|
boehmes@32618
|
28 |
val builtin_make: (term * string) list -> builtin_table
|
boehmes@32618
|
29 |
val builtin_add: term * builtin_fun -> builtin_table -> builtin_table
|
boehmes@32618
|
30 |
val builtin_lookup: builtin_table -> theory -> string * typ ->
|
boehmes@32618
|
31 |
(sym, typ) sterm list -> (string * (sym, typ) sterm list) option
|
boehmes@32618
|
32 |
val bv_rotate: (int -> string) -> builtin_fun
|
boehmes@32618
|
33 |
val bv_extend: (int -> string) -> builtin_fun
|
boehmes@32618
|
34 |
val bv_extract: (int -> int -> string) -> builtin_fun
|
boehmes@32618
|
35 |
|
boehmes@32618
|
36 |
(* configuration options *)
|
boehmes@32618
|
37 |
datatype prefixes = Prefixes of {
|
boehmes@32618
|
38 |
var_prefix: string,
|
boehmes@32618
|
39 |
typ_prefix: string,
|
boehmes@32618
|
40 |
fun_prefix: string,
|
boehmes@32618
|
41 |
pred_prefix: string }
|
boehmes@32618
|
42 |
datatype markers = Markers of {
|
boehmes@32618
|
43 |
term_marker: string,
|
boehmes@32618
|
44 |
formula_marker: string }
|
boehmes@32618
|
45 |
datatype builtins = Builtins of {
|
boehmes@32618
|
46 |
builtin_typ: typ -> string option,
|
boehmes@32618
|
47 |
builtin_num: int * typ -> string option,
|
boehmes@32618
|
48 |
builtin_fun: bool -> builtin_table }
|
boehmes@32618
|
49 |
datatype sign = Sign of {
|
boehmes@32618
|
50 |
typs: string list,
|
boehmes@32618
|
51 |
funs: (string * (string list * string)) list,
|
boehmes@32618
|
52 |
preds: (string * string list) list }
|
boehmes@32618
|
53 |
datatype config = Config of {
|
boehmes@32618
|
54 |
strict: bool,
|
boehmes@32618
|
55 |
prefixes: prefixes,
|
boehmes@32618
|
56 |
markers: markers,
|
boehmes@32618
|
57 |
builtins: builtins,
|
boehmes@32618
|
58 |
serialize: sign -> (string, string) sterm list -> TextIO.outstream -> unit}
|
boehmes@32618
|
59 |
datatype recon = Recon of {typs: typ Symtab.table, terms: term Symtab.table}
|
boehmes@32618
|
60 |
|
boehmes@32618
|
61 |
val translate: config -> theory -> thm list -> TextIO.outstream ->
|
boehmes@32618
|
62 |
recon * thm list
|
boehmes@32618
|
63 |
|
boehmes@32618
|
64 |
val dest_binT: typ -> int
|
boehmes@32618
|
65 |
val dest_funT: int -> typ -> typ list * typ
|
boehmes@32618
|
66 |
end
|
boehmes@32618
|
67 |
|
boehmes@32618
|
68 |
structure SMT_Translate: SMT_TRANSLATE =
|
boehmes@32618
|
69 |
struct
|
boehmes@32618
|
70 |
|
boehmes@32618
|
71 |
(* Intermediate term structure *)
|
boehmes@32618
|
72 |
|
boehmes@32618
|
73 |
datatype sym =
|
boehmes@32618
|
74 |
SConst of string * typ |
|
boehmes@32618
|
75 |
SFree of string * typ |
|
boehmes@32618
|
76 |
SNum of int * typ
|
boehmes@32618
|
77 |
datatype squant = SForall | SExists
|
boehmes@32618
|
78 |
datatype 'a spattern = SPat of 'a list | SNoPat of 'a list
|
boehmes@32618
|
79 |
datatype ('a, 'b) sterm =
|
boehmes@32618
|
80 |
SVar of int |
|
boehmes@32618
|
81 |
SApp of 'a * ('a, 'b) sterm list |
|
boehmes@32618
|
82 |
SLet of (string * 'b) * ('a, 'b) sterm * ('a, 'b) sterm |
|
boehmes@32618
|
83 |
SQuant of squant * (string * 'b) list * ('a, 'b) sterm spattern list *
|
boehmes@32618
|
84 |
('a, 'b) sterm
|
boehmes@32618
|
85 |
|
boehmes@32618
|
86 |
fun app c ts = SApp (c, ts)
|
boehmes@32618
|
87 |
|
boehmes@32618
|
88 |
fun map_pat f (SPat ps) = SPat (map f ps)
|
boehmes@32618
|
89 |
| map_pat f (SNoPat ps) = SNoPat (map f ps)
|
boehmes@32618
|
90 |
|
boehmes@32618
|
91 |
fun fold_map_pat f (SPat ps) = fold_map f ps #>> SPat
|
boehmes@32618
|
92 |
| fold_map_pat f (SNoPat ps) = fold_map f ps #>> SNoPat
|
boehmes@32618
|
93 |
|
boehmes@32618
|
94 |
val make_sconst = SConst o Term.dest_Const
|
boehmes@32618
|
95 |
|
boehmes@32618
|
96 |
|
boehmes@32618
|
97 |
(* General type destructors. *)
|
boehmes@32618
|
98 |
|
boehmes@32618
|
99 |
fun dest_binT T =
|
boehmes@32618
|
100 |
(case T of
|
boehmes@32618
|
101 |
Type (@{type_name "Numeral_Type.num0"}, _) => 0
|
boehmes@32618
|
102 |
| Type (@{type_name "Numeral_Type.num1"}, _) => 1
|
boehmes@32618
|
103 |
| Type (@{type_name "Numeral_Type.bit0"}, [T]) => 2 * dest_binT T
|
boehmes@32618
|
104 |
| Type (@{type_name "Numeral_Type.bit1"}, [T]) => 1 + 2 * dest_binT T
|
boehmes@32618
|
105 |
| _ => raise TYPE ("dest_binT", [T], []))
|
boehmes@32618
|
106 |
|
boehmes@32618
|
107 |
val dest_wordT = (fn
|
boehmes@32618
|
108 |
Type (@{type_name "word"}, [T]) => dest_binT T
|
boehmes@32618
|
109 |
| T => raise TYPE ("dest_wordT", [T], []))
|
boehmes@32618
|
110 |
|
boehmes@32618
|
111 |
val dest_funT =
|
boehmes@32618
|
112 |
let
|
boehmes@32618
|
113 |
fun dest Ts 0 T = (rev Ts, T)
|
boehmes@32618
|
114 |
| dest Ts i (Type ("fun", [T, U])) = dest (T::Ts) (i-1) U
|
boehmes@32618
|
115 |
| dest _ _ T = raise TYPE ("dest_funT", [T], [])
|
boehmes@32618
|
116 |
in dest [] end
|
boehmes@32618
|
117 |
|
boehmes@32618
|
118 |
|
boehmes@32618
|
119 |
(* Table for built-in symbols *)
|
boehmes@32618
|
120 |
|
boehmes@32618
|
121 |
type builtin_fun = typ -> (sym, typ) sterm list ->
|
boehmes@32618
|
122 |
(string * (sym, typ) sterm list) option
|
boehmes@32618
|
123 |
type builtin_table = (typ * builtin_fun) list Symtab.table
|
boehmes@32618
|
124 |
|
boehmes@32618
|
125 |
fun builtin_make entries =
|
boehmes@32618
|
126 |
let
|
boehmes@32618
|
127 |
fun dest (t, bn) =
|
boehmes@32618
|
128 |
let val (n, T) = Term.dest_Const t
|
boehmes@32618
|
129 |
in (n, (Logic.varifyT T, K (SOME o pair bn))) end
|
boehmes@32618
|
130 |
in Symtab.make (AList.group (op =) (map dest entries)) end
|
boehmes@32618
|
131 |
|
boehmes@32618
|
132 |
fun builtin_add (t, f) tab =
|
boehmes@32618
|
133 |
let val (n, T) = apsnd Logic.varifyT (Term.dest_Const t)
|
boehmes@32618
|
134 |
in Symtab.map_default (n, []) (AList.update (op =) (T, f)) tab end
|
boehmes@32618
|
135 |
|
boehmes@32618
|
136 |
fun builtin_lookup tab thy (n, T) ts =
|
boehmes@32618
|
137 |
AList.lookup (Sign.typ_instance thy) (Symtab.lookup_list tab n) T
|
boehmes@32618
|
138 |
|> (fn SOME f => f T ts | NONE => NONE)
|
boehmes@32618
|
139 |
|
boehmes@32618
|
140 |
local
|
boehmes@32618
|
141 |
val dest_nat = (fn
|
boehmes@32618
|
142 |
SApp (SConst (@{const_name nat}, _), [SApp (SNum (i, _), _)]) => SOME i
|
boehmes@32618
|
143 |
| _ => NONE)
|
boehmes@32618
|
144 |
in
|
boehmes@32618
|
145 |
fun bv_rotate mk_name T ts =
|
boehmes@32618
|
146 |
dest_nat (hd ts) |> Option.map (fn i => (mk_name i, tl ts))
|
boehmes@32618
|
147 |
|
boehmes@32618
|
148 |
fun bv_extend mk_name T ts =
|
boehmes@32618
|
149 |
(case (try dest_wordT (domain_type T), try dest_wordT (range_type T)) of
|
boehmes@32618
|
150 |
(SOME i, SOME j) => if j - i >= 0 then SOME (mk_name (j - i), ts) else NONE
|
boehmes@32618
|
151 |
| _ => NONE)
|
boehmes@32618
|
152 |
|
boehmes@32618
|
153 |
fun bv_extract mk_name T ts =
|
boehmes@32618
|
154 |
(case (try dest_wordT (body_type T), dest_nat (hd ts)) of
|
boehmes@32618
|
155 |
(SOME i, SOME lb) => SOME (mk_name (i + lb - 1) lb, tl ts)
|
boehmes@32618
|
156 |
| _ => NONE)
|
boehmes@32618
|
157 |
end
|
boehmes@32618
|
158 |
|
boehmes@32618
|
159 |
|
boehmes@32618
|
160 |
(* Configuration options *)
|
boehmes@32618
|
161 |
|
boehmes@32618
|
162 |
datatype prefixes = Prefixes of {
|
boehmes@32618
|
163 |
var_prefix: string,
|
boehmes@32618
|
164 |
typ_prefix: string,
|
boehmes@32618
|
165 |
fun_prefix: string,
|
boehmes@32618
|
166 |
pred_prefix: string }
|
boehmes@32618
|
167 |
datatype markers = Markers of {
|
boehmes@32618
|
168 |
term_marker: string,
|
boehmes@32618
|
169 |
formula_marker: string }
|
boehmes@32618
|
170 |
datatype builtins = Builtins of {
|
boehmes@32618
|
171 |
builtin_typ: typ -> string option,
|
boehmes@32618
|
172 |
builtin_num: int * typ -> string option,
|
boehmes@32618
|
173 |
builtin_fun: bool -> builtin_table }
|
boehmes@32618
|
174 |
datatype sign = Sign of {
|
boehmes@32618
|
175 |
typs: string list,
|
boehmes@32618
|
176 |
funs: (string * (string list * string)) list,
|
boehmes@32618
|
177 |
preds: (string * string list) list }
|
boehmes@32618
|
178 |
datatype config = Config of {
|
boehmes@32618
|
179 |
strict: bool,
|
boehmes@32618
|
180 |
prefixes: prefixes,
|
boehmes@32618
|
181 |
markers: markers,
|
boehmes@32618
|
182 |
builtins: builtins,
|
boehmes@32618
|
183 |
serialize: sign -> (string, string) sterm list -> TextIO.outstream -> unit}
|
boehmes@32618
|
184 |
datatype recon = Recon of {typs: typ Symtab.table, terms: term Symtab.table}
|
boehmes@32618
|
185 |
|
boehmes@32618
|
186 |
|
boehmes@32618
|
187 |
(* Translate Isabelle/HOL terms into SMT intermediate terms.
|
boehmes@32618
|
188 |
We assume that lambda-lifting has been performed before, i.e., lambda
|
boehmes@32618
|
189 |
abstractions occur only at quantifiers and let expressions.
|
boehmes@32618
|
190 |
*)
|
boehmes@32618
|
191 |
local
|
boehmes@32618
|
192 |
val quantifier = (fn
|
boehmes@32618
|
193 |
@{const_name All} => SOME SForall
|
boehmes@32618
|
194 |
| @{const_name Ex} => SOME SExists
|
boehmes@32618
|
195 |
| _ => NONE)
|
boehmes@32618
|
196 |
|
boehmes@32618
|
197 |
fun group_quant qname vs (t as Const (q, _) $ Abs (n, T, u)) =
|
boehmes@32618
|
198 |
if q = qname then group_quant qname ((n, T) :: vs) u else (vs, t)
|
boehmes@32618
|
199 |
| group_quant qname vs t = (vs, t)
|
boehmes@32618
|
200 |
|
boehmes@32618
|
201 |
fun dest_trigger (@{term trigger} $ tl $ t) = (HOLogic.dest_list tl, t)
|
boehmes@32618
|
202 |
| dest_trigger t = ([], t)
|
boehmes@32618
|
203 |
|
boehmes@32618
|
204 |
fun pat f ps (Const (@{const_name pat}, _) $ p) = SPat (rev (f p :: ps))
|
boehmes@32618
|
205 |
| pat f ps (Const (@{const_name nopat}, _) $ p) = SNoPat (rev (f p :: ps))
|
boehmes@32618
|
206 |
| pat f ps (Const (@{const_name andpat}, _) $ p $ t) = pat f (f p :: ps) t
|
boehmes@32618
|
207 |
| pat _ _ t = raise TERM ("pat", [t])
|
boehmes@32618
|
208 |
|
boehmes@32618
|
209 |
fun trans Ts t =
|
boehmes@32618
|
210 |
(case Term.strip_comb t of
|
boehmes@32618
|
211 |
(t1 as Const (qn, qT), [t2 as Abs (n, T, t3)]) =>
|
boehmes@32618
|
212 |
(case quantifier qn of
|
boehmes@32618
|
213 |
SOME q =>
|
boehmes@32618
|
214 |
let
|
boehmes@32618
|
215 |
val (vs, u) = group_quant qn [(n, T)] t3
|
boehmes@32618
|
216 |
val Us = map snd vs @ Ts
|
boehmes@32618
|
217 |
val (ps, b) = dest_trigger u
|
boehmes@32618
|
218 |
in SQuant (q, rev vs, map (pat (trans Us) []) ps, trans Us b) end
|
boehmes@32618
|
219 |
| NONE => raise TERM ("intermediate", [t]))
|
boehmes@32618
|
220 |
| (Const (@{const_name Let}, _), [t1, Abs (n, T, t2)]) =>
|
boehmes@32618
|
221 |
SLet ((n, T), trans Ts t1, trans (T :: Ts) t2)
|
boehmes@32618
|
222 |
| (Const (c as (@{const_name distinct}, _)), [t1]) =>
|
boehmes@32618
|
223 |
(* this is not type-correct, but will be corrected at a later stage *)
|
boehmes@32618
|
224 |
SApp (SConst c, map (trans Ts) (HOLogic.dest_list t1))
|
boehmes@32618
|
225 |
| (Const c, ts) =>
|
boehmes@32618
|
226 |
(case try HOLogic.dest_number t of
|
boehmes@32618
|
227 |
SOME (T, i) => SApp (SNum (i, T), [])
|
boehmes@32618
|
228 |
| NONE => SApp (SConst c, map (trans Ts) ts))
|
boehmes@32618
|
229 |
| (Free c, ts) => SApp (SFree c, map (trans Ts) ts)
|
boehmes@32618
|
230 |
| (Bound i, []) => SVar i
|
boehmes@32618
|
231 |
| _ => raise TERM ("intermediate", [t]))
|
boehmes@32618
|
232 |
in
|
boehmes@32618
|
233 |
fun intermediate ts = map (trans [] o HOLogic.dest_Trueprop) ts
|
boehmes@32618
|
234 |
end
|
boehmes@32618
|
235 |
|
boehmes@32618
|
236 |
|
boehmes@32618
|
237 |
(* Separate formulas from terms by adding special marker symbols ("term",
|
boehmes@32618
|
238 |
"formula"). Atoms "P" whose head symbol also occurs as function symbol are
|
boehmes@32618
|
239 |
rewritten to "term P = term True". Connectives and built-in predicates
|
boehmes@32618
|
240 |
occurring at term level are replaced by new constants, and theorems
|
boehmes@32618
|
241 |
specifying their meaning are added.
|
boehmes@32618
|
242 |
*)
|
boehmes@32618
|
243 |
local
|
boehmes@32618
|
244 |
(** Add the marker symbols "term" and "formulas" to separate formulas and
|
boehmes@32618
|
245 |
terms. **)
|
boehmes@32618
|
246 |
|
boehmes@32618
|
247 |
val connectives = map make_sconst [@{term True}, @{term False},
|
boehmes@32618
|
248 |
@{term Not}, @{term "op &"}, @{term "op |"}, @{term "op -->"},
|
boehmes@32618
|
249 |
@{term "op = :: bool => _"}]
|
boehmes@32618
|
250 |
|
boehmes@32618
|
251 |
fun note false c (ps, fs) = (insert (op =) c ps, fs)
|
boehmes@32618
|
252 |
| note true c (ps, fs) = (ps, insert (op =) c fs)
|
boehmes@32618
|
253 |
|
boehmes@32618
|
254 |
val term_marker = SConst (@{const_name term}, Term.dummyT)
|
boehmes@32618
|
255 |
val formula_marker = SConst (@{const_name formula}, Term.dummyT)
|
boehmes@32618
|
256 |
fun mark f true t = f true t #>> app term_marker o single
|
boehmes@32618
|
257 |
| mark f false t = f false t #>> app formula_marker o single
|
boehmes@32618
|
258 |
fun mark' f false t = f true t #>> app term_marker o single
|
boehmes@32618
|
259 |
| mark' f true t = f true t
|
boehmes@32618
|
260 |
val mark_term = app term_marker o single
|
boehmes@32618
|
261 |
fun lift_term_marker c ts =
|
boehmes@32618
|
262 |
let val rem = (fn SApp (SConst (@{const_name term}, _), [t]) => t | t => t)
|
boehmes@32618
|
263 |
in mark_term (SApp (c, map rem ts)) end
|
boehmes@32618
|
264 |
fun is_term (SApp (SConst (@{const_name term}, _), _)) = true
|
boehmes@32618
|
265 |
| is_term _ = false
|
boehmes@32618
|
266 |
|
boehmes@32618
|
267 |
fun either x = (fn y as SOME _ => y | _ => x)
|
boehmes@32618
|
268 |
fun get_loc loc i t =
|
boehmes@32618
|
269 |
(case t of
|
boehmes@32618
|
270 |
SVar j => if i = j then SOME loc else NONE
|
boehmes@32618
|
271 |
| SApp (SConst (@{const_name term}, _), us) => get_locs true i us
|
boehmes@32618
|
272 |
| SApp (SConst (@{const_name formula}, _), us) => get_locs false i us
|
boehmes@32618
|
273 |
| SApp (_, us) => get_locs loc i us
|
boehmes@32618
|
274 |
| SLet (_, u1, u2) => either (get_loc true i u1) (get_loc loc (i+1) u2)
|
boehmes@32618
|
275 |
| SQuant (_, vs, _, u) => get_loc loc (i + length vs) u)
|
boehmes@32618
|
276 |
and get_locs loc i ts = fold (either o get_loc loc i) ts NONE
|
boehmes@32618
|
277 |
|
boehmes@32618
|
278 |
fun sep loc t =
|
boehmes@32618
|
279 |
(case t of
|
boehmes@32618
|
280 |
SVar i => pair t
|
boehmes@32618
|
281 |
| SApp (c as SConst (@{const_name If}, _), u :: us) =>
|
boehmes@32618
|
282 |
mark sep false u ##>> fold_map (sep loc) us #>> app c o (op ::)
|
boehmes@32618
|
283 |
| SApp (c, us) =>
|
boehmes@32618
|
284 |
if not loc andalso member (op =) connectives c
|
boehmes@32618
|
285 |
then fold_map (sep loc) us #>> app c
|
boehmes@32618
|
286 |
else note loc c #> fold_map (mark' sep loc) us #>> app c
|
boehmes@32618
|
287 |
| SLet (v, u1, u2) =>
|
boehmes@32618
|
288 |
sep loc u2 #-> (fn u2' =>
|
boehmes@32618
|
289 |
mark sep (the (get_loc loc 0 u2')) u1 #>> (fn u1' =>
|
boehmes@32618
|
290 |
SLet (v, u1', u2')))
|
boehmes@32618
|
291 |
| SQuant (q, vs, ps, u) =>
|
boehmes@32618
|
292 |
fold_map (fold_map_pat (mark sep true)) ps ##>>
|
boehmes@32618
|
293 |
sep loc u #>> (fn (ps', u') =>
|
boehmes@32618
|
294 |
SQuant (q, vs, ps', u')))
|
boehmes@32618
|
295 |
|
boehmes@32618
|
296 |
(** Rewrite atoms. **)
|
boehmes@32618
|
297 |
|
boehmes@32618
|
298 |
val unterm_rule = @{lemma "term x == x" by (simp add: term_def)}
|
boehmes@32618
|
299 |
val unterm_conv = More_Conv.top_sweep_conv (K (Conv.rewr_conv unterm_rule))
|
boehmes@32618
|
300 |
|
boehmes@32618
|
301 |
val dest_word_type = (fn Type (@{type_name word}, [T]) => T | T => T)
|
boehmes@32618
|
302 |
fun instantiate [] _ = I
|
boehmes@32618
|
303 |
| instantiate (v :: _) T =
|
boehmes@32618
|
304 |
Term.subst_TVars [(v, dest_word_type (Term.domain_type T))]
|
boehmes@32618
|
305 |
|
boehmes@32618
|
306 |
fun dest_alls (Const (@{const_name All}, _) $ Abs (_, _, t)) = dest_alls t
|
boehmes@32618
|
307 |
| dest_alls t = t
|
boehmes@32618
|
308 |
val dest_iff = (fn (Const (@{const_name iff}, _) $ t $ _ ) => t | t => t)
|
boehmes@32618
|
309 |
val dest_eq = (fn (Const (@{const_name "op ="}, _) $ t $ _ ) => t | t => t)
|
boehmes@32618
|
310 |
val dest_not = (fn (@{term Not} $ t) => t | t => t)
|
boehmes@32618
|
311 |
val head_of = HOLogic.dest_Trueprop #> dest_alls #> dest_iff #> dest_not #>
|
boehmes@32618
|
312 |
dest_eq #> Term.head_of
|
boehmes@32618
|
313 |
|
boehmes@32618
|
314 |
fun prepare ctxt thm =
|
boehmes@32618
|
315 |
let
|
boehmes@32618
|
316 |
val rule = Conv.fconv_rule (unterm_conv ctxt) thm
|
boehmes@32618
|
317 |
val prop = Thm.prop_of thm
|
boehmes@32618
|
318 |
val inst = instantiate (Term.add_tvar_names prop [])
|
boehmes@32618
|
319 |
fun inst_for T = (singleton intermediate (inst T prop), rule)
|
boehmes@32618
|
320 |
in (make_sconst (head_of (Thm.prop_of rule)), inst_for) end
|
boehmes@32618
|
321 |
|
boehmes@32618
|
322 |
val logicals = map (prepare @{context})
|
boehmes@32618
|
323 |
@{lemma
|
boehmes@32618
|
324 |
"~ holds False"
|
boehmes@32618
|
325 |
"ALL p. holds (~ p) iff (~ holds p)"
|
boehmes@32618
|
326 |
"ALL p q. holds (p & q) iff (holds p & holds q)"
|
boehmes@32618
|
327 |
"ALL p q. holds (p | q) iff (holds p | holds q)"
|
boehmes@32618
|
328 |
"ALL p q. holds (p --> q) iff (holds p --> holds q)"
|
boehmes@32618
|
329 |
"ALL p q. holds (p iff q) iff (holds p iff holds q)"
|
boehmes@32618
|
330 |
"ALL p q. holds (p = q) iff (p = q)"
|
boehmes@32618
|
331 |
"ALL (a::int) b. holds (a < b) iff (a < b)"
|
boehmes@32618
|
332 |
"ALL (a::int) b. holds (a <= b) iff (a <= b)"
|
boehmes@32618
|
333 |
"ALL (a::real) b. holds (a < b) iff (a < b)"
|
boehmes@32618
|
334 |
"ALL (a::real) b. holds (a <= b) iff (a <= b)"
|
boehmes@32618
|
335 |
"ALL (a::'a::len0 word) b. holds (a < b) iff (a < b)"
|
boehmes@32618
|
336 |
"ALL (a::'a::len0 word) b. holds (a <= b) iff (a <= b)"
|
boehmes@32618
|
337 |
"ALL a b. holds (a <s b) iff (a <s b)"
|
boehmes@32618
|
338 |
"ALL a b. holds (a <=s b) iff (a <=s b)"
|
boehmes@32618
|
339 |
by (simp_all add: term_def iff_def)}
|
boehmes@32618
|
340 |
|
boehmes@32618
|
341 |
fun is_instance thy (SConst (n, T), SConst (m, U)) =
|
boehmes@32618
|
342 |
(n = m) andalso Sign.typ_instance thy (T, U)
|
boehmes@32618
|
343 |
| is_instance _ _ = false
|
boehmes@32618
|
344 |
|
boehmes@32618
|
345 |
fun lookup_logical thy (c as SConst (_, T)) =
|
boehmes@32618
|
346 |
AList.lookup (is_instance thy) logicals c
|
boehmes@32618
|
347 |
|> Option.map (fn inst_for => inst_for T)
|
boehmes@32618
|
348 |
| lookup_logical _ _ = NONE
|
boehmes@32618
|
349 |
|
boehmes@32618
|
350 |
val s_eq = make_sconst @{term "op = :: bool => _"}
|
boehmes@32618
|
351 |
val s_True = mark_term (SApp (make_sconst @{term True}, []))
|
boehmes@32618
|
352 |
fun holds (SApp (c, ts)) = SApp (s_eq, [lift_term_marker c ts, s_True])
|
boehmes@32618
|
353 |
| holds t = SApp (s_eq, [mark_term t, s_True])
|
boehmes@32618
|
354 |
|
boehmes@32618
|
355 |
val rewr_iff = (fn
|
boehmes@32618
|
356 |
SConst (@{const_name "op ="}, T as @{typ "bool => bool => bool"}) =>
|
boehmes@32618
|
357 |
SConst (@{const_name iff}, T)
|
boehmes@32618
|
358 |
| c => c)
|
boehmes@32618
|
359 |
|
boehmes@32618
|
360 |
fun rewrite ls =
|
boehmes@32618
|
361 |
let
|
boehmes@32618
|
362 |
fun rewr env loc t =
|
boehmes@32618
|
363 |
(case t of
|
boehmes@32618
|
364 |
SVar i => if not loc andalso nth env i then holds t else t
|
boehmes@32618
|
365 |
| SApp (c as SConst (@{const_name term}, _), [u]) =>
|
boehmes@32618
|
366 |
SApp (c, [rewr env true u])
|
boehmes@32618
|
367 |
| SApp (c as SConst (@{const_name formula}, _), [u]) =>
|
boehmes@32618
|
368 |
SApp (c, [rewr env false u])
|
boehmes@32618
|
369 |
| SApp (c, us) =>
|
boehmes@32618
|
370 |
let val f = if not loc andalso member (op =) ls c then holds else I
|
boehmes@32618
|
371 |
in f (SApp (rewr_iff c, map (rewr env loc) us)) end
|
boehmes@32618
|
372 |
| SLet (v, u1, u2) =>
|
boehmes@32618
|
373 |
SLet (v, rewr env loc u1, rewr (is_term u1 :: env) loc u2)
|
boehmes@32618
|
374 |
| SQuant (q, vs, ps, u) =>
|
boehmes@32618
|
375 |
let val e = replicate (length vs) true @ env
|
boehmes@32618
|
376 |
in SQuant (q, vs, map (map_pat (rewr e loc)) ps, rewr e loc u) end)
|
boehmes@32618
|
377 |
in map (rewr [] false) end
|
boehmes@32618
|
378 |
in
|
boehmes@32618
|
379 |
fun separate thy ts =
|
boehmes@32618
|
380 |
let
|
boehmes@32618
|
381 |
val (ts', (ps, fs)) = fold_map (sep false) ts ([], [])
|
boehmes@32618
|
382 |
val eq_name = (fn
|
boehmes@32618
|
383 |
(SConst (n, _), SConst (m, _)) => n = m
|
boehmes@32618
|
384 |
| (SFree (n, _), SFree (m, _)) => n = m
|
boehmes@32618
|
385 |
| _ => false)
|
boehmes@32618
|
386 |
val ls = filter (member eq_name fs) ps
|
boehmes@32618
|
387 |
val (us, thms) = split_list (map_filter (lookup_logical thy) fs)
|
boehmes@32618
|
388 |
in (thms, us @ rewrite ls ts') end
|
boehmes@32618
|
389 |
end
|
boehmes@32618
|
390 |
|
boehmes@32618
|
391 |
|
boehmes@32618
|
392 |
(* Collect the signature of intermediate terms, identify built-in symbols,
|
boehmes@32618
|
393 |
rename uninterpreted symbols and types, make bound variables unique.
|
boehmes@32618
|
394 |
We require @{term distinct} to be a built-in constant of the SMT solver.
|
boehmes@32618
|
395 |
*)
|
boehmes@32618
|
396 |
local
|
boehmes@32618
|
397 |
fun empty_nctxt p = (p, 1)
|
boehmes@32618
|
398 |
fun make_nctxt (pT, pf, pp) = (empty_nctxt pT, empty_nctxt (pf, pp))
|
boehmes@32618
|
399 |
fun fresh_name (p, i) = (p ^ string_of_int i, (p, i+1))
|
boehmes@32618
|
400 |
fun fresh_typ (nT, nfp) = fresh_name nT ||> (fn nT' => (nT', nfp))
|
boehmes@32618
|
401 |
fun fresh_fun loc (nT, ((pf, pp), i)) =
|
boehmes@32618
|
402 |
let val p = if loc then pf else pp
|
boehmes@32618
|
403 |
in fresh_name (p, i) ||> (fn (_, i') => (nT, ((pf, pp), i'))) end
|
boehmes@32618
|
404 |
|
boehmes@32618
|
405 |
val empty_sign = (Typtab.empty, Termtab.empty, Termtab.empty)
|
boehmes@32618
|
406 |
fun lookup_typ (typs, _, _) = Typtab.lookup typs
|
boehmes@32618
|
407 |
fun lookup_fun true (_, funs, _) = Termtab.lookup funs
|
boehmes@32618
|
408 |
| lookup_fun false (_, _, preds) = Termtab.lookup preds
|
boehmes@32618
|
409 |
fun add_typ x (typs, funs, preds) = (Typtab.update x typs, funs, preds)
|
boehmes@32618
|
410 |
fun add_fun true x (typs, funs, preds) = (typs, Termtab.update x funs, preds)
|
boehmes@32618
|
411 |
| add_fun false x (typs, funs, preds) = (typs, funs, Termtab.update x preds)
|
boehmes@32618
|
412 |
fun make_sign (typs, funs, preds) = Sign {
|
boehmes@32618
|
413 |
typs = map snd (Typtab.dest typs),
|
boehmes@32618
|
414 |
funs = map snd (Termtab.dest funs),
|
boehmes@32618
|
415 |
preds = map (apsnd fst o snd) (Termtab.dest preds) }
|
boehmes@32618
|
416 |
fun make_rtab (typs, funs, preds) =
|
boehmes@32618
|
417 |
let
|
boehmes@32618
|
418 |
val rTs = Typtab.dest typs |> map swap |> Symtab.make
|
boehmes@32618
|
419 |
val rts = Termtab.dest funs @ Termtab.dest preds
|
boehmes@32618
|
420 |
|> map (apfst fst o swap) |> Symtab.make
|
boehmes@32618
|
421 |
in Recon {typs=rTs, terms=rts} end
|
boehmes@32618
|
422 |
|
boehmes@32618
|
423 |
fun either f g x = (case f x of NONE => g x | y => y)
|
boehmes@32618
|
424 |
|
boehmes@32618
|
425 |
fun rep_typ (Builtins {builtin_typ, ...}) T (st as (vars, ns, sgn)) =
|
boehmes@32618
|
426 |
(case either builtin_typ (lookup_typ sgn) T of
|
boehmes@32618
|
427 |
SOME n => (n, st)
|
boehmes@32618
|
428 |
| NONE =>
|
boehmes@32618
|
429 |
let val (n, ns') = fresh_typ ns
|
boehmes@32618
|
430 |
in (n, (vars, ns', add_typ (T, n) sgn)) end)
|
boehmes@32618
|
431 |
|
boehmes@32618
|
432 |
fun rep_var bs (n, T) (vars, ns, sgn) =
|
boehmes@32618
|
433 |
let val (n', vars') = fresh_name vars
|
boehmes@32618
|
434 |
in (vars', ns, sgn) |> rep_typ bs T |>> pair n' end
|
boehmes@32618
|
435 |
|
boehmes@32618
|
436 |
fun rep_fun bs loc t T i (st as (_, _, sgn0)) =
|
boehmes@32618
|
437 |
(case lookup_fun loc sgn0 t of
|
boehmes@32618
|
438 |
SOME (n, _) => (n, st)
|
boehmes@32618
|
439 |
| NONE =>
|
boehmes@32618
|
440 |
let
|
boehmes@32618
|
441 |
val (Us, U) = dest_funT i T
|
boehmes@32618
|
442 |
val (uns, (vars, ns, sgn)) =
|
boehmes@32618
|
443 |
st |> fold_map (rep_typ bs) Us ||>> rep_typ bs U
|
boehmes@32618
|
444 |
val (n, ns') = fresh_fun loc ns
|
boehmes@32618
|
445 |
in (n, (vars, ns', add_fun loc (t, (n, uns)) sgn)) end)
|
boehmes@32618
|
446 |
|
boehmes@32618
|
447 |
fun rep_num (bs as Builtins {builtin_num, ...}) (i, T) st =
|
boehmes@32618
|
448 |
(case builtin_num (i, T) of
|
boehmes@32618
|
449 |
SOME n => (n, st)
|
boehmes@32618
|
450 |
| NONE => rep_fun bs true (HOLogic.mk_number T i) T 0 st)
|
boehmes@32618
|
451 |
in
|
boehmes@32618
|
452 |
fun signature_of prefixes markers builtins thy ts =
|
boehmes@32618
|
453 |
let
|
boehmes@32618
|
454 |
val Prefixes {var_prefix, typ_prefix, fun_prefix, pred_prefix} = prefixes
|
boehmes@32618
|
455 |
val Markers {formula_marker, term_marker} = markers
|
boehmes@32618
|
456 |
val Builtins {builtin_fun, ...} = builtins
|
boehmes@32618
|
457 |
|
boehmes@32618
|
458 |
fun sign loc t =
|
boehmes@32618
|
459 |
(case t of
|
boehmes@32618
|
460 |
SVar i => pair (SVar i)
|
boehmes@32618
|
461 |
| SApp (c as SConst (@{const_name term}, _), [u]) =>
|
boehmes@32618
|
462 |
sign true u #>> app term_marker o single
|
boehmes@32618
|
463 |
| SApp (c as SConst (@{const_name formula}, _), [u]) =>
|
boehmes@32618
|
464 |
sign false u #>> app formula_marker o single
|
boehmes@32618
|
465 |
| SApp (SConst (c as (_, T)), ts) =>
|
boehmes@32618
|
466 |
(case builtin_lookup (builtin_fun loc) thy c ts of
|
boehmes@32618
|
467 |
SOME (n, ts') => fold_map (sign loc) ts' #>> app n
|
boehmes@32618
|
468 |
| NONE =>
|
boehmes@32618
|
469 |
rep_fun builtins loc (Const c) T (length ts) ##>>
|
boehmes@32618
|
470 |
fold_map (sign loc) ts #>> SApp)
|
boehmes@32618
|
471 |
| SApp (SFree (c as (_, T)), ts) =>
|
boehmes@32618
|
472 |
rep_fun builtins loc (Free c) T (length ts) ##>>
|
boehmes@32618
|
473 |
fold_map (sign loc) ts #>> SApp
|
boehmes@32618
|
474 |
| SApp (SNum n, _) => rep_num builtins n #>> (fn n => SApp (n, []))
|
boehmes@32618
|
475 |
| SLet (v, u1, u2) =>
|
boehmes@32618
|
476 |
rep_var builtins v #-> (fn v' =>
|
boehmes@32618
|
477 |
sign loc u1 ##>> sign loc u2 #>> (fn (u1', u2') =>
|
boehmes@32618
|
478 |
SLet (v', u1', u2')))
|
boehmes@32618
|
479 |
| SQuant (q, vs, ps, u) =>
|
boehmes@32618
|
480 |
fold_map (rep_var builtins) vs ##>>
|
boehmes@32618
|
481 |
fold_map (fold_map_pat (sign loc)) ps ##>>
|
boehmes@32618
|
482 |
sign loc u #>> (fn ((vs', ps'), u') =>
|
boehmes@32618
|
483 |
SQuant (q, vs', ps', u')))
|
boehmes@32618
|
484 |
in
|
boehmes@32618
|
485 |
(empty_nctxt var_prefix, make_nctxt (typ_prefix, fun_prefix, pred_prefix),
|
boehmes@32618
|
486 |
empty_sign)
|
boehmes@32618
|
487 |
|> fold_map (sign false) ts
|
boehmes@32618
|
488 |
|> (fn (us, (_, _, sgn)) => (make_rtab sgn, (make_sign sgn, us)))
|
boehmes@32618
|
489 |
end
|
boehmes@32618
|
490 |
end
|
boehmes@32618
|
491 |
|
boehmes@32618
|
492 |
|
boehmes@32618
|
493 |
(* Combination of all translation functions and invocation of serialization. *)
|
boehmes@32618
|
494 |
|
boehmes@32618
|
495 |
fun translate config thy thms stream =
|
boehmes@32618
|
496 |
let val Config {strict, prefixes, markers, builtins, serialize} = config
|
boehmes@32618
|
497 |
in
|
boehmes@32618
|
498 |
map Thm.prop_of thms
|
boehmes@32618
|
499 |
|> SMT_Monomorph.monomorph thy
|
boehmes@32618
|
500 |
|> intermediate
|
boehmes@32618
|
501 |
|> (if strict then separate thy else pair [])
|
boehmes@32618
|
502 |
||>> signature_of prefixes markers builtins thy
|
boehmes@32618
|
503 |
||> (fn (sgn, ts) => serialize sgn ts stream)
|
boehmes@32618
|
504 |
|> (fn ((thms', rtab), _) => (rtab, thms' @ thms))
|
boehmes@32618
|
505 |
end
|
boehmes@32618
|
506 |
|
boehmes@32618
|
507 |
end
|