The XSB documentation has a paragraph about a heap data structure library, in the manual volume 2 Section 1.16.5. But I can't find any sign of the library, either in the source, or the version history, or via Google. Any ideas if this library actually exists still?
The only lead I have is a library in logtalk which is apparently sourced from the same original. But I'm working with Prolog, so would have to port the logtalk back to Prolog.
You can use Logtalk in XSB (or any other supported Prolog compiler) as just another library and call its resources from plain Prolog or from Prolog modules. Regarding Logtalk's heaps library support, it's indeed based (as stated in its documentation) on original Richard O'Keefe code but enhanced to provide both minimum heaps and maximum heaps. The heaps interface can be browsed e.g. here:
http://logtalk.org/library/heapp_0.html
http://logtalk.org/library/heap_1.html
A simple usage example:
?- heap(<)::(new(Heap), insert_all([1-a,4-d,2-b,5-e,6-f,3-c,7-g], Heap, UpdatedHeap), top(UpdatedHeap, Key, Value)).
Heap = t(0, [], t),
UpdatedHeap = t(7, [], t(1, a, t(3, c, t(5, e, t, t), t(4, d, t, t)), t(2, b, t(6, f, t, t), t(7, g, t, t)))),
Key = 1,
Value = a.
?- heap(>)::(new(Heap), insert_all([1-a,4-d,2-b,5-e,6-f,3-c,7-g], Heap, UpdatedHeap), top(UpdatedHeap, Key, Value)).
Heap = t(0, [], t),
UpdatedHeap = t(7, [], t(7, g, t(4, d, t(1, a, t, t), t(3, c, t, t)), t(6, f, t(2, b, t, t), t(5, e, t, t)))),
Key = 7,
Value = g.
One caveat, however. The ::/2 calls offer performance compared with plain Prolog only when made from within Logtalk objects (or Logtalk categories). Queries at the top-level interpreter or from within a Prolog module are interpreted (meaning that the message is resolved at runtime) instead of compiled (where the message would be resolved at compile time). Whether the performance hit is meaningful for your application only you can tell (in Prolog compilers supporting term-expansion, is easy to reduce the performance hit for ::/2 calls from within modules).
Google shows a few locations around:
heaps
heaps
Related
I am using a higher order Prolog variant that lacks findall.
There is another question on implementing our own findall here: Getting list of solutions in Prolog.
The inefficient implementation is:
parent(pam, bob). %pam is a parent of bob
parent(george, bob). %george is a parent of bob
list_parents(A, Es, [X|Xs]) :-
parent(X, A),
\+ member(X, Es),
list_parents(A, [X|Es], Xs).
list_parents(A, Es, []).
The efficient one
need a "solutions" higher-order predicate:
list_parents(X, Ys) :- solutions(parent, [X, W], 1, Ys)
What is solutions? Can I implement my own solutions predicate in higher order lambda Prolog?
Yes, if findall/3 were not available, you could implement it for example via the dynamic database.
For example, for the concrete use case of parents:
list_parents(_) :-
parent(P, _),
assertz(parent(P)),
false.
list_parents(Ps) :-
phrase(retract_parents, Ps).
retract_parents -->
( { retract(parent(P)) } ->
[P],
retract_parents
; []
).
Sample query:
?- list_parents(Ps).
Ps = [pam, george].
You can combine this with sort/2 for asymptotically optimal performance, avoiding the quadratic overhead of the "naive" solution to remove duplicates.
Beware though: First, this is not thread-safe. To make it thread-safe you need to add more information pertaining to the current thread.
Second, if you implement full-fledged findall/3 in this way, you must take care of nested findall/3 calls.
One way to do this is to assert two kinds of terms:
solution(S), such as solution(parent(pam)), indicating a concrete solution that was found on backtracking via the most recent findall/3 call
mark, indicating that a new findall/3 starts here
When collecting solutions, you only proceed to the most recent mark.
See Richard O'Keefe's book for a good introduction to these issues.
If your Prolog has some kind of non backtrackable assignment, like SWI-Prolog 'global' variables, you could implement (beware, simple minded code) in this way:
:- meta_predicate solutions(0, ?).
:- meta_predicate solutions(+, 0, ?).
solutions(G, L) :-
solutions(G, G, L).
solutions(P, G, L) :-
( nb_current(solutions_depth, C) -> true ; C=1 ),
D is C+1,
nb_setval(solutions_depth, D),
atom_concat(solutions_depth_, D, Store),
nb_setval(Store, []),
( G,
nb_getval(Store, T),
nb_setval(Store, [P|T]),
fail
; nb_getval(Store, R)
),
nb_delete(Store),
nb_setval(solutions_depth, C),
reverse(R, L).
Usage of 'global' variables results in more efficient execution WRT the dynamic database (assert/retract), and (in SWI-prolog) can be used even in multithreaded applications.
edit
Thanks to #false comment, moved the cut(s) before reverse/2, and introduced a stack for reentrant calls: for instance
?- solutions(X-Ys,(between(1,3,X),solutions(Y,between(1,5,Y),Ys)),S).
S = [1-[1, 2, 3, 4, 5], 2-[1, 2, 3, 4, 5], 3-[1, 2, 3, 4, 5]].
edit
Here is a variant of solutions/3, building the result list in order, to avoid the final reverse/2 call. Adding results to the list tail is a bit tricky...
solutions(P, G, L) :-
( nb_current(solutions_depth, C) -> true ; C=1 ),
D is C+1,
nb_setval(solutions_depth, D),
atom_concat(solutions_depth_, D, Store),
( G,
( nb_current(Store, U/B) -> B = [P|R], Q = U/R ; Q = [P|T]/T ),
nb_setval(Store, Q),
fail
; ( nb_current(Store, L/[]) -> true ; L = [] )
),
nb_delete(Store),
nb_setval(solutions_depth, C).
How to define in ISO Prolog a (meta-logical) predicate for the intersection of two lists of variables that runs in linear time? The variables may appear in any determined order. No implementation dependent property like the "age" of variables must influence the outcome.
In analogy to library(ordsets), let's call the relation varset_intersection(As, Bs, As_cap_Bs).
?- varset_intersection([A,B], [C,D], []).
true.
?-varset_intersection([A,B], [B,A], []).
false.
?- varset_intersection([A,B,C], [C,A,D], Inter).
Inter = [A,C].
or
Inter = [C,A].
?- varset_intersection([A,B],[A,B],[A,C]).
B = C
or
A = B, A = C
?- varset_intersection([A,B,C],[A,B],[A,C]).
idem
That is, the third argument is an output argument, that unifies with the intersection of the first two arguments.
See this list of the built-ins from the current ISO standard (ISO/IEC 13211-1:1995 including Cor.2).
(Note, that I did answer this question in the course of another one several years ago. However, it remains hidden and invisible to Google.)
If term_variables/2 works in a time linear with the size of its first argument, then this might work:
varset_intersection(As, Bs, As_cap_Bs):-
term_variables([As, Bs], As_and_Bs),
term_variables(As, SetAs),
append(SetAs, OnlyBs, As_and_Bs),
term_variables([OnlyBs, Bs], SetBs),
append(OnlyBs, As_cap_Bs, SetBs).
Each common variable appears only once in the result list no matter how many times it appears in the two given lists.
?- varset_intersection2([A,_C,A,A,A], [A,_B,A,A,A], L).
L = [A].
Also, it might give strange results as in this case:
?- varset_intersection([A,_X,B,C], [B,C,_Y,A], [C, A, B]).
A = B, B = C.
(permutation/2 might help here).
If copy_term/2 uses linear time, I believe the following works:
varset_intersection(As, Bs, Cs) :-
copy_term(As-Bs, CopyAs-CopyBs),
ground_list(CopyAs),
select_grounded(CopyBs, Bs, Cs).
ground_list([]).
ground_list([a|Xs]) :-
ground_list(Xs).
select_grounded([], [], []).
select_grounded([X|Xs], [_|Bs], Cs) :-
var(X),
!,
select_grounded(Xs, Bs, Cs).
select_grounded([_|Xs], [B|Bs], [B|Cs]) :-
select_grounded(Xs, Bs, Cs).
The idea is to copy both lists in one call to copy_term/2 to preserve shared variables between them, then ground the variables of the first copy, then pick out the original variables of the second list corresponding to the grounded positions of the second copy.
If unify_with_occurs_check(Var, ListOfVars) fails or succeeds in constant time, this implementation should yield answers in linear time:
filter_vars([], _, Acc, Acc).
filter_vars([A|As], Bs, Acc, As_cap_Bs):-
(
\+ unify_with_occurs_check(A, Bs)
->
filter_vars(As, Bs, [A|Acc], As_cap_Bs)
;
filter_vars(As, Bs, Acc, As_cap_Bs)
).
varset_intersection(As, Bs, As_cap_Bs):-
filter_vars(As, Bs, [], Inter),
permutation(Inter, As_cap_Bs).
This implementation has problems when given lists contain duplicates:
?- varset_intersection1([A,A,A,A,B], [B,A], L).
L = [B, A, A, A, A] ;
?- varset_intersection1([B,A], [A,A,A,A,B], L).
L = [A, B] ;
Edited : changed bagof/3 to a manually written filter thanks to observation by #false in comments below.
A possible solution is to use a Bloom filter. In case of collision, the result might be wrong, but functions with better collision resistance exist. Here is an implementation that uses a single hash function.
sum_codes([], _, Sum, Sum).
sum_codes([Head|Tail], K, Acc,Sum):-
Acc1 is Head * (256 ** K) + Acc,
K1 is (K + 1) mod 4,
sum_codes(Tail, K1, Acc1, Sum).
hash_func(Var, HashValue):-
with_output_to(atom(A), write(Var)),
atom_codes(A, Codes),
sum_codes(Codes, 0, 0, Sum),
HashValue is Sum mod 1024.
add_to_bitarray(Var, BAIn, BAOut):-
hash_func(Var, HashValue),
BAOut is BAIn \/ (1 << HashValue).
bitarray_contains(BA, Var):-
hash_func(Var, HashValue),
R is BA /\ (1 << HashValue),
R > 0.
varset_intersection(As, Bs, As_cap_Bs):-
foldl(add_to_bitarray, As, 0, BA),
include(bitarray_contains(BA), Bs, As_cap_Bs).
I know that foldl/4 and include/3 are not ISO, but their implementation is easy.
link(a, b).
link(a, c).
link(b, c).
link(b, e).
link(c, f).
link(c, g).
link(c, d).
symlink(F1, F2) :-
link(F1, F2).
symlink(F1, F2) :-
link(F2, F1).
profile(a,box). %Tag it is the same as box for a.
find(Start, Tag, Rpath) :
find2(Start, Tag, 0, [], Rpath).
find2(Step, Tag, Count, Path, Rpath) :-
C is Count +1,
C < 5,
symlink(Step, A),
compat(A,Tag), % Compatible means the distance between the tag of A
% and the Tag that is given as argument should be maximum 1.
append(Path, [A|E],Rpath), %This part i want make my final path in Rpath.
not(member(Step,Path)),
find2(A, Tag, C, [Step|Path], Rpath).
You are quite close to a working predicate here. I've include a code snippet that hopefully solves a few of the small mistakes you make. Notice that find/3 is the predicate you would actually use (from the outside), a so-called wrapper clause.
find/4 works in the following way:
The first clause is only used to detect a transgression of the maximum depth.
The second clause is only used to detect a goal node, i.e. one that matches the given tag.
The third clause does the real job of finding a symmetric link in the graph.
Some small things to note:
Renamed symlink/2 to symmetric_link/2 to avoid confusion with symbolic links.
Used \+ instead of not for negation (the former is more common I believe).
Used tag/2 for tagging nodes, not profile/2 to avoid confusion with the act of profiling/analyzing code performance.
Code snippet:
link(a, b).
link(a, c).
link(b, c).
link(b, d).
link(b, e).
link(c, f).
link(c, g).
link(c, d).
tag(a, box).
symmetric_link(F1, F2) :-
link(F1, F2).
symmetric_link(F1, F2) :-
link(F2, F1).
maximum_depth(5).
find(Start, End, Path):-
find(Start, End, 0, [Start], Path).
find(_, _, Depth, _, _):-
maximum_depth(Max),
Depth > Max, !,
fail.
find(Node, Tag, _, _, [Node]):-
tag(Node, Tag), !.
find(Node1, Tag, Depth1, History, [Node1|Path]):-
symmetric_link(Node1, Node2),
\+ memberchk(Node2, History),
Depth2 is Depth1 + 1,
find(Node2, Tag, Depth2, [Node2|History], Path).
Example of usage:
?- find(g, box, Path).
Path = [g, c, d, b, a] ;
Path = [g, c, a] ;
Path = [g, c, b, a].
I have not fully tested this predicate and would advice you to write a unit test for these kinds of predicates. I use plUnit for this, which runs on SWI-Prolog and SICStus Prolog, but there may be others as well.
Hope this helps!
I am studying Prolog using Ivan Bratko book: Programming for Artificial Intelligence and I am finding some difficulties to implement the final part of an exercise proposed
The exercise is a program that use graphs to decide how to move blocks and to arrange them in an order.
This is an image related to what the program have to do:
As you can see in the previous immage the blocks A,B,C can be moved using a number of admissible moves that are:
A block can be moved only if it is at the top of the stack
A block can be moved on the ground (on a void stack)
A block can be moved over another block (at the top of another stack
that contains some others blocks)
So these admissible moves induce a graph of the possible transitions between one state and another state in the graph, something like this:
So, as you can se in the previous graph I can rappresent a situation using a list of 3 sublist.
Each sublist rappresent a stack where I can put the blocks according to the previous constraints
So for example the situation of the central node of the previous graph can be represented by:
[[A], [B], [C]]
Because each stack contains a single block.
The situation represented by the node at the top left where I stacked one below the other blocks C,A,B can be represented by:
[[C,A,B], [], []]
Ok, so my program is the following one:
del(X, [X|Tail], Tail).
del(X, [Y|Tail], [Y|Tail1]) :- del(X, Tail, Tail1).
/* s(CurrentState, SuccessorState): Predicate that calculate a legal move from
the CurrentState to the SuccessorState:
*/
s(Stacks, [Stack1, [Top1|Stack2] | OtherStacks]) :-
del( [Top1|Stack1], Stacks, Stacks1),
del( Stack2, Stacks1, OtherStacks).
goal(Situation) :- member([a,b,c], Situation).
In these last days I have deeply studied it and I understand how it works.
Substantially the s/3 predicate is my successor function s(CurrentState, SuccessorState) that calculates a legal move from the CurrentState to the SuccessorState.
This predicate works well, in fact if I launch the following query:
[debug] ?- s([[a,b,c],[],[]],R).
R = [[b, c], [a], []]
I obtain that [[b,c],[a],[]] is a successor state for the state [[a,b,c],[],[]] and this is good because I have moved the a block from the top of the first stack on the top of the second stack (that was void) and this is a perfectly legal move.
Ok, going on I have the goal/1 predicate that says when I have reached a final state (when the computation have to stop):
goal(Situation) :- member([a,b,c], Situation).
It says that a situation (a specific stacks list configuration) is a goal situation if in the related stacks list there is a stack that is the [a,b,c] list.
So the following situations are goal situations:
[[a,b,c],[],[]]
[[], [a,b,c],[]]
[[],[], [a,b,c]]
Ok now my problem is the following one: I have to implement the solve/2 predicate like this:
solve([[c,a,b],[],[]], Situation)
that starts from a passed situation (in this case the list of stacks that have all the blocks in the first stack with c on the ground, b in the middle and a on the top) and arrives to a goal situation.
I don't know exactly what I have to do and how I have to solve it (unfortunately I have no teacher)
I was trying to inspire myself looking at this version of 8 queen problem that uses a similar programming technique (in which I have a goal to satisfy and the solve predicate):
s(Queens, [Queen|Queens]) :- member(Queen, [1,2,3,4,5,6,7,8]),
noattack(Queen, Queens, 1).
goal([_,_,_,_,_,_,_,_]).
noattack(_,[],_) :- !.
noattack(Y,[Y1|Ylist],Xdist) :- Y =\= Y1,
Y1-Y =\= Xdist,
Y-Y1 =\= Xdist,
Dist1 is Xdist + 1,
noattack(Y,Ylist,Dist1).
solve(N,[N]) :- goal(N). % sample call: solve([], X).
solve(N, [N|Sol1]) :- s(N,N1),
solve(N1,Sol1).
There will be loops in space search graph, then you can switch to some form of bound search. The easier I know it's bounded depth search:
?- length(Situation,_), solve([[c,a,b],[],[]], Situation).
Situation = [[[c, a, b], [], []], [[a, b], [c], []], [[b], [a], [c]], [[], [b, c], [a]], [[], [a, b|...], []]] .
length/2 enumerates unbound lists of growing length. So we get a result.
Note that this will still loop if there are no solutions from initial state to goal/1.
If this is bad, I think solve/2 will need a service solve2/2 predicate, that will get the path, to enable the usual \+ memberchk(NewState, Visited) after the nondeterministic s/2 call. Then it will be (untested)
solve(N, SearchPath) :- solve2([N], SearchPath).
solve2([N|Visited], [N|Visited]) :- goal(N).
solve2([N|Visited], Path) :-
s(N,N1),
\+ memberchk(N1, Visited),
solve2([N1,N|Visited], Path).
I have the following program that represent a specific b-tree by the t predicate and provides the in/2 predicate that says if an element X belongs to this tree:
t(
t(nil, b, nil),
a,
t(t(nil,d,nil), c, nil)
).
in(X, t(_,X,_)).
in(X, t(L,_,_)) :- in(X,L).
in(X, t(_,_,R)) :- in(X,R).
My problem is that I don't know how to execute this query in the Prolog shell using these two predicates.
For example, what do I have to do to ask Prolog if the d element is in the represented tree (obtaining true) or if the element z is in this tree (obtaining false)?
I'd say the problem is that t/3 doesn't belong in your fact database, it belongs in the query. Or perhaps that t/3 isn't a predicate at all, but merely a fact (though the distinction is less meaningful than it seems at first blush). But we can work with this, we just need to do some reconstruction:
?- t(A,B,C), T=t(A,B,C), in(d,T).
A = t(nil, b, nil),
B = a,
C = t(t(nil, d, nil), c, nil),
T = t(t(nil, b, nil), a, t(t(nil, d, nil), c, nil))
?- t(A,B,C), T=t(A,B,C), in(z,T).
false.
The T=t(A,B,C) gymnastic is necessary to rebuild your tree. It would be more clear if you had predicates for creating trees, so you could make a query that looks more like this:
?- empty_tree(T),
insert(T, a, T1),
insert(T1, b, T2),
insert(T2, c, T3),
in(c, T3).
Or you could store your tree like this:
tree(t(t(nil,b,nil),a,t(t(nil,d,nil),c,nil)).
And then your query would look more like:
?- tree(T), in(d, T).