23663
|
1 |
(* Title: Tools/Compute_Oracle/Linker.ML
|
|
2 |
ID: $$
|
|
3 |
Author: Steven Obua
|
|
4 |
|
|
5 |
Linker.ML solves the problem that the computing oracle does not instantiate polymorphic rules.
|
|
6 |
By going through the PCompute interface, all possible instantiations are resolved by compiling new programs, if necessary.
|
|
7 |
The obvious disadvantage of this approach is that in the worst case for each new term to be rewritten, a new program may be compiled.
|
|
8 |
*)
|
|
9 |
|
|
10 |
(*
|
|
11 |
Given constants/frees c_1::t_1, c_2::t_2, ...., c_n::t_n,
|
|
12 |
and constants/frees d_1::d_1, d_2::s_2, ..., d_m::s_m
|
|
13 |
|
|
14 |
Find all substitutions S such that
|
|
15 |
a) the domain of S is tvars (t_1, ..., t_n)
|
|
16 |
b) there are indices i_1, ..., i_k, and j_1, ..., j_k with
|
|
17 |
1. S (c_i_1::t_i_1) = d_j_1::s_j_1, ..., S (c_i_k::t_i_k) = d_j_k::s_j_k
|
|
18 |
2. tvars (t_i_1, ..., t_i_k) = tvars (t_1, ..., t_n)
|
|
19 |
*)
|
|
20 |
signature LINKER =
|
|
21 |
sig
|
|
22 |
exception Link of string
|
|
23 |
|
|
24 |
datatype constant = Constant of bool * string * typ
|
|
25 |
val constant_of : term -> constant
|
|
26 |
|
|
27 |
type instances
|
|
28 |
type subst = Type.tyenv
|
|
29 |
|
|
30 |
val empty : constant list -> instances
|
|
31 |
val typ_of_constant : constant -> typ
|
|
32 |
val add_instances : Type.tsig -> instances -> constant list -> subst list * instances
|
|
33 |
val substs_of : instances -> subst list
|
|
34 |
val is_polymorphic : constant -> bool
|
|
35 |
val distinct_constants : constant list -> constant list
|
|
36 |
val collect_consts : term list -> constant list
|
|
37 |
end
|
|
38 |
|
|
39 |
structure Linker : LINKER = struct
|
|
40 |
|
|
41 |
exception Link of string;
|
|
42 |
|
|
43 |
type subst = Type.tyenv
|
|
44 |
|
|
45 |
datatype constant = Constant of bool * string * typ
|
|
46 |
fun constant_of (Const (name, ty)) = Constant (false, name, ty)
|
|
47 |
| constant_of (Free (name, ty)) = Constant (true, name, ty)
|
|
48 |
| constant_of _ = raise Link "constant_of"
|
|
49 |
|
|
50 |
fun bool_ord (x,y) = if x then (if y then EQUAL else GREATER) else (if y then LESS else EQUAL)
|
|
51 |
fun constant_ord (Constant (x1,x2,x3), Constant (y1,y2,y3)) = (prod_ord (prod_ord bool_ord fast_string_ord) Term.typ_ord) (((x1,x2),x3), ((y1,y2),y3))
|
|
52 |
fun constant_modty_ord (Constant (x1,x2,_), Constant (y1,y2,_)) = (prod_ord bool_ord fast_string_ord) ((x1,x2), (y1,y2))
|
|
53 |
|
|
54 |
|
|
55 |
structure Consttab = TableFun(type key = constant val ord = constant_ord);
|
|
56 |
structure ConsttabModTy = TableFun(type key = constant val ord = constant_modty_ord);
|
|
57 |
|
|
58 |
fun typ_of_constant (Constant (_, _, ty)) = ty
|
|
59 |
|
|
60 |
val empty_subst = (Vartab.empty : Type.tyenv)
|
|
61 |
|
|
62 |
fun merge_subst (A:Type.tyenv) (B:Type.tyenv) =
|
|
63 |
SOME (Vartab.fold (fn (v, t) =>
|
|
64 |
fn tab =>
|
|
65 |
(case Vartab.lookup tab v of
|
|
66 |
NONE => Vartab.update (v, t) tab
|
|
67 |
| SOME t' => if t = t' then tab else raise Type.TYPE_MATCH)) A B)
|
|
68 |
handle Type.TYPE_MATCH => NONE
|
|
69 |
|
|
70 |
fun subst_ord (A:Type.tyenv, B:Type.tyenv) =
|
|
71 |
(list_ord (prod_ord Term.fast_indexname_ord (prod_ord Term.sort_ord Term.typ_ord))) (Vartab.dest A, Vartab.dest B)
|
|
72 |
|
|
73 |
structure Substtab = TableFun(type key = Type.tyenv val ord = subst_ord);
|
|
74 |
|
|
75 |
val substtab_union = Substtab.fold Substtab.update
|
|
76 |
fun substtab_unions [] = Substtab.empty
|
|
77 |
| substtab_unions [c] = c
|
|
78 |
| substtab_unions (c::cs) = substtab_union c (substtab_unions cs)
|
|
79 |
|
|
80 |
datatype instances = Instances of unit ConsttabModTy.table * Type.tyenv Consttab.table Consttab.table * constant list list * unit Substtab.table
|
|
81 |
|
|
82 |
fun is_polymorphic (Constant (_, _, ty)) = not (null (typ_tvars ty))
|
|
83 |
|
|
84 |
fun distinct_constants cs =
|
|
85 |
Consttab.keys (fold (fn c => Consttab.update (c, ())) cs Consttab.empty)
|
|
86 |
|
|
87 |
fun empty cs =
|
|
88 |
let
|
|
89 |
val cs = distinct_constants (filter is_polymorphic cs)
|
|
90 |
val old_cs = cs
|
|
91 |
(* fun collect_tvars ty tab = fold (fn v => fn tab => Typtab.update (TVar v, ()) tab) (typ_tvars ty) tab
|
|
92 |
val tvars_count = length (Typtab.keys (fold (fn c => fn tab => collect_tvars (typ_of_constant c) tab) cs Typtab.empty))
|
|
93 |
fun tvars_of ty = collect_tvars ty Typtab.empty
|
|
94 |
val cs = map (fn c => (c, tvars_of (typ_of_constant c))) cs
|
|
95 |
|
|
96 |
fun tyunion A B =
|
|
97 |
Typtab.fold
|
|
98 |
(fn (v,()) => fn tab => Typtab.update (v, case Typtab.lookup tab v of NONE => 1 | SOME n => n+1) tab)
|
|
99 |
A B
|
|
100 |
|
|
101 |
fun is_essential A B =
|
|
102 |
Typtab.fold
|
|
103 |
(fn (v, ()) => fn essential => essential orelse (case Typtab.lookup B v of NONE => raise Link "is_essential" | SOME n => n=1))
|
|
104 |
A false
|
|
105 |
|
|
106 |
fun add_minimal (c', tvs') (tvs, cs) =
|
|
107 |
let
|
|
108 |
val tvs = tyunion tvs' tvs
|
|
109 |
val cs = (c', tvs')::cs
|
|
110 |
in
|
|
111 |
if forall (fn (c',tvs') => is_essential tvs' tvs) cs then
|
|
112 |
SOME (tvs, cs)
|
|
113 |
else
|
|
114 |
NONE
|
|
115 |
end
|
|
116 |
|
|
117 |
fun is_spanning (tvs, _) = (length (Typtab.keys tvs) = tvars_count)
|
|
118 |
|
|
119 |
fun generate_minimal_subsets subsets [] = subsets
|
|
120 |
| generate_minimal_subsets subsets (c::cs) =
|
|
121 |
let
|
|
122 |
val subsets' = map_filter (add_minimal c) subsets
|
|
123 |
in
|
|
124 |
generate_minimal_subsets (subsets@subsets') cs
|
|
125 |
end*)
|
|
126 |
|
|
127 |
val minimal_subsets = [old_cs] (*map (fn (tvs, cs) => map fst cs) (filter is_spanning (generate_minimal_subsets [(Typtab.empty, [])] cs))*)
|
|
128 |
|
|
129 |
val constants = Consttab.keys (fold (fold (fn c => Consttab.update (c, ()))) minimal_subsets Consttab.empty)
|
|
130 |
|
|
131 |
in
|
|
132 |
Instances (
|
|
133 |
fold (fn c => fn tab => ConsttabModTy.update (c, ()) tab) constants ConsttabModTy.empty,
|
|
134 |
Consttab.make (map (fn c => (c, Consttab.empty : Type.tyenv Consttab.table)) constants),
|
|
135 |
minimal_subsets, Substtab.empty)
|
|
136 |
end
|
|
137 |
|
|
138 |
local
|
|
139 |
fun calc ctab substtab [] = substtab
|
|
140 |
| calc ctab substtab (c::cs) =
|
|
141 |
let
|
|
142 |
val csubsts = map snd (Consttab.dest (the (Consttab.lookup ctab c)))
|
|
143 |
fun merge_substs substtab subst =
|
|
144 |
Substtab.fold (fn (s,_) =>
|
|
145 |
fn tab =>
|
|
146 |
(case merge_subst subst s of NONE => tab | SOME s => Substtab.update (s, ()) tab))
|
|
147 |
substtab Substtab.empty
|
|
148 |
val substtab = substtab_unions (map (merge_substs substtab) csubsts)
|
|
149 |
in
|
|
150 |
calc ctab substtab cs
|
|
151 |
end
|
|
152 |
in
|
|
153 |
fun calc_substs ctab (cs:constant list) = calc ctab (Substtab.update (empty_subst, ()) Substtab.empty) cs
|
|
154 |
end
|
|
155 |
|
|
156 |
fun add_instances tsig (Instances (cfilter, ctab,minsets,substs)) cs =
|
|
157 |
let
|
|
158 |
(* val _ = writeln (makestring ("add_instances: ", length_cs, length cs, length (Consttab.keys ctab)))*)
|
|
159 |
fun calc_instantiations (constant as Constant (free, name, ty)) instantiations =
|
|
160 |
Consttab.fold (fn (constant' as Constant (free', name', ty'), insttab) =>
|
|
161 |
fn instantiations =>
|
|
162 |
if free <> free' orelse name <> name' then
|
|
163 |
instantiations
|
|
164 |
else case Consttab.lookup insttab constant of
|
|
165 |
SOME _ => instantiations
|
|
166 |
| NONE => ((constant', (constant, Type.typ_match tsig (ty', ty) empty_subst))::instantiations
|
|
167 |
handle TYPE_MATCH => instantiations))
|
|
168 |
ctab instantiations
|
|
169 |
val instantiations = fold calc_instantiations cs []
|
|
170 |
(*val _ = writeln ("instantiations = "^(makestring (length instantiations)))*)
|
|
171 |
fun update_ctab (constant', entry) ctab =
|
|
172 |
(case Consttab.lookup ctab constant' of
|
|
173 |
NONE => raise Link "internal error: update_ctab"
|
|
174 |
| SOME tab => Consttab.update (constant', Consttab.update entry tab) ctab)
|
|
175 |
val ctab = fold update_ctab instantiations ctab
|
|
176 |
val new_substs = fold (fn minset => fn substs => substtab_union (calc_substs ctab minset) substs)
|
|
177 |
minsets Substtab.empty
|
|
178 |
val (added_substs, substs) =
|
|
179 |
Substtab.fold (fn (ns, _) =>
|
|
180 |
fn (added, substtab) =>
|
|
181 |
(case Substtab.lookup substs ns of
|
|
182 |
NONE => (ns::added, Substtab.update (ns, ()) substtab)
|
|
183 |
| SOME () => (added, substtab)))
|
|
184 |
new_substs ([], substs)
|
|
185 |
in
|
|
186 |
(added_substs, Instances (cfilter, ctab, minsets, substs))
|
|
187 |
end
|
|
188 |
|
|
189 |
|
|
190 |
fun substs_of (Instances (_,_,_,substs)) = Substtab.keys substs
|
|
191 |
|
|
192 |
local
|
|
193 |
fun get_thm thmname = PureThy.get_thm (theory "Main") (Name thmname)
|
|
194 |
val eq_th = get_thm "HOL.eq_reflection"
|
|
195 |
in
|
|
196 |
fun eq_to_meta th = (eq_th OF [th] handle _ => th)
|
|
197 |
end
|
|
198 |
|
|
199 |
|
|
200 |
local
|
|
201 |
|
|
202 |
fun collect (Var x) tab = tab
|
|
203 |
| collect (Bound _) tab = tab
|
|
204 |
| collect (a $ b) tab = collect b (collect a tab)
|
|
205 |
| collect (Abs (_, _, body)) tab = collect body tab
|
|
206 |
| collect t tab = Consttab.update (constant_of t, ()) tab
|
|
207 |
|
|
208 |
in
|
|
209 |
fun collect_consts tms = Consttab.keys (fold collect tms Consttab.empty)
|
|
210 |
end
|
|
211 |
|
|
212 |
end
|
|
213 |
|
|
214 |
signature PCOMPUTE =
|
|
215 |
sig
|
|
216 |
|
|
217 |
type pcomputer
|
|
218 |
|
|
219 |
val make : Compute.machine -> theory -> thm list -> Linker.constant list -> pcomputer
|
|
220 |
|
|
221 |
(* val add_thms : pcomputer -> thm list -> bool*)
|
|
222 |
|
|
223 |
val add_instances : pcomputer -> Linker.constant list -> bool
|
|
224 |
|
|
225 |
val rewrite : pcomputer -> cterm list -> thm list
|
|
226 |
|
|
227 |
end
|
|
228 |
|
|
229 |
structure PCompute : PCOMPUTE = struct
|
|
230 |
|
|
231 |
exception PCompute of string
|
|
232 |
|
|
233 |
datatype theorem = MonoThm of thm | PolyThm of thm * Linker.instances * thm list
|
|
234 |
|
|
235 |
datatype pcomputer = PComputer of Compute.machine * theory_ref * Compute.computer ref * theorem list ref
|
|
236 |
|
|
237 |
(*fun collect_consts (Var x) = []
|
|
238 |
| collect_consts (Bound _) = []
|
|
239 |
| collect_consts (a $ b) = (collect_consts a)@(collect_consts b)
|
|
240 |
| collect_consts (Abs (_, _, body)) = collect_consts body
|
|
241 |
| collect_consts t = [Linker.constant_of t]*)
|
|
242 |
|
|
243 |
fun collect_consts_of_thm th =
|
|
244 |
let
|
|
245 |
val th = prop_of th
|
|
246 |
val (prems, th) = (Logic.strip_imp_prems th, Logic.strip_imp_concl th)
|
|
247 |
val (left, right) = Logic.dest_equals th
|
|
248 |
in
|
|
249 |
(Linker.collect_consts [left], Linker.collect_consts (right::prems))
|
|
250 |
end
|
|
251 |
|
|
252 |
fun create_theorem th =
|
|
253 |
let
|
|
254 |
val (left, right) = collect_consts_of_thm th
|
|
255 |
val polycs = filter Linker.is_polymorphic left
|
|
256 |
val tytab = fold (fn p => fn tab => fold (fn n => fn tab => Typtab.update (TVar n, ()) tab) (typ_tvars (Linker.typ_of_constant p)) tab) polycs Typtab.empty
|
|
257 |
fun check_const (c::cs) cs' =
|
|
258 |
let
|
|
259 |
val tvars = typ_tvars (Linker.typ_of_constant c)
|
|
260 |
val wrong = fold (fn n => fn wrong => wrong orelse is_none (Typtab.lookup tytab (TVar n))) tvars false
|
|
261 |
in
|
|
262 |
if wrong then raise PCompute "right hand side of theorem contains type variables which do not occur on the left hand side"
|
|
263 |
else
|
|
264 |
if null (tvars) then
|
|
265 |
check_const cs (c::cs')
|
|
266 |
else
|
|
267 |
check_const cs cs'
|
|
268 |
end
|
|
269 |
| check_const [] cs' = cs'
|
|
270 |
val monocs = check_const right []
|
|
271 |
in
|
|
272 |
if null (polycs) then
|
|
273 |
(monocs, MonoThm th)
|
|
274 |
else
|
|
275 |
(monocs, PolyThm (th, Linker.empty polycs, []))
|
|
276 |
end
|
|
277 |
|
|
278 |
fun create_computer machine thy ths =
|
|
279 |
let
|
|
280 |
fun add (MonoThm th) ths = th::ths
|
|
281 |
| add (PolyThm (_, _, ths')) ths = ths'@ths
|
|
282 |
val ths = fold_rev add ths []
|
|
283 |
in
|
|
284 |
Compute.make machine thy ths
|
|
285 |
end
|
|
286 |
|
|
287 |
fun conv_subst thy (subst : Type.tyenv) =
|
|
288 |
map (fn (iname, (sort, ty)) => (ctyp_of thy (TVar (iname, sort)), ctyp_of thy ty)) (Vartab.dest subst)
|
|
289 |
|
|
290 |
fun add_monos thy monocs ths =
|
|
291 |
let
|
|
292 |
val tsig = Sign.tsig_of thy
|
|
293 |
val changed = ref false
|
|
294 |
fun add monocs (th as (MonoThm _)) = ([], th)
|
|
295 |
| add monocs (PolyThm (th, instances, instanceths)) =
|
|
296 |
let
|
|
297 |
val (newsubsts, instances) = Linker.add_instances tsig instances monocs
|
|
298 |
val _ = if not (null newsubsts) then changed := true else ()
|
|
299 |
val newths = map (fn subst => Thm.instantiate (conv_subst thy subst, []) th) newsubsts
|
|
300 |
(* val _ = if not (null newths) then (print ("added new theorems: ", newths); ()) else ()*)
|
|
301 |
val newmonos = fold (fn th => fn monos => (snd (collect_consts_of_thm th))@monos) newths []
|
|
302 |
in
|
|
303 |
(newmonos, PolyThm (th, instances, instanceths@newths))
|
|
304 |
end
|
|
305 |
fun step monocs ths =
|
|
306 |
fold_rev (fn th =>
|
|
307 |
fn (newmonos, ths) =>
|
|
308 |
let val (newmonos', th') = add monocs th in
|
|
309 |
(newmonos'@newmonos, th'::ths)
|
|
310 |
end)
|
|
311 |
ths ([], [])
|
|
312 |
fun loop monocs ths =
|
|
313 |
let val (monocs', ths') = step monocs ths in
|
|
314 |
if null (monocs') then
|
|
315 |
ths'
|
|
316 |
else
|
|
317 |
loop monocs' ths'
|
|
318 |
end
|
|
319 |
val result = loop monocs ths
|
|
320 |
in
|
|
321 |
(!changed, result)
|
|
322 |
end
|
|
323 |
|
|
324 |
datatype cthm = ComputeThm of term list * sort list * term
|
|
325 |
|
|
326 |
fun thm2cthm th =
|
|
327 |
let
|
|
328 |
val {hyps, prop, shyps, ...} = Thm.rep_thm th
|
|
329 |
in
|
|
330 |
ComputeThm (hyps, shyps, prop)
|
|
331 |
end
|
|
332 |
|
|
333 |
val cthm_ord' = prod_ord (prod_ord (list_ord Term.term_ord) (list_ord Term.sort_ord)) Term.term_ord
|
|
334 |
|
|
335 |
fun cthm_ord (ComputeThm (h1, sh1, p1), ComputeThm (h2, sh2, p2)) = cthm_ord' (((h1,sh1), p1), ((h2, sh2), p2))
|
|
336 |
|
|
337 |
structure CThmtab = TableFun (type key = cthm val ord = cthm_ord)
|
|
338 |
|
|
339 |
fun remove_duplicates ths =
|
|
340 |
let
|
|
341 |
val counter = ref 0
|
|
342 |
val tab = ref (CThmtab.empty : unit CThmtab.table)
|
|
343 |
val thstab = ref (Inttab.empty : thm Inttab.table)
|
|
344 |
fun update th =
|
|
345 |
let
|
|
346 |
val key = thm2cthm th
|
|
347 |
in
|
|
348 |
case CThmtab.lookup (!tab) key of
|
|
349 |
NONE => ((tab := CThmtab.update_new (key, ()) (!tab)); thstab := Inttab.update_new (!counter, th) (!thstab); counter := !counter + 1)
|
|
350 |
| _ => ()
|
|
351 |
end
|
|
352 |
val _ = map update ths
|
|
353 |
in
|
|
354 |
map snd (Inttab.dest (!thstab))
|
|
355 |
end
|
|
356 |
|
|
357 |
|
|
358 |
fun make machine thy ths cs =
|
|
359 |
let
|
|
360 |
val ths = remove_duplicates ths
|
|
361 |
val (monocs, ths) = fold_rev (fn th =>
|
|
362 |
fn (monocs, ths) =>
|
|
363 |
let val (m, t) = create_theorem th in
|
|
364 |
(m@monocs, t::ths)
|
|
365 |
end)
|
|
366 |
ths (cs, [])
|
|
367 |
val (_, ths) = add_monos thy monocs ths
|
|
368 |
in
|
|
369 |
PComputer (machine, Theory.self_ref thy, ref (create_computer machine thy ths), ref ths)
|
|
370 |
end
|
|
371 |
|
|
372 |
fun add_instances (PComputer (machine, thyref, rcomputer, rths)) cs =
|
|
373 |
let
|
|
374 |
val thy = Theory.deref thyref
|
|
375 |
val (changed, ths) = add_monos thy cs (!rths)
|
|
376 |
in
|
|
377 |
if changed then
|
|
378 |
(rcomputer := create_computer machine thy ths;
|
|
379 |
rths := ths;
|
|
380 |
true)
|
|
381 |
else
|
|
382 |
false
|
|
383 |
end
|
|
384 |
|
|
385 |
fun rewrite (pc as PComputer (_, _, rcomputer, _)) cts =
|
|
386 |
let
|
|
387 |
val _ = map (fn ct => add_instances pc (Linker.collect_consts [term_of ct])) cts
|
|
388 |
in
|
|
389 |
map (fn ct => Compute.rewrite (!rcomputer) ct) cts
|
|
390 |
end
|
|
391 |
|
|
392 |
end |