1 (* ========================================================================= *)
2 (* Term nets: reasonably fast lookup based on term matchability. *)
4 (* John Harrison, University of Cambridge Computer Laboratory *)
6 (* (c) Copyright, University of Cambridge 1998 *)
7 (* (c) Copyright, John Harrison 1998-2007 *)
8 (* ========================================================================= *)
12 (* ------------------------------------------------------------------------- *)
13 (* Term nets are a finitely branching tree structure; at each level we *)
14 (* have a set of branches and a set of "values". Linearization is *)
15 (* performed from the left of a combination; even in iterated *)
16 (* combinations we look at the head first. This is probably fastest, and *)
17 (* anyway it's useful to allow our restricted second order matches: if *)
18 (* the head is a variable then then whole term is treated as a variable. *)
19 (* ------------------------------------------------------------------------- *)
21 type term_label = Vnet (* variable (instantiable) *)
22 | Lcnet of (string * int) (* local constant *)
23 | Cnet of (string * int) (* constant *)
24 | Lnet of int;; (* lambda term (abstraction) *)
26 type 'a net = Netnode of (term_label * 'a net) list * 'a list;;
28 (* ------------------------------------------------------------------------- *)
30 (* ------------------------------------------------------------------------- *)
32 let empty_net = Netnode([],[]);;
34 (* ------------------------------------------------------------------------- *)
35 (* Insert a new element into a net. *)
36 (* ------------------------------------------------------------------------- *)
39 let label_to_store lconsts tm =
40 let op,args = strip_comb tm in
41 if is_const op then Cnet(fst(dest_const op),length args),args
42 else if is_abs op then
43 let bv,bod = dest_abs op in
44 let bod' = if mem bv lconsts then vsubst [genvar(type_of bv),bv] bod
46 Lnet(length args),bod'::args
47 else if mem op lconsts then Lcnet(fst(dest_var op),length args),args
50 try Pervasives.compare x y = 0 with Invalid_argument _ -> false
52 try Pervasives.compare x y < 0 with Invalid_argument _ -> false in
54 if l = [] then [x] else
56 if canon_eq h x then failwith "sinsert" else
57 if canon_lt x h then x::l else
58 h::(sinsert x (tl l)) in
59 let set_insert x l = try sinsert x l with Failure "sinsert" -> l in
60 let rec net_update lconsts (elem,tms,Netnode(edges,tips)) =
62 [] -> Netnode(edges,set_insert elem tips)
64 let label,ntms = label_to_store lconsts tm in
66 try (snd F_F I) (remove (fun (x,y) -> x = label) edges)
67 with Failure _ -> (empty_net,edges) in
68 let new_child = net_update lconsts (elem,ntms@rtms,child) in
69 Netnode ((label,new_child)::others,tips) in
70 fun lconsts (tm,elem) net -> net_update lconsts (elem,[tm],net);;
72 (* ------------------------------------------------------------------------- *)
73 (* Look up a term in a net and return possible matches. *)
74 (* ------------------------------------------------------------------------- *)
77 let label_for_lookup tm =
78 let op,args = strip_comb tm in
79 if is_const op then Cnet(fst(dest_const op),length args),args
80 else if is_abs op then Lnet(length args),(body op)::args
81 else Lcnet(fst(dest_var op),length args),args in
82 let rec follow (tms,Netnode(edges,tips)) =
86 let label,ntms = label_for_lookup tm in
88 try let child = assoc label edges in
89 follow(ntms @ rtms, child)
90 with Failure _ -> [] in
91 if label = Vnet then collection else
92 try collection @ follow(rtms,assoc Vnet edges)
93 with Failure _ -> collection in
94 fun tm net -> follow([tm],net);;
96 (* ------------------------------------------------------------------------- *)
97 (* Function to merge two nets (code from Don Syme's hol-lite). *)
98 (* ------------------------------------------------------------------------- *)
102 try Pervasives.compare x y = 0 with Invalid_argument _ -> false
104 try Pervasives.compare x y < 0 with Invalid_argument _ -> false in
105 let rec set_merge l1 l2 =
107 else if l2 = [] then l1 else
108 let h1 = hd l1 and t1 = tl l1
109 and h2 = hd l2 and t2 = tl l2 in
110 if canon_eq h1 h2 then h1::(set_merge t1 t2)
111 else if canon_lt h1 h2 then h1::(set_merge t1 l2)
112 else h2::(set_merge l1 t2) in
113 let rec merge_nets (Netnode(l1,data1),Netnode(l2,data2)) =
114 let add_node ((lab,net) as p) l =
115 try let (lab',net'),rest = remove (fun (x,y) -> x = lab) l in
116 (lab',merge_nets (net,net'))::rest
117 with Failure _ -> p::l in
118 Netnode(itlist add_node l2 (itlist add_node l1 []),
119 set_merge data1 data2) in