1 (* ========================================================================= *) |
1 (* ========================================================================= *) |
2 (* MATCHING AND UNIFICATION FOR SETS OF FIRST ORDER LOGIC TERMS *) |
2 (* MATCHING AND UNIFICATION FOR SETS OF FIRST ORDER LOGIC TERMS *) |
3 (* Copyright (c) 2001-2006 Joe Hurd, distributed under the BSD License *) |
3 (* Copyright (c) 2001-2006 Joe Hurd, distributed under the BSD License *) |
4 (* ========================================================================= *) |
4 (* ========================================================================= *) |
5 |
5 |
6 structure TermNet :> TermNet = |
6 structure TermNet :> TermNet = |
7 struct |
7 struct |
8 |
8 |
9 open Useful; |
9 open Useful; |
10 |
10 |
11 (* ------------------------------------------------------------------------- *) |
11 (* ------------------------------------------------------------------------- *) |
12 (* Quotient terms *) |
12 (* Anonymous variables. *) |
13 (* ------------------------------------------------------------------------- *) |
13 (* ------------------------------------------------------------------------- *) |
14 |
14 |
15 datatype qterm = VAR | FN of NameArity.nameArity * qterm list; |
15 val anonymousName = Name.fromString "_"; |
16 |
16 val anonymousVar = Term.Var anonymousName; |
17 fun termToQterm (Term.Var _) = VAR |
17 |
18 | termToQterm (Term.Fn (f,l)) = FN ((f, length l), map termToQterm l); |
18 (* ------------------------------------------------------------------------- *) |
|
19 (* Quotient terms. *) |
|
20 (* ------------------------------------------------------------------------- *) |
|
21 |
|
22 datatype qterm = |
|
23 Var |
|
24 | Fn of NameArity.nameArity * qterm list; |
|
25 |
|
26 local |
|
27 fun cmp [] = EQUAL |
|
28 | cmp (q1_q2 :: qs) = |
|
29 if Portable.pointerEqual q1_q2 then cmp qs |
|
30 else |
|
31 case q1_q2 of |
|
32 (Var,Var) => EQUAL |
|
33 | (Var, Fn _) => LESS |
|
34 | (Fn _, Var) => GREATER |
|
35 | (Fn f1, Fn f2) => fnCmp f1 f2 qs |
|
36 |
|
37 and fnCmp (n1,q1) (n2,q2) qs = |
|
38 case NameArity.compare (n1,n2) of |
|
39 LESS => LESS |
|
40 | EQUAL => cmp (zip q1 q2 @ qs) |
|
41 | GREATER => GREATER; |
|
42 in |
|
43 fun compareQterm q1_q2 = cmp [q1_q2]; |
|
44 |
|
45 fun compareFnQterm (f1,f2) = fnCmp f1 f2 []; |
|
46 end; |
|
47 |
|
48 fun equalQterm q1 q2 = compareQterm (q1,q2) = EQUAL; |
|
49 |
|
50 fun equalFnQterm f1 f2 = compareFnQterm (f1,f2) = EQUAL; |
|
51 |
|
52 fun termToQterm (Term.Var _) = Var |
|
53 | termToQterm (Term.Fn (f,l)) = Fn ((f, length l), map termToQterm l); |
19 |
54 |
20 local |
55 local |
21 fun qm [] = true |
56 fun qm [] = true |
22 | qm ((VAR,_) :: rest) = qm rest |
57 | qm ((Var,_) :: rest) = qm rest |
23 | qm ((FN _, VAR) :: _) = false |
58 | qm ((Fn _, Var) :: _) = false |
24 | qm ((FN (f,a), FN (g,b)) :: rest) = f = g andalso qm (zip a b @ rest); |
59 | qm ((Fn (f,a), Fn (g,b)) :: rest) = |
|
60 NameArity.equal f g andalso qm (zip a b @ rest); |
25 in |
61 in |
26 fun matchQtermQterm qtm qtm' = qm [(qtm,qtm')]; |
62 fun matchQtermQterm qtm qtm' = qm [(qtm,qtm')]; |
27 end; |
63 end; |
28 |
64 |
29 local |
65 local |
30 fun qm [] = true |
66 fun qm [] = true |
31 | qm ((VAR,_) :: rest) = qm rest |
67 | qm ((Var,_) :: rest) = qm rest |
32 | qm ((FN _, Term.Var _) :: _) = false |
68 | qm ((Fn _, Term.Var _) :: _) = false |
33 | qm ((FN ((f,n),a), Term.Fn (g,b)) :: rest) = |
69 | qm ((Fn ((f,n),a), Term.Fn (g,b)) :: rest) = |
34 f = g andalso n = length b andalso qm (zip a b @ rest); |
70 Name.equal f g andalso n = length b andalso qm (zip a b @ rest); |
35 in |
71 in |
36 fun matchQtermTerm qtm tm = qm [(qtm,tm)]; |
72 fun matchQtermTerm qtm tm = qm [(qtm,tm)]; |
37 end; |
73 end; |
38 |
74 |
39 local |
75 local |
40 fun qn qsub [] = SOME qsub |
76 fun qn qsub [] = SOME qsub |
41 | qn qsub ((Term.Var v, qtm) :: rest) = |
77 | qn qsub ((Term.Var v, qtm) :: rest) = |
42 (case NameMap.peek qsub v of |
78 (case NameMap.peek qsub v of |
43 NONE => qn (NameMap.insert qsub (v,qtm)) rest |
79 NONE => qn (NameMap.insert qsub (v,qtm)) rest |
44 | SOME qtm' => if qtm = qtm' then qn qsub rest else NONE) |
80 | SOME qtm' => if equalQterm qtm qtm' then qn qsub rest else NONE) |
45 | qn _ ((Term.Fn _, VAR) :: _) = NONE |
81 | qn _ ((Term.Fn _, Var) :: _) = NONE |
46 | qn qsub ((Term.Fn (f,a), FN ((g,n),b)) :: rest) = |
82 | qn qsub ((Term.Fn (f,a), Fn ((g,n),b)) :: rest) = |
47 if f = g andalso length a = n then qn qsub (zip a b @ rest) else NONE; |
83 if Name.equal f g andalso length a = n then qn qsub (zip a b @ rest) |
|
84 else NONE; |
48 in |
85 in |
49 fun matchTermQterm qsub tm qtm = qn qsub [(tm,qtm)]; |
86 fun matchTermQterm qsub tm qtm = qn qsub [(tm,qtm)]; |
50 end; |
87 end; |
51 |
88 |
52 local |
89 local |
53 fun qv VAR x = x |
90 fun qv Var x = x |
54 | qv x VAR = x |
91 | qv x Var = x |
55 | qv (FN (f,a)) (FN (g,b)) = |
92 | qv (Fn (f,a)) (Fn (g,b)) = |
56 let |
93 let |
57 val _ = f = g orelse raise Error "TermNet.qv" |
94 val _ = NameArity.equal f g orelse raise Error "TermNet.qv" |
58 in |
95 in |
59 FN (f, zipwith qv a b) |
96 Fn (f, zipWith qv a b) |
60 end; |
97 end; |
61 |
98 |
62 fun qu qsub [] = qsub |
99 fun qu qsub [] = qsub |
63 | qu qsub ((VAR, _) :: rest) = qu qsub rest |
100 | qu qsub ((Var, _) :: rest) = qu qsub rest |
64 | qu qsub ((qtm, Term.Var v) :: rest) = |
101 | qu qsub ((qtm, Term.Var v) :: rest) = |
65 let |
102 let |
66 val qtm = |
103 val qtm = |
67 case NameMap.peek qsub v of NONE => qtm | SOME qtm' => qv qtm qtm' |
104 case NameMap.peek qsub v of NONE => qtm | SOME qtm' => qv qtm qtm' |
68 in |
105 in |
69 qu (NameMap.insert qsub (v,qtm)) rest |
106 qu (NameMap.insert qsub (v,qtm)) rest |
70 end |
107 end |
71 | qu qsub ((FN ((f,n),a), Term.Fn (g,b)) :: rest) = |
108 | qu qsub ((Fn ((f,n),a), Term.Fn (g,b)) :: rest) = |
72 if f = g andalso n = length b then qu qsub (zip a b @ rest) |
109 if Name.equal f g andalso n = length b then qu qsub (zip a b @ rest) |
73 else raise Error "TermNet.qu"; |
110 else raise Error "TermNet.qu"; |
74 in |
111 in |
75 fun unifyQtermQterm qtm qtm' = total (qv qtm) qtm'; |
112 fun unifyQtermQterm qtm qtm' = total (qv qtm) qtm'; |
76 |
113 |
77 fun unifyQtermTerm qsub qtm tm = total (qu qsub) [(qtm,tm)]; |
114 fun unifyQtermTerm qsub qtm tm = total (qu qsub) [(qtm,tm)]; |
78 end; |
115 end; |
79 |
116 |
80 local |
117 local |
81 fun qtermToTerm VAR = Term.Var "" |
118 fun qtermToTerm Var = anonymousVar |
82 | qtermToTerm (FN ((f,_),l)) = Term.Fn (f, map qtermToTerm l); |
119 | qtermToTerm (Fn ((f,_),l)) = Term.Fn (f, map qtermToTerm l); |
83 in |
120 in |
84 val ppQterm = Parser.ppMap qtermToTerm Term.pp; |
121 val ppQterm = Print.ppMap qtermToTerm Term.pp; |
85 end; |
122 end; |
86 |
123 |
87 (* ------------------------------------------------------------------------- *) |
124 (* ------------------------------------------------------------------------- *) |
88 (* A type of term sets that can be efficiently matched and unified. *) |
125 (* A type of term sets that can be efficiently matched and unified. *) |
89 (* ------------------------------------------------------------------------- *) |
126 (* ------------------------------------------------------------------------- *) |
90 |
127 |
91 type parameters = {fifo : bool}; |
128 type parameters = {fifo : bool}; |
92 |
129 |
93 datatype 'a net = |
130 datatype 'a net = |
94 RESULT of 'a list |
131 Result of 'a list |
95 | SINGLE of qterm * 'a net |
132 | Single of qterm * 'a net |
96 | MULTIPLE of 'a net option * 'a net NameArityMap.map; |
133 | Multiple of 'a net option * 'a net NameArityMap.map; |
97 |
134 |
98 datatype 'a termNet = NET of parameters * int * (int * (int * 'a) net) option; |
135 datatype 'a termNet = Net of parameters * int * (int * (int * 'a) net) option; |
99 |
136 |
100 (* ------------------------------------------------------------------------- *) |
137 (* ------------------------------------------------------------------------- *) |
101 (* Basic operations. *) |
138 (* Basic operations. *) |
102 (* ------------------------------------------------------------------------- *) |
139 (* ------------------------------------------------------------------------- *) |
103 |
140 |
104 fun new parm = NET (parm,0,NONE); |
141 fun new parm = Net (parm,0,NONE); |
105 |
142 |
106 local |
143 local |
107 fun computeSize (RESULT l) = length l |
144 fun computeSize (Result l) = length l |
108 | computeSize (SINGLE (_,n)) = computeSize n |
145 | computeSize (Single (_,n)) = computeSize n |
109 | computeSize (MULTIPLE (vs,fs)) = |
146 | computeSize (Multiple (vs,fs)) = |
110 NameArityMap.foldl |
147 NameArityMap.foldl |
111 (fn (_,n,acc) => acc + computeSize n) |
148 (fn (_,n,acc) => acc + computeSize n) |
112 (case vs of SOME n => computeSize n | NONE => 0) |
149 (case vs of SOME n => computeSize n | NONE => 0) |
113 fs; |
150 fs; |
114 in |
151 in |
115 fun netSize NONE = NONE |
152 fun netSize NONE = NONE |
116 | netSize (SOME n) = SOME (computeSize n, n); |
153 | netSize (SOME n) = SOME (computeSize n, n); |
117 end; |
154 end; |
118 |
155 |
119 fun size (NET (_,_,NONE)) = 0 |
156 fun size (Net (_,_,NONE)) = 0 |
120 | size (NET (_, _, SOME (i,_))) = i; |
157 | size (Net (_, _, SOME (i,_))) = i; |
121 |
158 |
122 fun null net = size net = 0; |
159 fun null net = size net = 0; |
123 |
160 |
124 fun singles qtms a = foldr SINGLE a qtms; |
161 fun singles qtms a = foldr Single a qtms; |
125 |
162 |
126 local |
163 local |
127 fun pre NONE = (0,NONE) |
164 fun pre NONE = (0,NONE) |
128 | pre (SOME (i,n)) = (i, SOME n); |
165 | pre (SOME (i,n)) = (i, SOME n); |
129 |
166 |
130 fun add (RESULT l) [] (RESULT l') = RESULT (l @ l') |
167 fun add (Result l) [] (Result l') = Result (l @ l') |
131 | add a (input1 as qtm :: qtms) (SINGLE (qtm',n)) = |
168 | add a (input1 as qtm :: qtms) (Single (qtm',n)) = |
132 if qtm = qtm' then SINGLE (qtm, add a qtms n) |
169 if equalQterm qtm qtm' then Single (qtm, add a qtms n) |
133 else add a input1 (add n [qtm'] (MULTIPLE (NONE, NameArityMap.new ()))) |
170 else add a input1 (add n [qtm'] (Multiple (NONE, NameArityMap.new ()))) |
134 | add a (VAR :: qtms) (MULTIPLE (vs,fs)) = |
171 | add a (Var :: qtms) (Multiple (vs,fs)) = |
135 MULTIPLE (SOME (oadd a qtms vs), fs) |
172 Multiple (SOME (oadd a qtms vs), fs) |
136 | add a (FN (f,l) :: qtms) (MULTIPLE (vs,fs)) = |
173 | add a (Fn (f,l) :: qtms) (Multiple (vs,fs)) = |
137 let |
174 let |
138 val n = NameArityMap.peek fs f |
175 val n = NameArityMap.peek fs f |
139 in |
176 in |
140 MULTIPLE (vs, NameArityMap.insert fs (f, oadd a (l @ qtms) n)) |
177 Multiple (vs, NameArityMap.insert fs (f, oadd a (l @ qtms) n)) |
141 end |
178 end |
142 | add _ _ _ = raise Bug "TermNet.insert: Match" |
179 | add _ _ _ = raise Bug "TermNet.insert: Match" |
143 |
180 |
144 and oadd a qtms NONE = singles qtms a |
181 and oadd a qtms NONE = singles qtms a |
145 | oadd a qtms (SOME n) = add a qtms n; |
182 | oadd a qtms (SOME n) = add a qtms n; |
146 |
183 |
147 fun ins a qtm (i,n) = SOME (i + 1, oadd (RESULT [a]) [qtm] n); |
184 fun ins a qtm (i,n) = SOME (i + 1, oadd (Result [a]) [qtm] n); |
148 in |
185 in |
149 fun insert (NET (p,k,n)) (tm,a) = |
186 fun insert (Net (p,k,n)) (tm,a) = |
150 NET (p, k + 1, ins (k,a) (termToQterm tm) (pre n)) |
187 Net (p, k + 1, ins (k,a) (termToQterm tm) (pre n)) |
151 handle Error _ => raise Bug "TermNet.insert: should never fail"; |
188 handle Error _ => raise Bug "TermNet.insert: should never fail"; |
152 end; |
189 end; |
153 |
190 |
154 fun fromList parm l = foldl (fn (tm_a,n) => insert n tm_a) (new parm) l; |
191 fun fromList parm l = foldl (fn (tm_a,n) => insert n tm_a) (new parm) l; |
155 |
192 |
156 fun filter pred = |
193 fun filter pred = |
157 let |
194 let |
158 fun filt (RESULT l) = |
195 fun filt (Result l) = |
159 (case List.filter (fn (_,a) => pred a) l of |
196 (case List.filter (fn (_,a) => pred a) l of |
160 [] => NONE |
197 [] => NONE |
161 | l => SOME (RESULT l)) |
198 | l => SOME (Result l)) |
162 | filt (SINGLE (qtm,n)) = |
199 | filt (Single (qtm,n)) = |
163 (case filt n of |
200 (case filt n of |
164 NONE => NONE |
201 NONE => NONE |
165 | SOME n => SOME (SINGLE (qtm,n))) |
202 | SOME n => SOME (Single (qtm,n))) |
166 | filt (MULTIPLE (vs,fs)) = |
203 | filt (Multiple (vs,fs)) = |
167 let |
204 let |
168 val vs = Option.mapPartial filt vs |
205 val vs = Option.mapPartial filt vs |
169 |
206 |
170 val fs = NameArityMap.mapPartial (fn (_,n) => filt n) fs |
207 val fs = NameArityMap.mapPartial (fn (_,n) => filt n) fs |
171 in |
208 in |
172 if not (Option.isSome vs) andalso NameArityMap.null fs then NONE |
209 if not (Option.isSome vs) andalso NameArityMap.null fs then NONE |
173 else SOME (MULTIPLE (vs,fs)) |
210 else SOME (Multiple (vs,fs)) |
174 end |
211 end |
175 in |
212 in |
176 fn net as NET (_,_,NONE) => net |
213 fn net as Net (_,_,NONE) => net |
177 | NET (p, k, SOME (_,n)) => NET (p, k, netSize (filt n)) |
214 | Net (p, k, SOME (_,n)) => Net (p, k, netSize (filt n)) |
178 end |
215 end |
179 handle Error _ => raise Bug "TermNet.filter: should never fail"; |
216 handle Error _ => raise Bug "TermNet.filter: should never fail"; |
180 |
217 |
181 fun toString net = "TermNet[" ^ Int.toString (size net) ^ "]"; |
218 fun toString net = "TermNet[" ^ Int.toString (size net) ^ "]"; |
182 |
219 |
337 (NameMap.insert qsub (v,qtm), net, tms) :: rest; |
374 (NameMap.insert qsub (v,qtm), net, tms) :: rest; |
338 |
375 |
339 fun seenInc qsub tms (_,net,rest) = (qsub,net,tms) :: rest; |
376 fun seenInc qsub tms (_,net,rest) = (qsub,net,tms) :: rest; |
340 |
377 |
341 fun mat acc [] = acc |
378 fun mat acc [] = acc |
342 | mat acc ((_, RESULT l, []) :: rest) = mat (l @ acc) rest |
379 | mat acc ((_, Result l, []) :: rest) = mat (l @ acc) rest |
343 | mat acc ((qsub, SINGLE (qtm,net), tm :: tms) :: rest) = |
380 | mat acc ((qsub, Single (qtm,net), tm :: tms) :: rest) = |
344 (case matchTermQterm qsub tm qtm of |
381 (case matchTermQterm qsub tm qtm of |
345 NONE => mat acc rest |
382 NONE => mat acc rest |
346 | SOME qsub => mat acc ((qsub,net,tms) :: rest)) |
383 | SOME qsub => mat acc ((qsub,net,tms) :: rest)) |
347 | mat acc ((qsub, net as MULTIPLE _, Term.Var v :: tms) :: rest) = |
384 | mat acc ((qsub, net as Multiple _, Term.Var v :: tms) :: rest) = |
348 (case NameMap.peek qsub v of |
385 (case NameMap.peek qsub v of |
349 NONE => mat acc (foldTerms (unseenInc qsub v tms) rest net) |
386 NONE => mat acc (foldTerms (unseenInc qsub v tms) rest net) |
350 | SOME qtm => mat acc (foldEqualTerms qtm (seenInc qsub tms) rest net)) |
387 | SOME qtm => mat acc (foldEqualTerms qtm (seenInc qsub tms) rest net)) |
351 | mat acc ((qsub, MULTIPLE (_,fns), Term.Fn (f,a) :: tms) :: rest) = |
388 | mat acc ((qsub, Multiple (_,fns), Term.Fn (f,a) :: tms) :: rest) = |
352 let |
389 let |
353 val rest = |
390 val rest = |
354 case NameArityMap.peek fns (f, length a) of |
391 case NameArityMap.peek fns (f, length a) of |
355 NONE => rest |
392 NONE => rest |
356 | SOME net => (qsub, net, a @ tms) :: rest |
393 | SOME net => (qsub, net, a @ tms) :: rest |
357 in |
394 in |
358 mat acc rest |
395 mat acc rest |
359 end |
396 end |
360 | mat _ _ = raise Bug "TermNet.matched.mat"; |
397 | mat _ _ = raise Bug "TermNet.matched.mat"; |
361 in |
398 in |
362 fun matched (NET (_,_,NONE)) _ = [] |
399 fun matched (Net (_,_,NONE)) _ = [] |
363 | matched (NET (parm, _, SOME (_,net))) tm = |
400 | matched (Net (parm, _, SOME (_,net))) tm = |
364 finally parm (mat [] [(NameMap.new (), net, [tm])]) |
401 finally parm (mat [] [(NameMap.new (), net, [tm])]) |
365 handle Error _ => raise Bug "TermNet.matched: should never fail"; |
402 handle Error _ => raise Bug "TermNet.matched: should never fail"; |
366 end; |
403 end; |
367 |
404 |
368 local |
405 local |
369 fun inc qsub v tms (qtm,net,rest) = |
406 fun inc qsub v tms (qtm,net,rest) = |
370 (NameMap.insert qsub (v,qtm), net, tms) :: rest; |
407 (NameMap.insert qsub (v,qtm), net, tms) :: rest; |
371 |
408 |
372 fun mat acc [] = acc |
409 fun mat acc [] = acc |
373 | mat acc ((_, RESULT l, []) :: rest) = mat (l @ acc) rest |
410 | mat acc ((_, Result l, []) :: rest) = mat (l @ acc) rest |
374 | mat acc ((qsub, SINGLE (qtm,net), tm :: tms) :: rest) = |
411 | mat acc ((qsub, Single (qtm,net), tm :: tms) :: rest) = |
375 (case unifyQtermTerm qsub qtm tm of |
412 (case unifyQtermTerm qsub qtm tm of |
376 NONE => mat acc rest |
413 NONE => mat acc rest |
377 | SOME qsub => mat acc ((qsub,net,tms) :: rest)) |
414 | SOME qsub => mat acc ((qsub,net,tms) :: rest)) |
378 | mat acc ((qsub, net as MULTIPLE _, Term.Var v :: tms) :: rest) = |
415 | mat acc ((qsub, net as Multiple _, Term.Var v :: tms) :: rest) = |
379 (case NameMap.peek qsub v of |
416 (case NameMap.peek qsub v of |
380 NONE => mat acc (foldTerms (inc qsub v tms) rest net) |
417 NONE => mat acc (foldTerms (inc qsub v tms) rest net) |
381 | SOME qtm => mat acc (foldUnifiableTerms qtm (inc qsub v tms) rest net)) |
418 | SOME qtm => mat acc (foldUnifiableTerms qtm (inc qsub v tms) rest net)) |
382 | mat acc ((qsub, MULTIPLE (v,fns), Term.Fn (f,a) :: tms) :: rest) = |
419 | mat acc ((qsub, Multiple (v,fns), Term.Fn (f,a) :: tms) :: rest) = |
383 let |
420 let |
384 val rest = case v of NONE => rest | SOME net => (qsub,net,tms) :: rest |
421 val rest = case v of NONE => rest | SOME net => (qsub,net,tms) :: rest |
385 |
422 |
386 val rest = |
423 val rest = |
387 case NameArityMap.peek fns (f, length a) of |
424 case NameArityMap.peek fns (f, length a) of |