@@ -23,20 +23,54 @@ type term_label = Vnet (* variable (instantiable) *)
2323 | Cnet of (string * int ) (* constant *)
2424 | Lnet of int ;; (* lambda term (abstraction) *)
2525
26- type 'a net = Netnode of (term_label * 'a net ) list * 'a list ;;
26+ (* ------------------------------------------------------------------------- *)
27+ (* Edges out of a net node are split by label kind. The Vnet edge is unique *)
28+ (* (so it's a direct field, looked up in O(1)); the others are persistent *)
29+ (* balanced trees keyed by (string * int) or int with monomorphic *)
30+ (* comparators. This gives O(log n) per-edge lookup. *)
31+ (* ------------------------------------------------------------------------- *)
32+
33+ module Sikey = struct
34+ type t = string * int
35+ let compare (s1 ,i1 ) (s2 ,i2 ) =
36+ let c = String. compare s1 s2 in
37+ if c <> 0 then c else compare (i1:int ) i2
38+ end ;;
39+
40+ module Intkey = struct
41+ type t = int
42+ let compare (i1 :int ) i2 = compare i1 i2
43+ end ;;
44+
45+ module Si_map = Map. Make (Sikey );;
46+ module I_map = Map. Make (Intkey );;
47+
48+ type 'a netnode_data = {
49+ vnet : 'a net option ;
50+ cnets : 'a net Si_map .t ;
51+ lcnets : 'a net Si_map .t ;
52+ lnets : 'a net I_map .t ;
53+ tips : 'a list ;
54+ }
55+ and 'a net = Netnode of 'a netnode_data ;;
2756
2857(* ------------------------------------------------------------------------- *)
2958(* The empty net. *)
3059(* ------------------------------------------------------------------------- *)
3160
32- let empty_net = Netnode ([] ,[] );;
61+ let empty_net =
62+ Netnode { vnet = None ;
63+ cnets = Si_map. empty;
64+ lcnets = Si_map. empty;
65+ lnets = I_map. empty;
66+ tips = [] };;
3367
3468(* ------------------------------------------------------------------------- *)
3569(* Insert a new element into a net. *)
3670(* ------------------------------------------------------------------------- *)
3771
3872let enter =
39- let label_to_store lconsts tm =
73+ let label_to_store ( lconsts :term list ) ( tm :term ) : term_label * term list =
4074 let op,args = strip_comb tm in
4175 if is_const op then Cnet (fst(dest_const op),length args),args
4276 else if is_abs op then
@@ -57,41 +91,65 @@ let enter =
5791 if canon_lt x h then x::l else
5892 h::(sinsert x (tl l)) in
5993 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 )) =
94+ let update_si k upd m =
95+ let child0 = try Si_map. find k m with Not_found -> empty_net in
96+ Si_map. add k (upd child0) m in
97+ let update_int k upd m =
98+ let child0 = try I_map. find k m with Not_found -> empty_net in
99+ I_map. add k (upd child0) m in
100+ let rec net_update (lconsts :term list ) (elem :'a )
101+ (tms :term list ) (net :'a net ) : 'a net =
102+ let Netnode r = net in
61103 match tms with
62- [] -> Netnode (edges, set_insert elem tips)
104+ [] -> Netnode { r with tips = set_insert elem r. tips }
63105 | (tm ::rtms ) ->
64- let label,ntms = label_to_store lconsts tm in
65- let child,others =
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);;
106+ let label,ntms = label_to_store lconsts tm in
107+ let upd child = net_update lconsts elem (ntms@ rtms) child in
108+ match (label:term_label ) with
109+ Vnet ->
110+ let child0 =
111+ match r.vnet with Some c -> c | None -> empty_net in
112+ Netnode { r with vnet = Some (upd child0) }
113+ | Cnet k ->
114+ Netnode { r with cnets = update_si k upd r.cnets }
115+ | Lcnet k ->
116+ Netnode { r with lcnets = update_si k upd r.lcnets }
117+ | Lnet k ->
118+ Netnode { r with lnets = update_int k upd r.lnets } in
119+ fun lconsts (tm ,elem ) net -> net_update lconsts elem [tm] net;;
71120
72121(* ------------------------------------------------------------------------- *)
73122(* Look up a term in a net and return possible matches. *)
74123(* ------------------------------------------------------------------------- *)
75124
76125let lookup =
77- let label_for_lookup tm =
126+ let label_for_lookup ( tm :term ) : term_label * term list =
78127 let op,args = strip_comb tm in
79128 if is_const op then Cnet (fst(dest_const op),length args),args
80129 else if is_abs op then Lnet (length args),(body op)::args
81130 else Lcnet (fst(dest_var op),length args),args in
82- let rec follow (tms ,Netnode(edges ,tips )) =
131+ let rec follow (tms :term list ) (net :'a net ) : 'a list =
132+ let Netnode r = net in
83133 match tms with
84- [] -> tips
134+ [] -> r. tips
85135 | (tm ::rtms ) ->
86- let label,ntms = label_for_lookup tm in
87- let collection =
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);;
136+ let label,ntms = label_for_lookup tm in
137+ let collection =
138+ match (label:term_label ) with
139+ Cnet k ->
140+ (try follow (ntms@ rtms) (Si_map. find k r.cnets)
141+ with Not_found -> [] )
142+ | Lcnet k ->
143+ (try follow (ntms@ rtms) (Si_map. find k r.lcnets)
144+ with Not_found -> [] )
145+ | Lnet k ->
146+ (try follow (ntms@ rtms) (I_map. find k r.lnets)
147+ with Not_found -> [] )
148+ | Vnet -> [] in
149+ match r.vnet with
150+ None -> collection
151+ | Some vchild -> collection @ follow rtms vchild in
152+ fun tm net -> follow [tm] net;;
95153
96154(* ------------------------------------------------------------------------- *)
97155(* Function to merge two nets (code from Don Syme's hol-lite). *)
@@ -110,11 +168,22 @@ let merge_nets =
110168 if canon_eq h1 h2 then h1::(set_merge t1 t2)
111169 else if canon_lt h1 h2 then h1::(set_merge t1 l2)
112170 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
171+ let rec merge_nets (n1 ,n2 ) =
172+ let Netnode r1 = n1 and Netnode r2 = n2 in
173+ let merge_opt a b =
174+ match a,b with
175+ Some x , Some y -> Some (merge_nets (x,y))
176+ | Some _ , None -> a
177+ | None , _ -> b in
178+ let merge_si =
179+ Si_map. union (fun _ a b -> Some (merge_nets (a,b))) in
180+ let merge_int =
181+ I_map. union (fun _ a b -> Some (merge_nets (a,b))) in
182+ Netnode {
183+ vnet = merge_opt r1.vnet r2.vnet;
184+ cnets = merge_si r1.cnets r2.cnets;
185+ lcnets = merge_si r1.lcnets r2.lcnets;
186+ lnets = merge_int r1.lnets r2.lnets;
187+ tips = set_merge r1.tips r2.tips;
188+ } in
120189 merge_nets;;
0 commit comments