16781
|
1 |
(* Title: Pure/Tools/compute.ML
|
|
2 |
ID: $Id$
|
|
3 |
Author: Steven Obua
|
|
4 |
*)
|
|
5 |
|
|
6 |
signature COMPUTE = sig
|
|
7 |
|
|
8 |
type computer
|
|
9 |
|
|
10 |
exception Make of string
|
|
11 |
|
|
12 |
val basic_make : theory -> thm list -> computer
|
|
13 |
val make : theory -> thm list -> computer
|
|
14 |
|
|
15 |
val compute : computer -> (int -> string) -> cterm -> term
|
|
16 |
val theory_of : computer -> theory
|
|
17 |
|
|
18 |
val rewrite_param : computer -> (int -> string) -> cterm -> thm
|
|
19 |
val rewrite : computer -> cterm -> thm
|
|
20 |
|
|
21 |
end
|
|
22 |
|
|
23 |
structure Compute :> COMPUTE = struct
|
|
24 |
|
|
25 |
exception Internal of string; (* this exception is only thrown if there is a bug *)
|
|
26 |
|
|
27 |
exception Make of string;
|
|
28 |
|
|
29 |
fun is_mono_typ (Type (_, list)) = List.all is_mono_typ list
|
|
30 |
| is_mono_typ _ = false
|
|
31 |
|
|
32 |
fun is_mono_term (Const (_, t)) = is_mono_typ t
|
|
33 |
| is_mono_term (Var (_, t)) = is_mono_typ t
|
|
34 |
| is_mono_term (Free (_, t)) = is_mono_typ t
|
|
35 |
| is_mono_term (Bound _) = true
|
|
36 |
| is_mono_term (a $ b) = is_mono_term a andalso is_mono_term b
|
|
37 |
| is_mono_term (Abs (_, ty, t)) = is_mono_typ ty andalso is_mono_term t
|
|
38 |
|
|
39 |
structure TermTab = Termtab
|
|
40 |
structure AMTermTab = TableFun (type key = AbstractMachine.term val ord = AM_Util.term_ord)
|
|
41 |
|
|
42 |
fun add x y = Int.+ (x, y)
|
|
43 |
fun inc x = Int.+ (x, 1)
|
|
44 |
|
|
45 |
exception Mono of term;
|
|
46 |
|
|
47 |
val remove_types =
|
|
48 |
let
|
|
49 |
fun remove_types_var table invtable ccount vcount ldepth t =
|
|
50 |
(case TermTab.lookup (table, t) of
|
|
51 |
NONE =>
|
|
52 |
let
|
|
53 |
val a = AbstractMachine.Var vcount
|
|
54 |
in
|
|
55 |
(TermTab.update ((t, a), table),
|
|
56 |
AMTermTab.update ((a, t), invtable),
|
|
57 |
ccount,
|
|
58 |
inc vcount,
|
|
59 |
AbstractMachine.Var (add vcount ldepth))
|
|
60 |
end
|
|
61 |
| SOME (AbstractMachine.Var v) =>
|
|
62 |
(table, invtable, ccount, vcount, AbstractMachine.Var (add v ldepth))
|
|
63 |
| SOME _ => raise (Internal "remove_types_var: lookup should be a var"))
|
|
64 |
|
|
65 |
fun remove_types_const table invtable ccount vcount ldepth t =
|
|
66 |
(case TermTab.lookup (table, t) of
|
|
67 |
NONE =>
|
|
68 |
let
|
|
69 |
val a = AbstractMachine.Const ccount
|
|
70 |
in
|
|
71 |
(TermTab.update ((t, a), table),
|
|
72 |
AMTermTab.update ((a, t), invtable),
|
|
73 |
inc ccount,
|
|
74 |
vcount,
|
|
75 |
a)
|
|
76 |
end
|
|
77 |
| SOME (c as AbstractMachine.Const _) =>
|
|
78 |
(table, invtable, ccount, vcount, c)
|
|
79 |
| SOME _ => raise (Internal "remove_types_const: lookup should be a const"))
|
|
80 |
|
|
81 |
fun remove_types table invtable ccount vcount ldepth t =
|
|
82 |
case t of
|
|
83 |
Var (_, ty) =>
|
|
84 |
if is_mono_typ ty then remove_types_var table invtable ccount vcount ldepth t
|
|
85 |
else raise (Mono t)
|
|
86 |
| Free (_, ty) =>
|
|
87 |
if is_mono_typ ty then remove_types_var table invtable ccount vcount ldepth t
|
|
88 |
else raise (Mono t)
|
|
89 |
| Const (_, ty) =>
|
|
90 |
if is_mono_typ ty then remove_types_const table invtable ccount vcount ldepth t
|
|
91 |
else raise (Mono t)
|
|
92 |
| Abs (_, ty, t') =>
|
|
93 |
if is_mono_typ ty then
|
|
94 |
let
|
|
95 |
val (table, invtable, ccount, vcount, t') =
|
|
96 |
remove_types table invtable ccount vcount (inc ldepth) t'
|
|
97 |
in
|
|
98 |
(table, invtable, ccount, vcount, AbstractMachine.Abs t')
|
|
99 |
end
|
|
100 |
else
|
|
101 |
raise (Mono t)
|
|
102 |
| a $ b =>
|
|
103 |
let
|
|
104 |
val (table, invtable, ccount, vcount, a) =
|
|
105 |
remove_types table invtable ccount vcount ldepth a
|
|
106 |
val (table, invtable, ccount, vcount, b) =
|
|
107 |
remove_types table invtable ccount vcount ldepth b
|
|
108 |
in
|
|
109 |
(table, invtable, ccount, vcount, AbstractMachine.App (a,b))
|
|
110 |
end
|
|
111 |
| Bound b => (table, invtable, ccount, vcount, AbstractMachine.Var b)
|
|
112 |
in
|
|
113 |
fn (table, invtable, ccount, vcount) => remove_types table invtable ccount vcount 0
|
|
114 |
end
|
|
115 |
|
|
116 |
fun infer_types naming =
|
|
117 |
let
|
|
118 |
fun infer_types invtable ldepth bounds ty (AbstractMachine.Var v) =
|
|
119 |
if v < ldepth then (Bound v, List.nth (bounds, v)) else
|
|
120 |
(case AMTermTab.lookup (invtable, AbstractMachine.Var (v-ldepth)) of
|
|
121 |
SOME (t as Var (_, ty)) => (t, ty)
|
|
122 |
| SOME (t as Free (_, ty)) => (t, ty)
|
|
123 |
| _ => raise (Internal "infer_types: lookup should deliver Var or Free"))
|
|
124 |
| infer_types invtable ldepth _ ty (c as AbstractMachine.Const _) =
|
|
125 |
(case AMTermTab.lookup (invtable, c) of
|
|
126 |
SOME (c as Const (_, ty)) => (c, ty)
|
|
127 |
| _ => raise (Internal "infer_types: lookup should deliver Const"))
|
|
128 |
| infer_types invtable ldepth bounds (n,ty) (AbstractMachine.App (a, b)) =
|
|
129 |
let
|
|
130 |
val (a, aty) = infer_types invtable ldepth bounds (n+1, ty) a
|
|
131 |
val (adom, arange) =
|
|
132 |
case aty of
|
|
133 |
Type ("fun", [dom, range]) => (dom, range)
|
|
134 |
| _ => raise (Internal "infer_types: function type expected")
|
|
135 |
val (b, bty) = infer_types invtable ldepth bounds (0, adom) b
|
|
136 |
in
|
|
137 |
(a $ b, arange)
|
|
138 |
end
|
|
139 |
| infer_types invtable ldepth bounds (0, ty as Type ("fun", [dom, range])) (AbstractMachine.Abs m) =
|
|
140 |
let
|
|
141 |
val (m, _) = infer_types invtable (ldepth+1) (dom::bounds) (0, range) m
|
|
142 |
in
|
|
143 |
(Abs (naming ldepth, dom, m), ty)
|
|
144 |
end
|
|
145 |
| infer_types invtable ldepth bounds ty (AbstractMachine.Abs m) =
|
|
146 |
raise (Internal "infer_types: cannot infer type of abstraction")
|
|
147 |
|
|
148 |
fun infer invtable ty term =
|
|
149 |
let
|
|
150 |
val (term', _) = infer_types invtable 0 [] (0, ty) term
|
|
151 |
in
|
|
152 |
term'
|
|
153 |
end
|
|
154 |
in
|
|
155 |
infer
|
|
156 |
end
|
|
157 |
|
|
158 |
structure Inttab = TableFun (type key = int val ord=int_ord);
|
|
159 |
|
|
160 |
type computer = theory_ref * (AbstractMachine.term TermTab.table * term AMTermTab.table * int *
|
|
161 |
AbstractMachine.program)
|
|
162 |
|
|
163 |
fun rthy_of_thm th = Theory.self_ref (theory_of_thm th)
|
|
164 |
|
|
165 |
fun basic_make thy ths =
|
|
166 |
let
|
|
167 |
val _ = List.foldl (fn (th, _) => Theory.assert_super (theory_of_thm th) thy) thy ths
|
|
168 |
val rthy = Theory.self_ref thy
|
|
169 |
|
|
170 |
fun thm2rule table invtable ccount th =
|
|
171 |
let
|
|
172 |
val prop = Drule.plain_prop_of (transfer thy th)
|
|
173 |
val _ = if Logic.is_equals prop then () else raise (Make "theorems must be equations")
|
|
174 |
val (a, b) = Logic.dest_equals prop
|
|
175 |
|
|
176 |
val (table, invtable, ccount, vcount, prop) =
|
|
177 |
remove_types (table, invtable, ccount, 0) (a$b)
|
|
178 |
handle Mono _ => raise (Make "no type variables allowed")
|
|
179 |
val (left, right) = (case prop of AbstractMachine.App x => x | _ => raise (Internal "make: remove_types should deliver application"))
|
|
180 |
|
|
181 |
fun make_pattern table invtable n vars (var as AbstractMachine.Var v) =
|
|
182 |
let
|
|
183 |
val var' = valOf (AMTermTab.lookup (invtable, var))
|
|
184 |
val table = TermTab.delete var' table
|
|
185 |
val invtable = AMTermTab.delete var invtable
|
|
186 |
val vars = Inttab.update_new ((v, n), vars) handle Inttab.DUP _ => raise (Make "no duplicate variable in pattern allowed")
|
|
187 |
in
|
|
188 |
(table, invtable, n+1, vars, AbstractMachine.PVar)
|
|
189 |
end
|
|
190 |
| make_pattern table invtable n vars (AbstractMachine.Abs _) = raise (Make "no lambda abstractions allowed in pattern")
|
|
191 |
| make_pattern table invtable n vars (AbstractMachine.Const c) =
|
|
192 |
(table, invtable, n, vars, AbstractMachine.PConst (c, []))
|
|
193 |
| make_pattern table invtable n vars (AbstractMachine.App (a, b)) =
|
|
194 |
let
|
|
195 |
val (table, invtable, n, vars, pa) = make_pattern table invtable n vars a
|
|
196 |
val (table, invtable, n, vars, pb) = make_pattern table invtable n vars b
|
|
197 |
in
|
|
198 |
case pa of
|
|
199 |
AbstractMachine.PVar => raise (Make "patterns may not start with a variable")
|
|
200 |
| AbstractMachine.PConst (c, args) => (table, invtable, n, vars, AbstractMachine.PConst (c, args@[pb]))
|
|
201 |
end
|
|
202 |
|
|
203 |
val (table, invtable, vcount, vars, pattern) = make_pattern table invtable 0 Inttab.empty left
|
|
204 |
val _ = (case pattern of
|
|
205 |
AbstractMachine.PVar => raise (Make "patterns may not start with a variable")
|
|
206 |
| _ => ())
|
|
207 |
|
|
208 |
(* at this point, there shouldn't be any variables left in table or invtable, only constants *)
|
|
209 |
|
|
210 |
(* finally, provide a function for renaming the pattern bound variables on the right hand side *)
|
|
211 |
fun rename ldepth vars (var as AbstractMachine.Var v) =
|
|
212 |
if v < ldepth then var
|
|
213 |
else (case Inttab.lookup (vars, v-ldepth) of
|
|
214 |
NONE => raise (Make "new variable on right hand side")
|
|
215 |
| SOME n => AbstractMachine.Var ((vcount-n-1)+ldepth))
|
|
216 |
| rename ldepth vars (c as AbstractMachine.Const _) = c
|
|
217 |
| rename ldepth vars (AbstractMachine.App (a, b)) =
|
|
218 |
AbstractMachine.App (rename ldepth vars a, rename ldepth vars b)
|
|
219 |
| rename ldepth vars (AbstractMachine.Abs m) =
|
|
220 |
AbstractMachine.Abs (rename (ldepth+1) vars m)
|
|
221 |
|
|
222 |
in
|
|
223 |
(table, invtable, ccount, (pattern, rename 0 vars right))
|
|
224 |
end
|
|
225 |
|
|
226 |
val (table, invtable, ccount, rules) =
|
|
227 |
List.foldl (fn (th, (table, invtable, ccount, rules)) =>
|
|
228 |
let
|
|
229 |
val (table, invtable, ccount, rule) = thm2rule table invtable ccount th
|
|
230 |
in
|
|
231 |
(table, invtable, ccount, rule::rules)
|
|
232 |
end)
|
|
233 |
(TermTab.empty, AMTermTab.empty, 0, []) (List.rev ths)
|
|
234 |
|
|
235 |
val prog = AbstractMachine.compile rules
|
|
236 |
|
|
237 |
in
|
|
238 |
(rthy, (table, invtable, ccount, prog))
|
|
239 |
end
|
|
240 |
|
|
241 |
fun make thy ths =
|
|
242 |
let
|
|
243 |
val (_, {mk_rews={mk=mk,mk_eq_True=emk, ...},...}) = rep_ss (simpset_of thy)
|
|
244 |
fun mk_eq_True th = (case emk th of NONE => [th] | SOME th' => [th, th'])
|
|
245 |
fun app f l = List.concat (map f l)
|
|
246 |
in
|
|
247 |
basic_make thy (app mk (app mk_eq_True ths))
|
|
248 |
end
|
|
249 |
|
|
250 |
fun compute r naming ct =
|
|
251 |
let
|
|
252 |
val {t=t, T=ty, thy=ctthy, ...} = rep_cterm ct
|
|
253 |
val (rthy, (table, invtable, ccount, prog)) = r
|
|
254 |
val thy = Theory.merge (Theory.deref rthy, ctthy)
|
|
255 |
val (table, invtable, ccount, vcount, t) = remove_types (table, invtable, ccount, 0) t
|
|
256 |
val t = AbstractMachine.run prog t
|
|
257 |
val t = infer_types naming invtable ty t
|
|
258 |
in
|
|
259 |
t
|
|
260 |
end handle Internal s => (writeln ("Internal error: "^s); raise (Internal s))
|
|
261 |
|
|
262 |
fun theory_of (rthy, _) = Theory.deref rthy
|
|
263 |
|
|
264 |
fun default_naming i = "v_"^(Int.toString i)
|
|
265 |
|
|
266 |
exception Param of computer * (int -> string) * cterm;
|
|
267 |
|
|
268 |
fun rewrite_param r n ct =
|
|
269 |
let val thy = theory_of_cterm ct in
|
|
270 |
invoke_oracle_i thy "Pure.compute" (thy, Param (r, n, ct))
|
|
271 |
end
|
|
272 |
|
|
273 |
fun rewrite r ct = rewrite_param r default_naming ct
|
|
274 |
|
|
275 |
(* setup of the Pure.compute oracle *)
|
|
276 |
fun compute_oracle (sg, Param (r, naming, ct)) =
|
|
277 |
let
|
|
278 |
val _ = Theory.assert_super (theory_of r) sg
|
|
279 |
val t' = compute r naming ct
|
|
280 |
in
|
|
281 |
Logic.mk_equals (term_of ct, t')
|
|
282 |
end
|
|
283 |
|
|
284 |
fun setup_oracle thy = Theory.add_oracle ("compute", compute_oracle) thy
|
|
285 |
|
|
286 |
val _ = Context.add_setup [setup_oracle]
|
|
287 |
|
|
288 |
end
|
|
289 |
|