Since some people have shown interests, here is the code for non-backtracking d-ary heap based on prolog compound terms, together with some tests:
d-ary heaps
:- module(dary_heap, [
create_dary_heap/3,
nb_add_to_heap/3,
nb_get_from_heap/3,
nb_decrease_key/3]).
create_dary_heap(D, Size, heap(D, 1, Array, Map)) :-
compound_name_arity(Array, array, Size),
compound_name_arity(Map, map, Size).
set(I, Array, P-K, Map) :-
nb_setarg(I, Array, P-K),
nb_setarg(K, Map, I).
swap(Array, I1, E1, I2, E2, Map) :-
set(I2, Array, E1, Map),
set(I1, Array, E2, Map).
nb_add_to_heap(Priority, Key, Heap) :-
Heap = heap(D, Last, Array, Map),
compound_name_arity(Array, _, Size),
Size >= Last,
set(Last, Array, Priority-Key, Map),
compare(R, Last, 1),
sift_up(R, D, Last, Array, Priority-Key, Map),
Last1 is Last + 1,
nb_setarg(2, Heap, Last1).
sift_up(=, _, _, _, _, _).
sift_up(>, D, Index, Array, Priority-Key, Map) :-
ParentIndex is (Index+2) // D,
arg(ParentIndex, Array, ParentPriority-ParentKey),
compare(R, ParentPriority, Priority),
sift_up(R, D, Index, Array, Priority-Key, ParentIndex, ParentPriority-ParentKey, Map).
sift_up(< , _ , _ , _ , _ , _ , _ , _).
sift_up(= , _ , _ , _ , _ , _ , _ , _).
sift_up(> , D , Index , Array , Entry , ParentIndex , ParentEntry , Map) :-
swap(Array, Index, Entry, ParentIndex, ParentEntry, Map),
compare(R, ParentIndex, 1),
sift_up(R, D, ParentIndex, Array, Entry, Map).
nb_get_from_heap(Priority, Key, Heap) :-
Heap = heap(D, Last, Array, Map),
Last > 1,
arg(1, Array, Priority-Key),
Last1 is Last - 1,
arg(Last1, Array, Entry),
set(1, Array, Entry, Map),
( Last1 > 1
-> sift_down(D, Last1, 1, Array, Entry, Map)
; true
),
nb_setarg(2, Heap, Last1).
% :- table child_indices/2.
% child_indices(Index, [C1, C2, C3, C4]) :-
% C1 is (Index-1) * 4 + 2,
% C2 is C1 + 1,
% C3 is C2 + 1,
% C4 is C3 + 1.
%
% arg_(C, I, P-(I-K)) :- arg(I, C, P-K).
% sift_down(D, Last, Index, Array, Priority-Key, Map) :-
% child_indices(Index, ChildIndices),
% include('>'(Last), ChildIndices, ValidChildIndices),
% ( ValidChildIndices \== []
% -> maplist(arg_(Array), ValidChildIndices, Childs),
% keysort(Childs, [ChildPriority-(Child-ChildKey) | _]),
% ( Priority > ChildPriority
% -> swap(Array, Index, Priority-Key, Child, ChildPriority-ChildKey, Map),
% sift_down(D, Last, Child, Array, Priority-Key, Map)
% ; true
% )
% ; true
% ).
sift_down(D, Last, Index, Array, Priority-Key, Map) :-
C1 is (Index-1) * D + 2,
( C1 >= Last
-> true
; arg(C1, Array, P1-K1),
C2 is C1 + 1,
( C2 >= Last
-> ( Priority > P1
-> swap(Array, Index, Priority-Key, C1, P1-K1, Map),
sift_down(D, Last, C1, Array, Priority-Key, Map)
; true
)
; arg(C2, Array, P2-K2),
C3 is C2 + 1,
( C3 >= Last
-> ( P1 < P2
-> ( Priority > P1
-> swap(Array, Index, Priority-Key, C1, P1-K1, Map),
sift_down(D, Last, C1, Array, Priority-Key, Map)
; true
)
; Priority > P2
-> swap(Array, Index, Priority-Key, C2, P2-K2, Map),
sift_down(D, Last, C2, Array, Priority-Key, Map)
; true
)
; arg(C3, Array, P3-K3),
C4 is C3 + 1,
( C4 >= Last
-> ( P1 < P2
-> ( P1 < P3
-> ( Priority > P1
-> swap(Array, Index, Priority-Key, C1, P1-K1, Map),
sift_down(D, Last, C1, Array, Priority-Key, Map)
; true
)
; Priority > P3
-> swap(Array, Index, Priority-Key, C3, P3-K3, Map),
sift_down(D, Last, C3, Array, Priority-Key, Map)
; true
)
; ( P2 < P3
-> ( Priority > P2
-> swap(Array, Index, Priority-Key, C2, P2-K2, Map),
sift_down(D, Last, C2, Array, Priority-Key, Map)
; true
)
; Priority > P3
-> swap(Array, Index, Priority-Key, C3, P3-K3, Map),
sift_down(D, Last, C3, Array, Priority-Key, Map)
; true
)
)
; arg(C4, Array, P4-K4),
( P1 < P2
-> ( P1 < P3
-> ( P1 < P4
-> ( Priority > P1
-> swap(Array, Index, Priority-Key, C1, P1-K1, Map),
sift_down(D, Last, C1, Array, Priority-Key, Map)
; true
)
; Priority > P4
-> swap(Array, Index, Priority-Key, C4, P4-K4, Map),
sift_down(D, Last, C4, Array, Priority-Key, Map)
; true
)
; ( P3 < P4
-> ( Priority > P3
-> swap(Array, Index, Priority-Key, C3, P3-K3, Map),
sift_down(D, Last, C3, Array, Priority-Key, Map)
; true
)
; Priority > P4
-> swap(Array, Index, Priority-Key, C4, P4-K4, Map),
sift_down(D, Last, C4, Array, Priority-Key, Map)
; true
)
)
; ( P2 < P3
-> ( P2 < P4
-> ( Priority > P2
-> swap(Array, Index, Priority-Key, C2, P2-K2, Map),
sift_down(D, Last, C2, Array, Priority-Key, Map)
; true
)
; Priority > P4
-> swap(Array, Index, Priority-Key, C4, P4-K4, Map),
sift_down(D, Last, C4, Array, Priority-Key, Map)
; true
)
; ( P3 < P4
-> ( Priority > P3
-> swap(Array, Index, Priority-Key, C3, P3-K3, Map),
sift_down(D, Last, C3, Array, Priority-Key, Map)
; true
)
; Priority > P4
-> swap(Array, Index, Priority-Key, C4, P4-K4, Map),
sift_down(D, Last, C4, Array, Priority-Key, Map)
; true
)
)
)
)
)
)
).
nb_decrease_key(NewPriority, Key, Heap) :-
Heap = heap(D, _, Array, Map),
arg(Key, Map, Index),
set(Index, Array, NewPriority-Key, Map),
compare(R, Index, 1),
sift_up(R, D, Index, Array, NewPriority-Key, Map).
:- begin_tests(heaps).
test(add_to_heap, []) :-
create_dary_heap(4, 5, Heap),
nb_add_to_heap(2, 1, Heap),
nb_add_to_heap(3, 2, Heap),
nb_add_to_heap(1, 3, Heap).
test(get_from_heap, []) :-
create_dary_heap(4, 5, Heap),
nb_add_to_heap(1, 1, Heap),
nb_get_from_heap(P, K, Heap),
P == 1, K == 1.
test(multiple_get_from_heap, []) :-
create_dary_heap(4, 5, Heap),
nb_add_to_heap(3, 1, Heap),
nb_add_to_heap(2, 2, Heap),
nb_add_to_heap(1, 3, Heap),
nb_get_from_heap(P1, K1, Heap),
P1 == 1, K1 == 3,
nb_get_from_heap(P2, K2, Heap),
P2 == 2, K2 == 2,
nb_get_from_heap(P3, K3, Heap),
P3 == 3, K3 == 1.
test(decrease_, []) :-
create_dary_heap(4, 5, Heap),
nb_add_to_heap(5, 1, Heap),
nb_decrease_key(1, 1, Heap),
nb_get_from_heap(P, K, Heap),
P == 1, K == 1.
test(multiple_get_from_heap, []) :-
create_dary_heap(4, 5, Heap),
nb_add_to_heap(4, 1, Heap),
nb_add_to_heap(3, 2, Heap),
nb_add_to_heap(2, 3, Heap),
nb_decrease_key(1, 1, Heap),
nb_get_from_heap(P, K, Heap),
P == 1, K == 1.
:- end_tests(heaps).