Prolog - List concatenation in Trees - prolog

I have to write a predicate ListInTree(T,X) which is true when T is a tree with a list in each node, and X is the concatenation of all the lists (assuming to visit in Pre-order).
I really can't understand how to use the recursion to visit all the tree.
Thanks

You do not indicate what tree you are after, so I have to guess. The best in this case is to use a DCG, for grammars are built to model concatenation in the most natural manner possible:
seq([]) -->
[].
seq([E|Es]) -->
[E],
seq(Es).
flattened(empty) -->
[].
flattened(node(Xs, L, R)) -->
seq(Xs),
flattened(L),
flattened(R).
tree_flattened(T, Es) :-
phrase(flattened(T), Es).

For the sake of example, let us assume the following representation for a tree:
The atom nil represents the empty tree.
The structure tree/3 represents a non-empty tree tree( Left , Right , Payload ) where Left and Right represent (respectively and recursively) the left and right subtrees, and Payload is the payload for the node: in your case, a list.
Many/Most recursive problems have 1 or 2 "special cases" and the more general case. This is no different:
The special case is that of the empty tree: flattening it produces the empty list.
The general case is that of a non-empty tree: flatting it consists of the following steps:
Flatten the left subtree to produce a list
Flatten the right subtree to product a list
The result is that obtained by the concatenation of
the flattened left subtree
the current node's payload
the flattened right subtree
The Prolog code to accomplish this is pretty much identical to the English description above:
flatten_tree( nil , [] ) . % flattening the empty tree yields an empty list, n'est-ce-pas?
flatten_tree( tree(Left,Right,Payload) , Result ) :- % flattening a non-empty tree consists of
flatten_tree( Left , Prefix ) , % - flattening the left subtree,
flatten_tree( Right , Suffix ) , % - flattening the right subtree,
concatenate( Prefix , Payload , Suffix , Result ) % - concatenating the three parts
. % - easy!
concat( Xs, Ys , Zs , Rs ) :-
append(Xs,Ys,T1) ,
append(T1,Zs,Rs)
.
One might note that another approach might be to use findall/3 and append/2 (if you're using SWI prolog).
First you need a predicate to visit the tree via backtracking:
visit( tree(L,_,_) , P ) :- visit( L , P ) . % visit the left subtree
visit( tree(_,_,P) , P ) . % visit the current node
visit( tree(_,R,_) , P ) :- visit( R , P ) . % visit the right subtree
Feel free to rearrange the order of the clauses to get the ordering you'd like. Once you have that, flattening the tree is trivial:
flatten_tree( Tree , List ) :-
findall( X, visit(Tree,X) , Xs ) ,
append(Xs,List)
.

Related

Prolog - Check if two binary trees are equivalent

I would like to know how to check if two binary trees are equivalent in SWI-Prolog.
I tried:
equivalent(nil, nil).
equivalent(t(N,L1,R1), t(N,L2,R2)):- equivalent(L1,L2), equivalent(R1,R2).
but it does not work.
I assume that by "equivalence", you mean that two trees are equivalent if they each contain the same ordered set of data nodes, with possibly different root nodes.
To test for that sort of equivalence requires either:
Traversing the trees in parallel and depth-first and comparing each node, or
Flattening each tree into an ordered list (the worst-case, degenerate form of a binary tree, where the nodes are inserted in order), and then comparing the two lists.
I would suggest the latter approach, because the implementation is much simpler.
Given a binary tree t(Payload,Left_Children,Right_Children) where the atom nil indicates the empty tree, flattening a binary tree into a linked list is as easy as this:
flatten( nil , [] ) .
flatten( t(P,L,R) , Ps ) :-
flatten(L,Ls),
flatten(R,Rs),
append(Ls,[P|Rs],Ps)
.
And comparing two trees for equivalence is as easy as
equivalent(T1,T2) :- flatten(T1,L), flatten(T2,L) .
The two trees are equivalent if the both flatten into the same list.
Another, perhaps simpler/more performant method of flattening a binary tree uses a predicate that visits each node in order and uses findall/3 to coalesce that into a list.
Visiting nodes in order is easy. Beginning with the root node,
Recursively visit the left subtree, then
Visit the current node, and finally
Recursively visit the right subtree
Something like this:
flatten(T,Ps) :- findall(P, visit(T,P), Ps ) .
visit( t(_,L,_) , P ) :- visit(L,P) .
visit( t(P,_,_) , P ) .
visit( t(_,_,R) , P ) :- visit(R,P) .

Checking if the second list is half the size of first list

I am a noob prolog programmer and facing a difficulty with one of the basic problems that have been given in the book where I am learning from. The question. The question basically asks us to write down a Prolog procedure that takes two lists as arguments, and succeeds if the first list is twice the size of the second list and the two lists start with the same element. The procedure should return false if the two lists are empty.
For example it should return true if we pass the query:
a2b([a,a,a,a],[a,b]).
and would fail with a query like:
a2b([a,a],[a,b,b,b]).
I don't know how to solve this problem recursively, any help would be appreciated. Thanks!
First, the request about lengths:
/* empty list fulfills request */
a2b_length([],[]).
/* non-empty: discard two elements of first list,
one of second list, and verify
remainder */
a2b_length([_,_|Q1],[_|Q2]) :-
a2b_length(Q1,Q2).
Now, we can add the requirement "starts by the same term and are non empty", and write the last clause:
a2b([X,_|Q1],[X|Q2]) :-
a2b_length(Q1,Q2).
Cute problem. It can be solved using the following code:
% fail of the first element of each list don't unify
% or if one or both lists are empty
a2b([First| List1], [First| List2]) :-
% calculate the length of the second list
% while traversing both lists in parallel
a2b_first(List2, 1, N, List1, Rest1),
% check that the length of the rest of the first
% list is equal to the length of the second list
a2b_second(Rest1, N).
a2b_first([], N, N, Tail1, Tail1).
a2b_first([_| Tail2], N0, N, [_| Tail1], Rest1) :-
N1 is N0 + 1,
a2b_first(Tail2, N1, N, Tail1, Rest1).
a2b_second([], 0).
a2b_second([_| Tail1], N) :-
M is N - 1,
a2b_second(Tail1, M).
Of course, there's a simpler (but not as fun to code!) solution:
% fail of the first element of each list don't unify
% or if one or both lists are empty
a2b([First| List1], [First| List2]) :-
length([First| List1], N1),
length([First| List2], N2),
N1 is 2 * N2.
The length/2 predicate is usually available either as a built-in predicate or as a library predicate.
For learning Prolog, studying the first solution is interesting. For example, it exemplifies how to take advantage of first-argument indexing and how to use accumulators for writing predicates that are tail-recursive (and thus space efficient).
Also, the first solution can be more efficient than the second solution. In the second solution, we always traverse both lists to the end to find their lengths. But, in the first solution, that is not always necessary.
Don't overthink things: just describe the solution and let Prolog sort it out.
The solution doesn't require counting or predicates other than its trivial self. It's all pattern matching. We have a special (terminating case), asserting that a list of length 2 is twice as long as a list of length 1 (which should be pretty obvious):
is_twice_as_long_as( [_,_] , [_] ) .
Then there is the general case, which asserts that given two lists of arbitrary length, the left is twice as long as the right IF we can (A) remove 2 items from the left, (B) remove 1 item from right, and recursively assert that their respective remainders are likewise twice as long:
is_twice_as_long_as( [_,_|A] , [_|B] ) :- is_twice_as_long_as( A , B ) .
Giving us the finished product:
is_twice_as_long_as( [_,_] , [_] ) .
is_twice_as_long_as( [_,_|A] , [_|B] ) :- is_twice_as_long_as( A , B ) .
Easy!
Edited to note the requirement that the two lists begin with the same element:
Depending on how that is interpreted...
this requires that the lists have a common head on each iteration:
is_twice_as_long_as( [A,_] , [A] ) .
is_twice_as_long_as( [A,_|L] , [A|R] ) :- is_twice_as_long_as( L , R ) .
this does the check for a common head just once::
is_twice_as_long_as( [A|As] , [A|Bs] ) :-
is_2x([A|As],[A|Bs]) .
is_2x( [_,_] , [_] ) .
is_2x( [_,_|L] , [_|R] ) :- is_2x( L , R ) .

Prolog - solving problems with lists

Hello I have to solve some prolog problems with lists but i can't figure it out how these work.
I have to add "1" after every even element in a list, and to make the difference of 2 lists.
I know this seems easy, in other language like java or c# i would make it very easy, but prolog it's giving me headaches.
Please help me :|
Edited to note the clarified problem statement ("even item" meaning the item's value is even (rather than the item's ordinal position within the list):
insert_one_after_even_items( [] , [] ). % if the source list is exhaused, we're done.
insert_one_after_even_items( [X|Xs] , [X,1|Ys] ) :- % otherwise,
0 is X mod 2 , % - if the number is even, prepend it and a 1 to the result list, and
insert_one_after_even_items( Xs , Ys ) % - recurse down.
. %
insert_one_after_even_items( [X|Xs] , [X|Ys] ) :- % otherwise,
1 is X mod 2 , % - if the number is odd, prepend it to the result list, and
insert_one_after_even_items( Xs , Ys ) % - recurse down.
. % Easy!
For your second problem, producing the difference between two lists, are you talking about set differences? If so, given two sets A and B, are you talking about the relative difference (all elements of A that do not exist in B), or the absolute difference (all elements of either A or B that do not exist in both sets)?
To solve the relative set difference problem (Find all members of A that do not also exist in B), you can use the built-in member/2 predicate:
relative_difference( [] , _ , [] ) . % if the source list is exhausted, we're done
relative_difference( [A|As] , Bs , R ) :- % if the source list is non-empty, and
member(A,Bs) , % - the current A is an element of B,
! , % - we insert a deterministic cut (no backtracking)
relative_difference( As , Bs , R ) % - and recurse down, discarding the current A
. %
relative_difference( [A|As] , Bs , [A|R] ) :- % if the source list is non-empty (and A is not an element of B due to the cut inserted earlier)
relative_difference( As , Bs , R ) % we simply add A to the result list and recurse down.
.
One thing you will note here: we are building the result list in all of these examples is built from a variable. The tail of the list is unbound (and passed as the new result to the next recursive call, where it either become a new list node or, at the very end, the empty list.
This has the effect of
building the list in order (rather than in reverse order).
if the result was bound on the initial call, unification against the expected result occurs item by item as the recursion proceeds, which means
execution is short-circuited when the first unification failure occurs.
If your prolog implementation doesn't have member/2 as a built in, it's easy enough to implement. Something like this ought to do it:
member(X,[X|T]) :- ! . % A hit! cut and succeed.
member(X,[_|T]) :- member(X,T) . % ... and a miss. Just recurse down on the tail.

Undefined procedure when procedure is defined

I am trying to define a simple binary search tree. It is stored in lists like so: [Key, Left Tree, Right Tree].
I believe I have done this but when I try to use bstadd on an existing tree I get the following error.
?- bstadd(19,[],T1), bstadd(9, T1, T2).
ERROR: bstadd/3: Undefined procedure: right/3
Exception: (8) right(9, [[], []], _G3233) ?
I have defined right with three arugments on line 8. What follows is my code:
% bstadd(Key, Tree, NewTree)
% add the element Key to the tree Tree and return an
% new tree as NewTree. Element in the left subtree L must be less than Key and
% elements in the right subtree R must be greater than Key. This means duplicates
% are not allowed in the binary search tree. Don’t put print statements in this
% predicate.
right(Key, [TreeKey|TreeTail], [TreeKey|NewTree]) :- grabtail(KEY, TreeTail, NewTree]).
grabtail(KEY, [TreeKey|_], [TreeKey|NewTree]) :- bstadd(KEY, TreeKey, NewTree).
bstadd(KEY, [], [KEY,[],[]]).
bstadd(KEY, [TreeKey|TreeTail], [TreeKey|NewTree]) :- KEY > TreeKey, grabtail(KEY, TreeTail, NewTree).
bstadd(KEY, [TreeKey|TreeTail], [TreeKey|NewTree]) :- KEY < TreeKey, right(KEY, TreeTail, NewTree).
% inorder(Tree)
% given a binary search tree Tree perform an inorder traversal of the
% Tree printing (use print(X) ) the value of each vertex inorder.
inorder([TreeHead|TreeTail]) :- inright(TreeTail), print(TreeHead), intail(TreeTail).
inright([_|TreeTail]) :- intail(TreeTail).
intail([TreeHead|_]) :- inorder(TreeHead).
Any and all insight is appreciated.
Always look what the systems says while loading your file. I am sure there was some kind of syntax error. In your case, right/3 contains a syntax error at the end. There is an unmatched closing ].
right(Key, [TreeKey|TreeTail], [TreeKey|NewTree]) :- grabtail(KEY, TreeTail, NewTree]).
^^^

