| author | huffman | 
| Wed, 08 Jun 2005 00:16:28 +0200 | |
| changeset 16316 | 17db5df51a35 | 
| parent 15574 | b1d1b5bfc464 | 
| child 16677 | 6c038c13fd0f | 
| permissions | -rw-r--r-- | 
| 12319 | 1 | (* Title: Pure/net.ML | 
| 0 | 2 | ID: $Id$ | 
| 12319 | 3 | Author: Lawrence C Paulson, Cambridge University Computer Laboratory | 
| 0 | 4 | Copyright 1993 University of Cambridge | 
| 5 | ||
| 6 | Discrimination nets: a data structure for indexing items | |
| 7 | ||
| 12319 | 8 | From the book | 
| 9 | E. Charniak, C. K. Riesbeck, D. V. McDermott. | |
| 0 | 10 | Artificial Intelligence Programming. | 
| 11 | (Lawrence Erlbaum Associates, 1980). [Chapter 14] | |
| 225 
76f60e6400e8
optimized net for matching of abstractions to speed up simplifier
 nipkow parents: 
0diff
changeset | 12 | |
| 12319 | 13 | match_term no longer treats abstractions as wildcards; instead they match | 
| 228 | 14 | only wildcards in patterns. Requires operands to be beta-eta-normal. | 
| 0 | 15 | *) | 
| 16 | ||
| 12319 | 17 | signature NET = | 
| 0 | 18 | sig | 
| 19 | type key | |
| 20 | type 'a net | |
| 21 | exception DELETE and INSERT | |
| 12319 | 22 |   val delete: (key list * 'a) * 'b net * ('a * 'b -> bool) -> 'b net
 | 
| 23 |   val delete_term: (term * 'a) * 'b net * ('a * 'b -> bool) -> 'b net
 | |
| 0 | 24 | val empty: 'a net | 
| 25 |   val insert: (key list * 'a) * 'a net * ('a*'a -> bool) -> 'a net
 | |
| 26 |   val insert_term:   (term * 'a) * 'a net * ('a*'a -> bool) -> 'a net
 | |
| 27 | val lookup: 'a net * key list -> 'a list | |
| 28 | val match_term: 'a net -> term -> 'a list | |
| 29 | val key_of_term: term -> key list | |
| 30 | val unify_term: 'a net -> term -> 'a list | |
| 3548 | 31 | val dest: 'a net -> (key list * 'a) list | 
| 32 |   val merge: 'a net * 'a net * ('a*'a -> bool) -> 'a net
 | |
| 0 | 33 | end; | 
| 34 | ||
| 12319 | 35 | structure Net : NET = | 
| 0 | 36 | struct | 
| 37 | ||
| 38 | datatype key = CombK | VarK | AtomK of string; | |
| 39 | ||
| 225 
76f60e6400e8
optimized net for matching of abstractions to speed up simplifier
 nipkow parents: 
0diff
changeset | 40 | (*Bound variables*) | 
| 7943 
e31a3c0c2c1e
now more than 256 generated bound variables possible
 oheimb parents: 
6539diff
changeset | 41 | fun string_of_bound i = "*B*" ^ chr (i div 256) ^ chr (i mod 256); | 
| 0 | 42 | |
| 228 | 43 | (*Keys are preorder lists of symbols -- Combinations, Vars, Atoms. | 
| 225 
76f60e6400e8
optimized net for matching of abstractions to speed up simplifier
 nipkow parents: 
0diff
changeset | 44 | Any term whose head is a Var is regarded entirely as a Var. | 
| 228 | 45 | Abstractions are also regarded as Vars; this covers eta-conversion | 
| 46 | and "near" eta-conversions such as %x.?P(?f(x)). | |
| 0 | 47 | *) | 
| 12319 | 48 | fun add_key_of_terms (t, cs) = | 
| 0 | 49 | let fun rands (f$t, cs) = CombK :: rands (f, add_key_of_terms(t, cs)) | 
| 12319 | 50 | | rands (Const(c,_), cs) = AtomK c :: cs | 
| 51 | | rands (Free(c,_), cs) = AtomK c :: cs | |
| 52 | | rands (Bound i, cs) = AtomK (string_of_bound i) :: cs | |
| 0 | 53 | in case (head_of t) of | 
| 225 
76f60e6400e8
optimized net for matching of abstractions to speed up simplifier
 nipkow parents: 
0diff
changeset | 54 | Var _ => VarK :: cs | 
| 228 | 55 | | Abs _ => VarK :: cs | 
| 225 
76f60e6400e8
optimized net for matching of abstractions to speed up simplifier
 nipkow parents: 
0diff
changeset | 56 | | _ => rands(t,cs) | 
| 0 | 57 | end; | 
| 58 | ||
| 225 
76f60e6400e8
optimized net for matching of abstractions to speed up simplifier
 nipkow parents: 
0diff
changeset | 59 | (*convert a term to a list of keys*) | 
| 0 | 60 | fun key_of_term t = add_key_of_terms (t, []); | 
| 61 | ||
| 62 | ||
| 63 | (*Trees indexed by key lists: each arc is labelled by a key. | |
| 64 | Each node contains a list of items, and arcs to children. | |
| 65 | Keys in the association list (alist) are stored in ascending order. | |
| 66 | The empty key addresses the entire net. | |
| 67 | Lookup functions preserve order in items stored at same level. | |
| 68 | *) | |
| 69 | datatype 'a net = Leaf of 'a list | |
| 12319 | 70 |                 | Net of {comb: 'a net,
 | 
| 71 | var: 'a net, | |
| 72 | alist: (string * 'a net) list}; | |
| 0 | 73 | |
| 74 | val empty = Leaf[]; | |
| 75 | val emptynet = Net{comb=empty, var=empty, alist=[]};
 | |
| 76 | ||
| 77 | ||
| 78 | (*** Insertion into a discrimination net ***) | |
| 79 | ||
| 12319 | 80 | exception INSERT; (*duplicate item in the net*) | 
| 0 | 81 | |
| 82 | ||
| 83 | (*Adds item x to the list at the node addressed by the keys. | |
| 84 | Creates node if not already present. | |
| 12319 | 85 | eq is the equality test for items. | 
| 0 | 86 | The empty list of keys generates a Leaf node, others a Net node. | 
| 87 | *) | |
| 88 | fun insert ((keys,x), net, eq) = | |
| 12319 | 89 | let fun ins1 ([], Leaf xs) = | 
| 0 | 90 | if gen_mem eq (x,xs) then raise INSERT else Leaf(x::xs) | 
| 91 | | ins1 (keys, Leaf[]) = ins1 (keys, emptynet) (*expand empty...*) | |
| 92 |         | ins1 (CombK :: keys, Net{comb,var,alist}) =
 | |
| 12319 | 93 |             Net{comb=ins1(keys,comb), var=var, alist=alist}
 | 
| 94 |         | ins1 (VarK :: keys, Net{comb,var,alist}) =
 | |
| 95 |             Net{comb=comb, var=ins1(keys,var), alist=alist}
 | |
| 96 |         | ins1 (AtomK a :: keys, Net{comb,var,alist}) =
 | |
| 97 | let fun newpair net = (a, ins1(keys,net)) | |
| 98 | fun inslist [] = [newpair empty] | |
| 99 | | inslist((b: string, netb) :: alist) = | |
| 100 | if a=b then newpair netb :: alist | |
| 101 | else if a<b then (*absent, ins1ert in alist*) | |
| 102 | newpair empty :: (b,netb) :: alist | |
| 103 | else (*a>b*) (b,netb) :: inslist alist | |
| 104 |             in  Net{comb=comb, var=var, alist= inslist alist}  end
 | |
| 0 | 105 | in ins1 (keys,net) end; | 
| 106 | ||
| 107 | fun insert_term ((t,x), net, eq) = insert((key_of_term t, x), net, eq); | |
| 108 | ||
| 109 | (*** Deletion from a discrimination net ***) | |
| 110 | ||
| 12319 | 111 | exception DELETE; (*missing item in the net*) | 
| 0 | 112 | |
| 113 | (*Create a new Net node if it would be nonempty*) | |
| 114 | fun newnet {comb=Leaf[], var=Leaf[], alist=[]} = empty
 | |
| 115 |   | newnet {comb,var,alist} = Net{comb=comb, var=var, alist=alist};
 | |
| 116 | ||
| 117 | (*add new (b,net) pair to the alist provided net is nonempty*) | |
| 118 | fun conspair((b, Leaf[]), alist) = alist | |
| 119 | | conspair((b, net), alist) = (b, net) :: alist; | |
| 120 | ||
| 121 | (*Deletes item x from the list at the node addressed by the keys. | |
| 122 | Raises DELETE if absent. Collapses the net if possible. | |
| 123 | eq is the equality test for items. *) | |
| 12319 | 124 | fun delete ((keys, x), net, eq) = | 
| 0 | 125 | let fun del1 ([], Leaf xs) = | 
| 12319 | 126 | if gen_mem eq (x,xs) then Leaf (gen_rem (eq o swap) (xs,x)) | 
| 0 | 127 | else raise DELETE | 
| 12319 | 128 | | del1 (keys, Leaf[]) = raise DELETE | 
| 129 |         | del1 (CombK :: keys, Net{comb,var,alist}) =
 | |
| 130 |             newnet{comb=del1(keys,comb), var=var, alist=alist}
 | |
| 131 |         | del1 (VarK :: keys, Net{comb,var,alist}) =
 | |
| 132 |             newnet{comb=comb, var=del1(keys,var), alist=alist}
 | |
| 133 |         | del1 (AtomK a :: keys, Net{comb,var,alist}) =
 | |
| 134 | let fun newpair net = (a, del1(keys,net)) | |
| 135 | fun dellist [] = raise DELETE | |
| 136 | | dellist((b: string, netb) :: alist) = | |
| 137 | if a=b then conspair(newpair netb, alist) | |
| 138 | else if a<b then (*absent*) raise DELETE | |
| 139 | else (*a>b*) (b,netb) :: dellist alist | |
| 140 |             in  newnet{comb=comb, var=var, alist= dellist alist}  end
 | |
| 0 | 141 | in del1 (keys,net) end; | 
| 142 | ||
| 143 | fun delete_term ((t,x), net, eq) = delete((key_of_term t, x), net, eq); | |
| 144 | ||
| 145 | (*** Retrieval functions for discrimination nets ***) | |
| 146 | ||
| 147 | exception OASSOC; | |
| 148 | ||
| 149 | (*Ordered association list lookup*) | |
| 150 | fun oassoc ([], a: string) = raise OASSOC | |
| 151 | | oassoc ((b,x)::pairs, a) = | |
| 152 | if b<a then oassoc(pairs,a) | |
| 153 | else if a=b then x | |
| 154 | else raise OASSOC; | |
| 155 | ||
| 156 | (*Return the list of items at the given node, [] if no such node*) | |
| 157 | fun lookup (Leaf(xs), []) = xs | |
| 12319 | 158 | | lookup (Leaf _, _::_) = [] (*non-empty keys and empty net*) | 
| 0 | 159 |   | lookup (Net{comb,var,alist}, CombK :: keys) = lookup(comb,keys)
 | 
| 160 |   | lookup (Net{comb,var,alist}, VarK :: keys) = lookup(var,keys)
 | |
| 12319 | 161 |   | lookup (Net{comb,var,alist}, AtomK a :: keys) =
 | 
| 0 | 162 | lookup(oassoc(alist,a),keys) handle OASSOC => []; | 
| 163 | ||
| 164 | ||
| 165 | (*Skipping a term in a net. Recursively skip 2 levels if a combination*) | |
| 166 | fun net_skip (Leaf _, nets) = nets | |
| 12319 | 167 |   | net_skip (Net{comb,var,alist}, nets) =
 | 
| 15574 
b1d1b5bfc464
Removed practically all references to Library.foldr.
 skalberg parents: 
15570diff
changeset | 168 | foldr net_skip | 
| 
b1d1b5bfc464
Removed practically all references to Library.foldr.
 skalberg parents: 
15570diff
changeset | 169 | (foldr (fn ((_,net), nets) => net::nets) (var::nets) alist) | 
| 
b1d1b5bfc464
Removed practically all references to Library.foldr.
 skalberg parents: 
15570diff
changeset | 170 | (net_skip (comb,[])) | 
| 0 | 171 | |
| 172 | (** Matching and Unification**) | |
| 173 | ||
| 174 | (*conses the linked net, if present, to nets*) | |
| 175 | fun look1 (alist, a) nets = | |
| 176 | oassoc(alist,a) :: nets handle OASSOC => nets; | |
| 177 | ||
| 12319 | 178 | (*Return the nodes accessible from the term (cons them before nets) | 
| 0 | 179 | "unif" signifies retrieval for unification rather than matching. | 
| 180 | Var in net matches any term. | |
| 12319 | 181 | Abs or Var in object: if "unif", regarded as wildcard, | 
| 225 
76f60e6400e8
optimized net for matching of abstractions to speed up simplifier
 nipkow parents: 
0diff
changeset | 182 | else matches only a variable in net. | 
| 
76f60e6400e8
optimized net for matching of abstractions to speed up simplifier
 nipkow parents: 
0diff
changeset | 183 | *) | 
| 0 | 184 | fun matching unif t (net,nets) = | 
| 185 | let fun rands _ (Leaf _, nets) = nets | |
| 12319 | 186 |         | rands t (Net{comb,alist,...}, nets) =
 | 
| 187 | case t of | |
| 15574 
b1d1b5bfc464
Removed practically all references to Library.foldr.
 skalberg parents: 
15570diff
changeset | 188 | f$t => foldr (matching unif t) nets (rands f (comb,[])) | 
| 12319 | 189 | | Const(c,_) => look1 (alist, c) nets | 
| 190 | | Free(c,_) => look1 (alist, c) nets | |
| 191 | | Bound i => look1 (alist, string_of_bound i) nets | |
| 192 | | _ => nets | |
| 193 | in | |
| 0 | 194 | case net of | 
| 12319 | 195 | Leaf _ => nets | 
| 0 | 196 |        | Net{var,...} =>
 | 
| 12319 | 197 | case head_of t of | 
| 198 | Var _ => if unif then net_skip (net,nets) | |
| 199 | else var::nets (*only matches Var in net*) | |
| 2836 | 200 | (*If "unif" then a var instantiation in the abstraction could allow | 
| 201 | an eta-reduction, so regard the abstraction as a wildcard.*) | |
| 12319 | 202 | | Abs _ => if unif then net_skip (net,nets) | 
| 203 | else var::nets (*only a Var can match*) | |
| 204 | | _ => rands t (net, var::nets) (*var could match also*) | |
| 0 | 205 | end; | 
| 206 | ||
| 2672 
85d7e800d754
Replaced "flat" by the Basis Library function List.concat
 paulson parents: 
2226diff
changeset | 207 | fun extract_leaves l = List.concat (map (fn Leaf(xs) => xs) l); | 
| 0 | 208 | |
| 225 
76f60e6400e8
optimized net for matching of abstractions to speed up simplifier
 nipkow parents: 
0diff
changeset | 209 | (*return items whose key could match t, WHICH MUST BE BETA-ETA NORMAL*) | 
| 12319 | 210 | fun match_term net t = | 
| 0 | 211 | extract_leaves (matching false t (net,[])); | 
| 212 | ||
| 213 | (*return items whose key could unify with t*) | |
| 12319 | 214 | fun unify_term net t = | 
| 0 | 215 | extract_leaves (matching true t (net,[])); | 
| 216 | ||
| 3548 | 217 | |
| 218 | (** dest **) | |
| 219 | ||
| 220 | fun cons_fst x (xs, y) = (x :: xs, y); | |
| 221 | ||
| 222 | fun dest (Leaf xs) = map (pair []) xs | |
| 223 |   | dest (Net {comb, var, alist}) =
 | |
| 3560 | 224 | map (cons_fst CombK) (dest comb) @ | 
| 225 | map (cons_fst VarK) (dest var) @ | |
| 15570 | 226 | List.concat (map (fn (a, net) => map (cons_fst (AtomK a)) (dest net)) alist); | 
| 3548 | 227 | |
| 228 | ||
| 229 | (** merge **) | |
| 230 | ||
| 231 | fun add eq (net, keys_x) = | |
| 232 | insert (keys_x, net, eq) handle INSERT => net; | |
| 233 | ||
| 234 | fun merge (net1, net2, eq) = | |
| 15570 | 235 | Library.foldl (add eq) (net1, dest net2); | 
| 3548 | 236 | |
| 237 | ||
| 0 | 238 | end; |