34
35:- module(dif,
36 [ dif/2 37 ]). 38:- use_module(library(lists)). 39:- set_prolog_flag(generate_debug_info, false).
53dif(X,Y) :-
54 X \== Y,
55 dif_c_c(X,Y,_).
56
57dif_unifiable(X, Y, Us) :-
58 ( current_prolog_flag(occurs_check, error) ->
59 catch(unifiable(X,Y,Us), error(occurs_check(_,_),_), false)
60 ; unifiable(X, Y, Us)
61 ).
62
63dif_c_c(X,Y,OrNode) :-
64 ( dif_unifiable(X, Y, Unifier) ->
65 ( Unifier == [] ->
66 or_one_fail(OrNode)
67 ;
68 dif_c_c_l(Unifier,OrNode)
69 )
70 ;
71 or_succeed(OrNode)
72 ).
73
74
75dif_c_c_l(Unifier,OrNode) :-
76 length(Unifier,N),
77 extend_ornode(OrNode,N,List,Tail),
78 dif_c_c_l_aux(Unifier,OrNode,List,Tail).
79
80extend_ornode(OrNode,N,List,Vars) :-
81 ( get_attr(OrNode,dif,Attr) ->
82 Attr = node(M,Vars),
83 O is N + M - 1
84 ;
85 O = N,
86 Vars = []
87 ),
88 put_attr(OrNode,dif,node(O,List)).
89
90dif_c_c_l_aux([],_,List,List).
91dif_c_c_l_aux([X=Y|Unifier],OrNode,List,Tail) :-
92 List = [X=Y|Rest],
93 add_ornode(X,Y,OrNode),
94 dif_c_c_l_aux(Unifier,OrNode,Rest,Tail).
95
96add_ornode(X,Y,OrNode) :-
97 add_ornode_var1(X,Y,OrNode),
98 ( var(Y) ->
99 add_ornode_var2(X,Y,OrNode)
100 ;
101 true
102 ).
103
104add_ornode_var1(X,Y,OrNode) :-
105 ( get_attr(X,dif,Attr) ->
106 Attr = vardif(V1,V2),
107 put_attr(X,dif,vardif([OrNode-Y|V1],V2))
108 ;
109 put_attr(X,dif,vardif([OrNode-Y],[]))
110 ).
111
112add_ornode_var2(X,Y,OrNode) :-
113 ( get_attr(Y,dif,Attr) ->
114 Attr = vardif(V1,V2),
115 put_attr(Y,dif,vardif(V1,[OrNode-X|V2]))
116 ;
117 put_attr(Y,dif,vardif([],[OrNode-X]))
118 ).
119
120attr_unify_hook(vardif(V1,V2),Other) :-
121 ( var(Other) ->
122 reverse_lookups(V1,Other,OrNodes1,NV1),
123 or_one_fails(OrNodes1),
124 get_attr(Other,dif,OAttr),
125 OAttr = vardif(OV1,OV2),
126 reverse_lookups(OV1,Other,OrNodes2,NOV1),
127 or_one_fails(OrNodes2),
128 remove_obsolete(V2,Other,NV2),
129 remove_obsolete(OV2,Other,NOV2),
130 append(NV1,NOV1,CV1),
131 append(NV2,NOV2,CV2),
132 ( CV1 == [], CV2 == [] ->
133 del_attr(Other,dif)
134 ;
135 put_attr(Other,dif,vardif(CV1,CV2))
136 )
137 ;
138 verify_compounds(V1,Other),
139 verify_compounds(V2,Other)
140 ).
141
142remove_obsolete([], _, []).
143remove_obsolete([N-Y|T], X, L) :-
144 ( Y==X ->
145 remove_obsolete(T, X, L)
146 ; L=[N-Y|RT],
147 remove_obsolete(T, X, RT)
148 ).
149
150reverse_lookups([],_,[],[]).
151reverse_lookups([N-X|NXs],Value,Nodes,Rest) :-
152 ( X == Value ->
153 Nodes = [N|RNodes],
154 Rest = RRest
155 ;
156 Nodes = RNodes,
157 Rest = [N-X|RRest]
158 ),
159 reverse_lookups(NXs,Value,RNodes,RRest).
160
161verify_compounds([],_).
162verify_compounds([OrNode-Y|Rest],X) :-
163 ( var(Y) ->
164 true
165 ; OrNode == (-) ->
166 true
167 ;
168 dif_c_c(X,Y,OrNode)
169 ),
170 verify_compounds(Rest,X).
171
173or_succeed(OrNode) :-
174 ( attvar(OrNode) ->
175 get_attr(OrNode,dif,Attr),
176 Attr = node(_Counter,Pairs),
177 del_attr(OrNode,dif),
178 OrNode = (-),
179 del_or_dif(Pairs)
180 ;
181 true
182 ).
183
184or_one_fails([]).
185or_one_fails([N|Ns]) :-
186 or_one_fail(N),
187 or_one_fails(Ns).
188
189or_one_fail(OrNode) :-
190 ( attvar(OrNode) ->
191 get_attr(OrNode,dif,Attr),
192 Attr = node(Counter,Pairs),
193 NCounter is Counter - 1,
194 ( NCounter == 0 ->
195 fail
196 ;
197 put_attr(OrNode,dif,node(NCounter,Pairs))
198 )
199 ;
200 fail
201 ).
202
203del_or_dif([]).
204del_or_dif([X=Y|Xs]) :-
205 cleanup_dead_nodes(X),
206 cleanup_dead_nodes(Y),
207 del_or_dif(Xs).
208
209cleanup_dead_nodes(X) :-
210 ( attvar(X) ->
211 get_attr(X,dif,Attr),
212 Attr = vardif(V1,V2),
213 filter_dead_ors(V1,NV1),
214 filter_dead_ors(V2,NV2),
215 ( NV1 == [], NV2 == [] ->
216 del_attr(X,dif)
217 ;
218 put_attr(X,dif,vardif(NV1,NV2))
219 )
220 ;
221 true
222 ).
223
224filter_dead_ors([],[]).
225filter_dead_ors([Or-Y|Rest],List) :-
226 ( var(Or) ->
227 List = [Or-Y|NRest]
228 ;
229 List = NRest
230 ),
231 filter_dead_ors(Rest,NRest).
232
240
241attribute_goals(Var) -->
242 ( { get_attr(Var, dif, vardif(Ors,_)) } ->
243 or_nodes(Ors, Var)
244 ; or_node(Var)
245 ).
246
247or_node(O) -->
248 ( { get_attr(O, dif, node(_, Pairs)) } ->
249 { eqs_lefts_rights(Pairs, As, Bs) },
250 mydif(As, Bs),
251 { del_attr(O, dif) }
252 ; []
253 ).
254
255or_nodes([], _) --> [].
256or_nodes([O-_|Os], X) -->
257 ( { get_attr(O, dif, node(_, Eqs)) } ->
258 ( { Eqs = [LHS=_|_], LHS == X } ->
259 { eqs_lefts_rights(Eqs, As, Bs) },
260 mydif(As, Bs),
261 { del_attr(O, dif) }
262 ; []
263 )
264 ; [] 265 ),
266 or_nodes(Os, X).
267
268mydif([X], [Y]) --> !, dif_if_necessary(X, Y).
269mydif(Xs0, Ys0) -->
270 { reverse(Xs0, Xs), reverse(Ys0, Ys), 271 X =.. [f|Xs], Y =.. [f|Ys] },
272 dif_if_necessary(X, Y).
273
274dif_if_necessary(X, Y) -->
275 ( { dif_unifiable(X, Y, _) } ->
276 [dif(X,Y)]
277 ; []
278 ).
279
280eqs_lefts_rights([], [], []).
281eqs_lefts_rights([A=B|ABs], [A|As], [B|Bs]) :-
282 eqs_lefts_rights(ABs, As, Bs)
The dif/2 constraint
*/