Counting all of the even integers within a b-tree in Prolog

I want to write a program in Prolog that builds a list of all the even integers that reside in a b-tree.
This is what I've written so far. A predicate that counts all the elements in the tree. I don't know where to scratch.
Domains
element=integer
tree=a(tree,element,tree);void
list=integer*
Predicates
nondeterm count(tree,element)
nondeterm count_even(tree,list)
Clauses
count(a(void,Number,void),1).
count(a(Esq,_,Dreta),Counter) :-
count(Esq,Counter1),
count(Dreta,Counter2),
Counter=Counter1+Counter2+1.
Goal
count(a(a(void,1,void),5,a(a(void,4,void),1,a(void,4,void))),N).
Thanks a lot.
Dunno anything about Visual Prolog, but in normal Prolog, I'd do something like the following...
First, I'd denote an empty btree as the atom btree and represent a non-empty btree as a structure of arity 3, thus:
btree( Payload, LeftChildren, RightChildren )
where Payload is the data for the node (an integer apparently), with LeftChildren and RightChildren being the btrees representing, respectively, the left and right children of the current node.
Traversing the tree to count those nodes with even-valued nodes is simple. The public predicate has arity 2, accepting the [bound] btree structure to be examined, and a bound or unbound value representing the count of even items. It calls an internal, recursive "helper" predicate that walks a tree and develops the count.
count_even( T , N ) :- count_even( T , 0 , N ) .
The internal predicate is simple as well. Having arity 3, the first argument is the tree to be examined, the second is an accumulator and the third is the final count (which won't be unified until the very end). There are two possible cases.
If the tree is empty, we have the final count:
count_even( btree , N , N ) .
If the tree is non-empty, we examine the current node, then recursively walk the left and right child trees, thusly:
count_even( btree( V , L , R ) , T , N ) :-
is_even( V , X ) ,
T1 is T+X ,
count_even( L , T1 , T2 ) ,
count_even( R , T2 , N )
.
We also need a trivial helper to tell us whether a particular value is even or odd:
is_even( V , 1 ) :- 0 is V mod 2 , ! .
is_even( V , 0 ) .
It should be noted that the data structure you're using is not a b-tree, per se: it is a binary tree.
B-trees are something of a generalization of a height-balanced binary tree optimized for disk storage. Each node has a variable number of keys and a variable number of children (corresponding to the number of keys). For more information, see
http://en.wikipedia.org/wiki/B-tree
http://cis.stvincent.edu/html/tutorials/swd/btree/btree.html
http://www.dtic.upf.edu/~rramirez/TA/btrees.pdf
Here's a picture of a B-tree:
And a picture of a binary tree:
You have to check every node to see if it's even or odd and only count the ones that are even.
A simple modification to your program should do (however I'd do it a bit different):
element=integer
tree=a(tree,element,tree);void
list=integer*
Predicates
nondeterm count_even(tree,list)
Clauses
count_even(a(void,Number,void),Value):-
Value = 1 - Number mod 2.
count_even(a(Esq,Number,Dreta),Counter) :-
count_even(Esq,Counter1),
count_even(Dreta,Counter2),
count_even=Counter1 + Counter2 + 1 - Number mod 2.
I just count 1 - Number mod 2 which is 1 when the number is even and 0 otherwise.

Resources