So check the exercize 3.5 description here:
%% Exercise 3.5 %%
% Binary trees are trees where all internal nodes have exactly two children.
% The smallest binary trees consist of only one leaf node. We will represent leaf nodes as
% leaf(Label) . For instance, leaf(3) and leaf(7) are leaf nodes, and therefore small binary
% trees. Given two binary trees B1 and B2 we can combine them into one binary tree using the
% functor tree/2 as follows: tree(B1,B2) . So, from the leaves leaf(1) and leaf(2) we can build
% the binary tree tree(leaf(1),leaf(2)) . And from the binary trees tree(leaf(1),leaf(2)) and
% leaf(4) we can build the binary tree tree(tree(leaf(1), leaf(2)),leaf(4)).
% Now, define a predicate swap/2 , which produces the mirror image of the binary tree that is its first argument. For example:
% ?- swap(tree(tree(leaf(1), leaf(2)), leaf(4)),T).
% T = tree(leaf(4), tree(leaf(2), leaf(1))).
% yes
And this is my implementation:
swap(tree(leaf(X), leaf(Y)), tree(leaf(Y), leaf(X))).
swap(tree(B1, leaf(Y)), tree(leaf(Y), SwapB1)) :-
dif(B1, leaf(_)),
swap(B1, SwapB1).
swap(tree(leaf(X), B2), tree(SwapB2, leaf(X))) :-
dif(B2, leaf(_)),
swap(B2, SwapB2).
swap(tree(B1, B2), tree(B2,B1)) :-
dif(B1, leaf(_)),
dif(B2, leaf(_)).
When I execute the following query swap(T1,T). I get:
?- swap(T1,T).
T1 = tree(leaf(_A), leaf(_B)),
T = tree(leaf(_B), leaf(_A)) ;
T1 = tree(tree(leaf(_A), leaf(_B)), leaf(_C)),
T = tree(leaf(_C), tree(leaf(_B), leaf(_A))) ;
T1 = tree(tree(tree(leaf(_A), leaf(_B)), leaf(_C)), leaf(_D)),
T = tree(leaf(_D), tree(leaf(_C), tree(leaf(_B), leaf(_A)))) ;
T1 = tree(tree(tree(tree(leaf(_A), leaf(_B)), leaf(_C)), leaf(_D)), leaf(_E)),
T = tree(leaf(_E), tree(leaf(_D), tree(leaf(_C), tree(leaf(_B), leaf(_A))))) .
As you can see Prolog is not considering all of the solutions for each number of leaves N. For example, for N = 4, the case T1 = tree( tree(leaf(_A) , leaf(_B)), tree(leaf(_C), leaf(_D)) ) is not being considered.
Edit: changed the case N=3 to N=4, now i think it's more clear.
I'm trying to make Prolog consider all solutions for each number of leaves N of the tree without relying on CLPFD as suggested before by user #false
Thank you for your attention!
Your problem is called fairness of enumeration. Prolog's backtracking algorithm explores the last recursive call in a goal as deeply as possible, so if you have two recursive calls in a goal, enumeration will always get "stuck" in the second one.
Here's a simpler example, just enumerating trees:
tree(leaf(_)).
tree(tree(Left, Right)) :-
tree(Left),
tree(Right).
Just like in your case, this builds trees that deepen to the right:
?- tree(Tree).
Tree = leaf(_1986) ;
Tree = tree(leaf(_1992), leaf(_1996)) ;
Tree = tree(leaf(_1992), tree(leaf(_2002), leaf(_2006))) ;
Tree = tree(leaf(_1992), tree(leaf(_2002), tree(leaf(_2012), leaf(_2016)))) ;
Tree = tree(leaf(_1992), tree(leaf(_2002), tree(leaf(_2012), tree(leaf(_2022), leaf(_2026))))) .
The fix for this is to introduce some kind of "size" measure, like the number of leaves, and to enumerate guided by the size. This is why using CLPFD arithmetic was suggested. Without arithmetic, one way of doing this is with lists.
Here is a predicate that relates trees and lists of their leaves:
tree_leaves(leaf(X), [X]).
tree_leaves(tree(Left, Right), Leaves) :-
LeftLeaves = [_ | _],
RightLeaves = [_ | _],
append(LeftLeaves, RightLeaves, Leaves),
tree_leaves(Left, LeftLeaves),
tree_leaves(Right, RightLeaves).
For example:
?- Leaves = [a, b, c], tree_leaves(Tree, Leaves).
Leaves = [a, b, c],
Tree = tree(leaf(a), tree(leaf(b), leaf(c))) ;
Leaves = [a, b, c],
Tree = tree(tree(leaf(a), leaf(b)), leaf(c)) ;
false.
As you can see, for a fixed-length list, this did enumerate all (two) possible tree structures.
So now we want to do something similar with a fair enumeration of all fixed-length lists -- this will force a fair enumeration of the corresponding trees. Lists can be enumerated fairly with the length/2 predicate:
?- length(List, N).
List = [],
N = 0 ;
List = [_2242],
N = 1 ;
List = [_2242, _2248],
N = 2 ;
List = [_2242, _2248, _2254],
N = 3 ;
List = [_2242, _2248, _2254, _2260],
N = 4 .
Therefore:
?- length(Leaves, N), tree_leaves(Tree, Leaves).
Leaves = [_2798],
N = 1,
Tree = leaf(_2798) ;
Leaves = [_2798, _2804],
N = 2,
Tree = tree(leaf(_2798), leaf(_2804)) ;
Leaves = [_2798, _2804, _2810],
N = 3,
Tree = tree(leaf(_2798), tree(leaf(_2804), leaf(_2810))) ;
Leaves = [_2798, _2804, _2810],
N = 3,
Tree = tree(tree(leaf(_2798), leaf(_2804)), leaf(_2810)) ;
Leaves = [_2798, _2804, _2810, _2816],
N = 4,
Tree = tree(leaf(_2798), tree(leaf(_2804), tree(leaf(_2810), leaf(_2816)))) ;
Leaves = [_2798, _2804, _2810, _2816],
N = 4,
Tree = tree(leaf(_2798), tree(tree(leaf(_2804), leaf(_2810)), leaf(_2816))) ;
Leaves = [_2798, _2804, _2810, _2816],
N = 4,
Tree = tree(tree(leaf(_2798), leaf(_2804)), tree(leaf(_2810), leaf(_2816))) ;
Leaves = [_2798, _2804, _2810, _2816],
N = 4,
Tree = tree(tree(leaf(_2798), tree(leaf(_2804), leaf(_2810))), leaf(_2816)) ;
Leaves = [_2798, _2804, _2810, _2816],
N = 4,
Tree = tree(tree(tree(leaf(_2798), leaf(_2804)), leaf(_2810)), leaf(_2816)) ;
Leaves = [_2798, _2804, _2810, _2816, _2822],
N = 5,
Tree = tree(leaf(_2798), tree(leaf(_2804), tree(leaf(_2810), tree(leaf(_2816), leaf(_2822))))) .
We can package this up:
fairtree(Tree) :-
length(Leaves, _N),
tree_leaves(Tree, Leaves).
And then test your swap/2 predicate with fair enumeration:
?- fairtree(Tree), swap(Tree, Swapped).
Tree = tree(leaf(_2122), leaf(_2128)),
Swapped = tree(leaf(_2128), leaf(_2122)) ;
Tree = tree(leaf(_2874), leaf(_2878)),
Swapped = tree(leaf(_2878), leaf(_2874)),
dif(_2906, _2874),
dif(_2918, _2878) ;
Tree = tree(leaf(_2122), tree(leaf(_2128), leaf(_2134))),
Swapped = tree(tree(leaf(_2134), leaf(_2128)), leaf(_2122)) ;
Tree = tree(leaf(_2922), tree(leaf(_2932), leaf(_2936))),
Swapped = tree(tree(leaf(_2936), leaf(_2932)), leaf(_2922)),
dif(_2974, _2932),
dif(_2986, _2936) ;
Tree = tree(leaf(_2690), tree(leaf(_2700), leaf(_2704))),
Swapped = tree(tree(leaf(_2700), leaf(_2704)), leaf(_2690)),
dif(_2732, _2690) ;
Tree = tree(tree(leaf(_2122), leaf(_2128)), leaf(_2134)),
Swapped = tree(leaf(_2134), tree(leaf(_2128), leaf(_2122))) ;
Tree = tree(tree(leaf(_2934), leaf(_2938)), leaf(_2942)),
Swapped = tree(leaf(_2942), tree(leaf(_2938), leaf(_2934))),
dif(_2980, _2934),
dif(_2992, _2938) ;
Tree = tree(tree(leaf(_2702), leaf(_2706)), leaf(_2710)),
Swapped = tree(leaf(_2710), tree(leaf(_2702), leaf(_2706))),
dif(_2738, _2710) ;
Tree = tree(leaf(_2122), tree(leaf(_2128), tree(leaf(_2134), leaf(_2140)))),
Swapped = tree(tree(tree(leaf(_2140), leaf(_2134)), leaf(_2128)), leaf(_2122)) ;
Tree = tree(leaf(_2970), tree(leaf(_2980), tree(leaf(_2990), leaf(_2994)))),
Swapped = tree(tree(tree(leaf(_2994), leaf(_2990)), leaf(_2980)), leaf(_2970)),
dif(_3042, _2990),
dif(_3054, _2994) ;
Tree = tree(leaf(_2738), tree(leaf(_2748), tree(leaf(_2758), leaf(_2762)))),
Swapped = tree(tree(tree(leaf(_2758), leaf(_2762)), leaf(_2748)), leaf(_2738)),
dif(_2800, _2748) ;
Tree = tree(leaf(_2724), tree(leaf(_2734), tree(leaf(_2744), leaf(_2748)))),
Swapped = tree(tree(leaf(_2734), tree(leaf(_2744), leaf(_2748))), leaf(_2724)),
dif(_2776, _2724) .
(For whatever it's worth, the canonical definition of swap is much shorter and simpler than yours. Two clauses are enough.)
Bad usage of dif/2
First some remarks on the goal dif(B1, leaf(_)). With this you intend to express that it should only be true if B1 is not a leaf. But what you said is that B1 should be different to a very particular leaf structure whose argument does not occur anywhere else. In other words, there is no term for B1 that makes this goal fail.
(Both Scryer and SWI have here a bug with the anonymous variable. So let's use _A instead.)
?- B1 = leaf(2), dif(B1, leaf(_A)).
B1 = leaf(2), dif:dif(leaf(2),leaf(_A)).
That is certainly not what you intend. What you meant was that this dif should be true for all _A. Or otherwise, that the functor of B1 must be different to leaf/1. There is no common way to express this idiomatically. But in your case, just consider which trees are not leaves! Certainly, they must look like tree(_,_). So you can replace that goal and all others by B1 = tree(_,_).
Mirroring a tree
Then for your definition of swap/2: It fails for swap(leaf(1),T). That might give you a clue. In general it is very often an error to try to specialize a program into too many separate cases. Instead, try to keep it as simple as possible. For that take the definition of a tree as a starting template, and fill in the remainder:
is_tree(leaf(_)).
is_tree(tree(L, R)) :-
is_tree(L),
is_tree(R).
% Version 0, too general w.r.t. the second argument, but otherwise fine
swap_v0(leaf(_), _).
swap_v0(tree(L,R), _) :-
swap_v0(L, _),
swap_v0(R, _).
Counterexample:
?- swap_v0(leaf(_), anything).
true. % unexpected
Evidently, this definition is too general, this anything is pointless. So we need to specialize the program. Let's do this very slowly:
swap_v1(leaf(E), leaf(E)).
swap_v1(tree(L,R), tree(_,_)) :-
swap_v1(L, _),
swap_v1(R, _).
Still too general, I will leave the rest to you.
Enumerating infinite answers/solutions
Prolog is very good at enumerating one infinite set that is described with infinitely many answers:
?- length(L, N).
L = [], N = 0
; L = [_A], N = 1
; L = [_A,_B], N = 2
; L = [_A,_B,_C], N = 3
; L = [_A,_B,_C,_D], N = 4
; L = [_A,_B,_C,_D,_E], N = 5
; ... .
It is only because of the finite space limit here on SO that we cannot have the entire sequence of answers. (Just kidding, it's because we have finite machines, always the cheap ones.) But just tell me a number and I will tell you were this number will appear. That's essentially what a fair enumeration is about.
But now consider that we want to have one further list:
?- length(L, N), length(K, M).
L = [], N = 0, K = [], M = 0
; L = [], N = 0, K = [_A], M = 1
; L = [], N = 0, K = [_A,_B], M = 2
; L = [], N = 0, K = [_A,_B,_C], M = 3
; L = [], N = 0, K = [_A,_B,_C,_D], M = 4
; L = [], N = 0, K = [_A,_B,_C,_D,_E], M = 5
; ... .
So here we have two infinite sets but only one is enumerated in a fair manner. That is the problem with chronological backtracking. We need to reformulate such queries in such a manner that only a single infinite sequence of answers will be produced.
Same problem with enumerating is_tree/2. Except that here it is a bit more confusing if you attempt to follow Prolog's execution step-by-step. Don't try it, yes there are tracers out there, but you will not understand this with the help of them. Instead, try to find some size-like norm such that for each such size, Prolog will enumerate all corresponding trees with finitely many answers. Like the number of leaves. Or, even better the list of all leaves. That is, for each such list, Prolog will enumerate all corresponding trees. Here is such a definition:
tree_leaves(T, Es) :-
Es = [_|Ls],
phrase(tree(T, Ls,[]), Es).
tree(leaf(E), Ls,Ls) --> [E].
tree(tree(L,R), [_|Ls0],Ls) -->
tree(L, Ls0,Ls1),
tree(R, Ls1,Ls).
Now all trees can be enumerated like so:
?- length(Es, N), tree_leaves(T, Es).
Es = [_A], N = 1, T = leaf(_A)
; Es = [_A,_B], N = 2, T = tree(leaf(_A),leaf(_B))
; Es = [_A,_B,_C], N = 3, T = tree(leaf(_A),tree(leaf(_B),leaf(_C)))
; Es = [_A,_B,_C], N = 3, T = tree(tree(leaf(_A),leaf(_B)),leaf(_C))
; Es = [_A,_B,_C,_D], N = 4, T = tree(leaf(_A),tree(leaf(_B),tree(leaf(_C),leaf(_D))))
; Es = [_A,_B,_C,_D], N = 4, T = tree(leaf(_A),tree(tree(leaf(_B),leaf(_C)),leaf(_D)))
; Es = [_A,_B,_C,_D], N = 4, T = tree(tree(leaf(_A),leaf(_B)),tree(leaf(_C),leaf(_D)))
; Es = [_A,_B,_C,_D], N = 4, T = tree(tree(leaf(_A),tree(leaf(_B),leaf(_C))),leaf(_D))
; Es = [_A,_B,_C,_D], N = 4, T = tree(tree(tree(leaf(_A),leaf(_B)),leaf(_C)),leaf(_D))
; Es = [_A,_B,_C,_D,_E], N = 5, T = tree(leaf(_A),tree(leaf(_B),tree(leaf(_C),tree(leaf(_D),leaf(_E)))))
; ... .
Test your code
With tree_leaves/2 you can now also test your definition of swap/2! The following must never succeed
?- any(Es), tree_leaves(T, Es), reverse(Es, EsR),
\+ ( swap(T, TS),
tree_leaves(TS, EsS),
EsS == EsR
).
I am trying my hand in writing a relational prolog program that manages a key, value store. The initial code is taken from some lecture slides i found on the internet (http://people.eng.unimelb.edu.au/pstuckey/book/course.html -- see: using data structure slides).
newdic([]).
addkey(D0,K,I,D) :- D = [p(K,I)|D0].
delkey([],_,[]).
delkey([p(K,_)|D],K,D).
delkey([p(K0,I)|D0],K,[p(K0,I)|D]) :-
dif(K, K0), delkey(D0,K,D).
This code allows adding more than one value with the same key -- which, is fine with me. However, it also adds the same key, value pair twice, e.g.
?- newdic(D), addkey(D, a, 1, D2), addkey(D2, a, 1, D3), lookup(D3, a, X).
D = [],
D2 = [p(a, 1)],
D3 = [p(a, 1), p(a, 1)],
X = 1
D3 includes p(a,1) twice.
To ensure that this doesn't happen i added the following code; and to ensure that backtracking doesn't find the alternative addkey clause, I added a cut in the end of the first clause.
Is this fair game for a purely relational program -- or are the better ways to ensure that no duplicate key,value pairs are added --without the use of a cut.
newdic([]).
addkey(D0,K,I,D0) :- lookup(D0, K, I), !. % if the key already do nothing
addkey(D0,K,I,D) :- D = [p(K,I)|D0].
delkey([],_,[]).
delkey([p(K,_)|D],K,D).
delkey([p(K0,I)|D0],K,[p(K0,I)|D]) :-
dif(K, K0), delkey(D0,K,D).
this leads to the following:
?- newdic(D), addkey(D, a, 1, D2), addkey(D2, a, 1, D3), lookup(D3, a, X).
D = [],
D2 = D3, D3 = [p(a, 1)],
X = 1.
No, more solutions are available -- the program returns immediately.
any suggestions are much appreciated,
Daniel
Note: as an aside: that if i add for the same key different values, the cut does allow to backtrack to identify the second value for the same key:
?- newdic(D), addkey(D, a, 1, D2), addkey(D2, a, 1, D3), addkey(D3, a, 2, D4), lookup(D4, a, X).
D = [],
D2 = D3, D3 = [p(a, 1)],
D4 = [p(a, 2), p(a, 1)],
X = 2 ;
D = [],
D2 = D3, D3 = [p(a, 1)],
D4 = [p(a, 2), p(a, 1)],
X = 1.
SWI Prolog has library predicates for dealing with key-value pairs and associations. I haven't looked at them closely to see what might match your situation, but something to consider.
If you want to roll your own solution, you could write addkey/4 out recursively and maintain the relational behavior:
addkey([], K, V, [p(K,V)]). % Add to empty dict
addkey([p(K,V)|T], K, _, [p(K,V)|T]). % Don't add
addkey([p(K,V)|T], Kadd, Vadd, [p(K,V)|TK]) :-
dif(Kadd, K),
addkey(T, Kadd, Vadd, TK).
This implementation adds if the key is unique. It ignores the addition and yields the same dictionary back if you try the same key even with different a value (which is usually how a dictionary of key-value pairs behaves). You can enhance it for the uniqueness of the key-value pair pretty easily. Of course, the Prolog you're using would need to include dif/2, or you'd need to roll your own dif/2. :)
You can use if-then-else instead of cut:
addkey(D0,K,I,D0) :-
( lookup(D0, K, I) ->
D = D0 % if the key already [exists] do nothing
; D = [p(K,I)|D0] ).
I am trying to solve a problem where I need to evaluate the value of a binary expression tree.
tree_calc(Tree, Eval)
where Eval should hold the final result and Tree must be in the form:
tree(LeftNode, Operator, RightNode)
If I create the tree function as per the form above, how am I supposed to pass the results of the calculations back up the recursion if there isn't an empty variable to store the results?
My understanding is that an extra variable is always needed to store the result in.
Apologies in advance as I am sure I am misunderstanding something basic.
Thanks for your help.
In this context, tree isn't what you are calling a function, nor is it what Prolog would refer to as a predicate. tree(LeftNode, Operator, RightNode) is just a term that is used as a structure to represent the tree. So, for example, (2 + 3) * 4 would be represented by, tree(tree(2,+,3), *, 4). You would call your predicate with tree_calc(tree(tree(2,+,3),*,4), Eval) and expect that query to yield, Eval = 20. The term, tree/3 doesn't carry results in this case.
To give an example of how to access tree/3 in a predicate, here's a simple predicate that evaluates the simplest tree (so there's no recursion to tree leaves):
tree_calc(tree(L, Op, R), E) :-
% Neither L or R are of the form `tree/3`
compute(Op, L, R, E).
compute(+, L, R, E) :- E is L + R.
compute(*, L, R, E) :- E is L * R.
compute(-, L, R, E) :- E is L - R.
compute(/, L, R, E) :- E is L / R.
You can generalize compute/4:
compute(Op, L, R, E) :-
Exp =.. [Op, L, R],
E is Exp.
And you can call it like so:
| ?- tree_calc(tree(2,+,3), Eval).
Eval = 5
yes
For your more general case, you'll need to check L and R to see if they are a tree/3 structure themselves and recursively call tree_calc recursively if so.
Prolog is good at matching term patters. So if you check unification L = tree(LL, Op, LR) and it succeeds, that means L is a tree with left branch LL, operation Op, and right branch LR. You can play with this behavior at the Prolog prompt to see how it works:
| ?- Tree = tree(2, +, 3), Tree = tree(L, Op, R).
L = 2
Op = (+)
R = 3
Tree = tree(2,+,3)
yes
| ?- Tree = tree(2,+,tree(3,*,4)), Tree = tree(L, Op, R).
L = 2
Op = (+)
R = tree(3,*,4)
Tree = tree(2,+,tree(3,*,4))
yes
| ?- Tree = tree(2,+,tree(3,*,4)), Tree = tree(L, Op, R), R = tree(LR, OpR, RR).
L = 2
LR = 3
Op = (+)
OpR = (*)
R = tree(3,*,4)
RR = 4
Tree = tree(2,+,tree(3,*,4))
yes
| ?-
I have the following prolog code. The link predicate refers to another file containing various links such as:
link(b,brown,j)
I am using the member predicate to attempt to control the looping in this route program. The idea is if I have been to a certain position before, the program will not try to go down that route.
However, when I try to trace the program to see where it is going wrong, when it checks to see if the position is a member in the positions list, the first position is already in the list so the program always tries another route after that point when it shouldn't. Anyone know how to fix this?
member(X,[X|_]).
member(X,[_|Xs]):- member(X,Xs).
route(X,X,[X],_).
route(X,Z,[X|Path],Positions):-
link(X,Colour,Y),
\+member([Y,Colour],Positions),
route(Y,Z,Path,[[Y,Colour]|Positions]),
!.
Some minor comments first: You do not need that cut at all. If you really want to restrict the predicate to exactly one answer, do it at the top using once/1. That is not only conceptually cleaner, it is even more efficient.
The other problem you had is related to Prolog's unsafe negation. If you, accidentally as you did, hand over a goal that is too general, the negation will always fail. In other words: negation is next-to-broken in Prolog. There are two ways out: Either produce an error for such cases or simply use a better definition like non_member/2.
Let's see what would have happened with non_member/2 in place:
link(b,brown,j).
route(X,X,[X],_).
route(X,Z,[X|Path],Positions):-
link(X,Colour,Y),
% \+member([Y,Colour],Positions),
non_member([Y,Colour],Positions),
route(Y,Z,Path,[[Y,Colour]|Positions]).
non_member(E, Es) :-
maplist(dif(E), Es).
?- route(X,Y,Path,Rs).
Y = X, Path = [X]
; X = b, Y = j, Path = "bj", Rs = []
; X = b, Y = j, Path = "bj", Rs = [_A],
dif([j,brown],_A)
; X = b, Y = j, Path = "bj", Rs = [_A,_B],
dif([j,brown],_A), dif([j,brown],_B)
; X = b, Y = j, Path = "bj", Rs = [_A,_B,_C],
dif([j,brown],_A), dif([j,brown],_B), dif([j,brown],_C)
; X = b, Y = j, Path = "bj", Rs = [_A,_B,_C,_D],
dif([j,brown],_A), dif([j,brown],_B), dif([j,brown],_C),
dif([j,brown],_D)
; X = b, Y = j, Path = "bj", Rs = [_A,_B,_C,_D,_E],
dif([j,brown],_A), dif([j,brown],_B), dif([j,brown],_C),
dif([j,brown],_D), dif([j,brown],_E)
; ... .
So all answers describe the same Path = "bj" (short form for [b,j]). But the last argument now is a list of elements that all must be different to [j,brown]. So the best would have been:
route(X, Y, Path) :-
route(X, Y, Path, []).
And here is an alternate definition reusing path/4. I am not really sure what you mean by these colors. Nevertheless:
clink(X-_, Y-Color) :-
link(X, Color, Y).
route(X, Y, Path) :-
path(clink, Path, X-none, Y-_).
or even shorter using library(lambda):
route(X, Y, Path) :-
path(\ (Xl,_)^(Yl^C)^clink(Xl,C,Yl), Path, X-none, Y-_).