35
36:- module(assoc,
37 [ empty_assoc/1, 38 is_assoc/1, 39 assoc_to_list/2, 40 assoc_to_keys/2, 41 assoc_to_values/2, 42 gen_assoc/3, 43 get_assoc/3, 44 get_assoc/5, 45 list_to_assoc/2, 46 map_assoc/2, 47 map_assoc/3, 48 max_assoc/3, 49 min_assoc/3, 50 ord_list_to_assoc/2, 51 put_assoc/4, 52 del_assoc/4, 53 del_min_assoc/4, 54 del_max_assoc/4 55 ]). 56:- autoload(library(error),[must_be/2,domain_error/2]).
68:- meta_predicate
69 map_assoc(1, ?),
70 map_assoc(2, ?, ?).
76empty_assoc(t).
83assoc_to_list(Assoc, List) :-
84 assoc_to_list(Assoc, List, []).
85
86assoc_to_list(t(Key,Val,_,L,R), List, Rest) :-
87 assoc_to_list(L, List, [Key-Val|More]),
88 assoc_to_list(R, More, Rest).
89assoc_to_list(t, List, List).
97assoc_to_keys(Assoc, List) :-
98 assoc_to_keys(Assoc, List, []).
99
100assoc_to_keys(t(Key,_,_,L,R), List, Rest) :-
101 assoc_to_keys(L, List, [Key|More]),
102 assoc_to_keys(R, More, Rest).
103assoc_to_keys(t, List, List).
112assoc_to_values(Assoc, List) :-
113 assoc_to_values(Assoc, List, []).
114
115assoc_to_values(t(_,Value,_,L,R), List, Rest) :-
116 assoc_to_values(L, List, [Value|More]),
117 assoc_to_values(R, More, Rest).
118assoc_to_values(t, List, List).
127is_assoc(Assoc) :-
128 is_assoc(Assoc, _Min, _Max, _Depth).
129
130is_assoc(t,X,X,0) :- !.
131is_assoc(t(K,_,-,t,t),K,K,1) :- !, ground(K).
132is_assoc(t(K,_,>,t,t(RK,_,-,t,t)),K,RK,2) :-
133 134 !, ground((K,RK)), K @< RK.
135
136is_assoc(t(K,_,<,t(LK,_,-,t,t),t),LK,K,2) :-
137 138 !, ground((LK,K)), LK @< K.
139
140is_assoc(t(K,_,B,L,R),Min,Max,Depth) :-
141 is_assoc(L,Min,LMax,LDepth),
142 is_assoc(R,RMin,Max,RDepth),
143 144 compare(Rel,RDepth,LDepth),
145 balance(Rel,B),
146 147 ground((LMax,K,RMin)),
148 LMax @< K,
149 K @< RMin,
150 Depth is max(LDepth, RDepth)+1.
151
153balance(=,-).
154balance(<,<).
155balance(>,>).
165gen_assoc(Key, Assoc, Value) :-
166 ( ground(Key)
167 -> get_assoc(Key, Assoc, Value)
168 ; gen_assoc_(Key, Assoc, Value)
169 ).
170
171gen_assoc_(Key, t(_,_,_,L,_), Val) :-
172 gen_assoc_(Key, L, Val).
173gen_assoc_(Key, t(Key,Val,_,_,_), Val).
174gen_assoc_(Key, t(_,_,_,_,R), Val) :-
175 gen_assoc_(Key, R, Val).
184get_assoc(Key, Assoc, Val) :-
185 must_be(assoc, Assoc),
186 get_assoc_(Key, Assoc, Val).
187
188:- if(current_predicate('$btree_find_node'/5)). 189get_assoc_(Key, Tree, Val) :-
190 Tree \== t,
191 '$btree_find_node'(Key, Tree, 0x010405, Node, =),
192 arg(2, Node, Val).
193:- else. 194get_assoc_(Key, t(K,V,_,L,R), Val) :-
195 compare(Rel, Key, K),
196 get_assoc(Rel, Key, V, L, R, Val).
197
198get_assoc(=, _, Val, _, _, Val).
199get_assoc(<, Key, _, Tree, _, Val) :-
200 get_assoc(Key, Tree, Val).
201get_assoc(>, Key, _, _, Tree, Val) :-
202 get_assoc(Key, Tree, Val).
203:- endif.
210get_assoc(Key, t(K,V,B,L,R), Val, t(K,NV,B,NL,NR), NVal) :-
211 compare(Rel, Key, K),
212 get_assoc(Rel, Key, V, L, R, Val, NV, NL, NR, NVal).
213
214get_assoc(=, _, Val, L, R, Val, NVal, L, R, NVal).
215get_assoc(<, Key, V, L, R, Val, V, NL, R, NVal) :-
216 get_assoc(Key, L, Val, NL, NVal).
217get_assoc(>, Key, V, L, R, Val, V, L, NR, NVal) :-
218 get_assoc(Key, R, Val, NR, NVal).
228list_to_assoc(List, Assoc) :-
229 ( List = [] -> Assoc = t
230 ; keysort(List, Sorted),
231 ( ord_pairs(Sorted)
232 -> length(Sorted, N),
233 list_to_assoc(N, Sorted, [], _, Assoc)
234 ; domain_error(unique_key_pairs, List)
235 )
236 ).
237
238list_to_assoc(1, [K-V|More], More, 1, t(K,V,-,t,t)) :- !.
239list_to_assoc(2, [K1-V1,K2-V2|More], More, 2, t(K2,V2,<,t(K1,V1,-,t,t),t)) :- !.
240list_to_assoc(N, List, More, Depth, t(K,V,Balance,L,R)) :-
241 N0 is N - 1,
242 RN is N0 div 2,
243 Rem is N0 mod 2,
244 LN is RN + Rem,
245 list_to_assoc(LN, List, [K-V|Upper], LDepth, L),
246 list_to_assoc(RN, Upper, More, RDepth, R),
247 Depth is LDepth + 1,
248 compare(B, RDepth, LDepth), balance(B, Balance).
258ord_list_to_assoc(Sorted, Assoc) :-
259 ( Sorted = [] -> Assoc = t
260 ; ( ord_pairs(Sorted)
261 -> length(Sorted, N),
262 list_to_assoc(N, Sorted, [], _, Assoc)
263 ; domain_error(key_ordered_pairs, Sorted)
264 )
265 ).
271ord_pairs([K-_V|Rest]) :-
272 ord_pairs(Rest, K).
273ord_pairs([], _K).
274ord_pairs([K-_V|Rest], K0) :-
275 K0 @< K,
276 ord_pairs(Rest, K).
282map_assoc(Pred, T) :-
283 map_assoc_(T, Pred).
284
285map_assoc_(t, _).
286map_assoc_(t(_,Val,_,L,R), Pred) :-
287 map_assoc_(L, Pred),
288 call(Pred, Val),
289 map_assoc_(R, Pred).
296map_assoc(Pred, T0, T) :-
297 map_assoc_(T0, Pred, T).
298
299map_assoc_(t, _, t).
300map_assoc_(t(Key,Val,B,L0,R0), Pred, t(Key,Ans,B,L1,R1)) :-
301 map_assoc_(L0, Pred, L1),
302 call(Pred, Val, Ans),
303 map_assoc_(R0, Pred, R1).
310max_assoc(t(K,V,_,_,R), Key, Val) :-
311 max_assoc(R, K, V, Key, Val).
312
313max_assoc(t, K, V, K, V).
314max_assoc(t(K,V,_,_,R), _, _, Key, Val) :-
315 max_assoc(R, K, V, Key, Val).
322min_assoc(t(K,V,_,L,_), Key, Val) :-
323 min_assoc(L, K, V, Key, Val).
324
325min_assoc(t, K, V, K, V).
326min_assoc(t(K,V,_,L,_), _, _, Key, Val) :-
327 min_assoc(L, K, V, Key, Val).
335put_assoc(Key, A0, Value, A) :-
336 insert(A0, Key, Value, A, _).
337
338insert(t, Key, Val, t(Key,Val,-,t,t), yes).
339insert(t(Key,Val,B,L,R), K, V, NewTree, WhatHasChanged) :-
340 compare(Rel, K, Key),
341 insert(Rel, t(Key,Val,B,L,R), K, V, NewTree, WhatHasChanged).
342
343insert(=, t(Key,_,B,L,R), _, V, t(Key,V,B,L,R), no).
344insert(<, t(Key,Val,B,L,R), K, V, NewTree, WhatHasChanged) :-
345 insert(L, K, V, NewL, LeftHasChanged),
346 adjust(LeftHasChanged, t(Key,Val,B,NewL,R), left, NewTree, WhatHasChanged).
347insert(>, t(Key,Val,B,L,R), K, V, NewTree, WhatHasChanged) :-
348 insert(R, K, V, NewR, RightHasChanged),
349 adjust(RightHasChanged, t(Key,Val,B,L,NewR), right, NewTree, WhatHasChanged).
350
351adjust(no, Oldree, _, Oldree, no).
352adjust(yes, t(Key,Val,B0,L,R), LoR, NewTree, WhatHasChanged) :-
353 table(B0, LoR, B1, WhatHasChanged, ToBeRebalanced),
354 rebalance(ToBeRebalanced, t(Key,Val,B0,L,R), B1, NewTree, _, _).
355
358table(- , left , < , yes , no ) :- !.
359table(- , right , > , yes , no ) :- !.
360table(< , left , - , no , yes ) :- !.
361table(< , right , - , no , no ) :- !.
362table(> , left , - , no , no ) :- !.
363table(> , right , - , no , yes ) :- !.
371del_min_assoc(Tree, Key, Val, NewTree) :-
372 del_min_assoc(Tree, Key, Val, NewTree, _DepthChanged).
373
374del_min_assoc(t(Key,Val,_B,t,R), Key, Val, R, yes) :- !.
375del_min_assoc(t(K,V,B,L,R), Key, Val, NewTree, Changed) :-
376 del_min_assoc(L, Key, Val, NewL, LeftChanged),
377 deladjust(LeftChanged, t(K,V,B,NewL,R), left, NewTree, Changed).
385del_max_assoc(Tree, Key, Val, NewTree) :-
386 del_max_assoc(Tree, Key, Val, NewTree, _DepthChanged).
387
388del_max_assoc(t(Key,Val,_B,L,t), Key, Val, L, yes) :- !.
389del_max_assoc(t(K,V,B,L,R), Key, Val, NewTree, Changed) :-
390 del_max_assoc(R, Key, Val, NewR, RightChanged),
391 deladjust(RightChanged, t(K,V,B,L,NewR), right, NewTree, Changed).
398del_assoc(Key, A0, Value, A) :-
399 delete(A0, Key, Value, A, _).
400
402delete(t(Key,Val,B,L,R), K, V, NewTree, WhatHasChanged) :-
403 compare(Rel, K, Key),
404 delete(Rel, t(Key,Val,B,L,R), K, V, NewTree, WhatHasChanged).
405
409delete(=, t(Key,Val,_B,t,R), Key, Val, R, yes) :- !.
410delete(=, t(Key,Val,_B,L,t), Key, Val, L, yes) :- !.
411delete(=, t(Key,Val,>,L,R), Key, Val, NewTree, WhatHasChanged) :-
412 413 del_min_assoc(R, K, V, NewR, RightHasChanged),
414 deladjust(RightHasChanged, t(K,V,>,L,NewR), right, NewTree, WhatHasChanged),
415 !.
416delete(=, t(Key,Val,B,L,R), Key, Val, NewTree, WhatHasChanged) :-
417 418 del_max_assoc(L, K, V, NewL, LeftHasChanged),
419 deladjust(LeftHasChanged, t(K,V,B,NewL,R), left, NewTree, WhatHasChanged),
420 !.
421
422delete(<, t(Key,Val,B,L,R), K, V, NewTree, WhatHasChanged) :-
423 delete(L, K, V, NewL, LeftHasChanged),
424 deladjust(LeftHasChanged, t(Key,Val,B,NewL,R), left, NewTree, WhatHasChanged).
425delete(>, t(Key,Val,B,L,R), K, V, NewTree, WhatHasChanged) :-
426 delete(R, K, V, NewR, RightHasChanged),
427 deladjust(RightHasChanged, t(Key,Val,B,L,NewR), right, NewTree, WhatHasChanged).
428
429deladjust(no, OldTree, _, OldTree, no).
430deladjust(yes, t(Key,Val,B0,L,R), LoR, NewTree, RealChange) :-
431 deltable(B0, LoR, B1, WhatHasChanged, ToBeRebalanced),
432 rebalance(ToBeRebalanced, t(Key,Val,B0,L,R), B1, NewTree, WhatHasChanged, RealChange).
433
436deltable(- , right , < , no , no ) :- !.
437deltable(- , left , > , no , no ) :- !.
438deltable(< , right , - , yes , yes ) :- !.
439deltable(< , left , - , yes , no ) :- !.
440deltable(> , right , - , yes , no ) :- !.
441deltable(> , left , - , yes , yes ) :- !.
443
453
454
455rebalance(no, t(K,V,_,L,R), B, t(K,V,B,L,R), Changed, Changed).
456rebalance(yes, OldTree, _, NewTree, _, RealChange) :-
457 avl_geq(OldTree, NewTree, RealChange).
458
459avl_geq(t(A,VA,>,Alpha,t(B,VB,>,Beta,Gamma)),
460 t(B,VB,-,t(A,VA,-,Alpha,Beta),Gamma), yes) :- !.
461avl_geq(t(A,VA,>,Alpha,t(B,VB,-,Beta,Gamma)),
462 t(B,VB,<,t(A,VA,>,Alpha,Beta),Gamma), no) :- !.
463avl_geq(t(B,VB,<,t(A,VA,<,Alpha,Beta),Gamma),
464 t(A,VA,-,Alpha,t(B,VB,-,Beta,Gamma)), yes) :- !.
465avl_geq(t(B,VB,<,t(A,VA,-,Alpha,Beta),Gamma),
466 t(A,VA,>,Alpha,t(B,VB,<,Beta,Gamma)), no) :- !.
467avl_geq(t(A,VA,>,Alpha,t(B,VB,<,t(X,VX,B1,Beta,Gamma),Delta)),
468 t(X,VX,-,t(A,VA,B2,Alpha,Beta),t(B,VB,B3,Gamma,Delta)), yes) :-
469 !,
470 table2(B1, B2, B3).
471avl_geq(t(B,VB,<,t(A,VA,>,Alpha,t(X,VX,B1,Beta,Gamma)),Delta),
472 t(X,VX,-,t(A,VA,B2,Alpha,Beta),t(B,VB,B3,Gamma,Delta)), yes) :-
473 !,
474 table2(B1, B2, B3).
475
476table2(< ,- ,> ).
477table2(> ,< ,- ).
478table2(- ,- ,- ).
479
480
481 484
485:- multifile
486 error:has_type/2. 487
488error:has_type(assoc, X) :-
489 ( X == t
490 -> true
491 ; compound(X),
492 functor(X, t, 5)
493 )
Binary associations
Assocs are Key-Value associations implemented as a balanced binary tree (AVL tree).