Prolog - Check if two binary trees are equivalent - prolog

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) .

Related

Number Of Ways To Traverse a Binary Tree

Consider a binary tree of n nodes. For the sake of example consider the following tree:
1
/ \
2 3
/ \ / \
4 5 6 7
\
8
How many different ways can I fully traverse the tree starting from the root (top) node and only moving to un-visited nodes that are directly connected to ones that have already been visited (i.e. I can go from 1 to 2 to 4 but then to 3)?
You might have more luck asking on the Math Stack exchange.
You are asking for the number of linear extensions of the binary tree considered as a poset. Although I can see no general formula, one can solve this recursively as follows:
Find the number of ways of traversing the left and right subtrees (the empty tree is trivially traversed in 1 way). Call these T_L and T_R. Let #L and #R be the cardinality (size) of the left tree and right tree respectively. Then the number of ways of traversing the whole tree is
T_L * T_R * (#L + #R choose #L)
because we can traverse the left tree in T_L ways, the right tree in T_R ways (independent of how we traverse the right tree), and we can interleave the left and right trees in (#L + #R choose #L) ways.
In your example there are two ways of traversing the left tree, and three ways of traversing the right tree and (7 choose 3) is 35, so there are 2*3*35 = 210 ways of traversing the tree.
Programmatic verification of #deinst's answer, with Prolog:
traverse([], []) :- !.
traverse(F, [N|P]) :-
% select a frontier node from F
select(t(N,C), F, Rem),
% append all new accessible children to the frontier
append(C, Rem, NewF),
% traverse the remaining set
traverse(NewF, P).
tree(X) :-
X = t(1,[t(2,[t(4,[]), t(5,[])]),t(3,[t(6,[]), t(7,[t(8,[])])])]).
do :-
tree(X),
findall(P, (traverse([X], P), write_ln(P)), Ps),
length(Ps, L),
write_ln(L).
This does indeed return 210 possibilities, as suggested for your example tree.
?- do.
[1,2,4,5,3,6,7,8]
[1,2,4,5,3,7,8,6]
[1,2,4,5,3,7,6,8]
[1,2,4,3,6,7,8,5]
[1,2,4,3,6,7,5,8]
[1,2,4,3,6,5,7,8]
[1,2,4,3,7,8,6,5]
[1,2,4,3,7,8,5,6]
[1,2,4,3,7,6,8,5]
...
[1,3,2,7,6,4,8,5]
[1,3,2,7,6,4,5,8]
[1,3,2,7,6,5,8,4]
[1,3,2,7,6,5,4,8]
210
true.

Prolog - List concatenation in Trees

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)
.

Recursive similarity between trees according to the number of common subtrees in Prolog

I am stufying Prolog using SWI Prolog and I am finding many difficult with this code snippet that found if 2 binary trees have N common subtree (having the same root):
/* BASE CASE: T1 and T2 are two tree composed of only the root X so it is
TRUE that they have exactly one common subtree
*/
delta(tree(X,[]),tree(X,[]),1):- !.
/* RULE: T1 and T2 are DIFFERENT and are structured tree.
It is TRUE that T1 and T2 have N subtrees if it is TRUE that:
*/
delta(tree(X,RX),tree(X,RX1),N):- sons(RX,SX),
sons(RX1,SX)
subdelta(RX,RX1,N),
!.
/* Else whatever T1 and T2 it is true that they have 0 common tree
(here we are in the case that the previous delta\2 predicate are
boot failed)
*/
delta(_,_,0):- !.
subdelta([],[],1).
subdelta([T1|R1],[T2|R2], N):-
delta(T1,T2,N1),
subdelta(R1,R2, NR),
N is (1 + N1)*NR.
I think that the delta/3 predicate it is true if the first tree have N common subtrees with the second tree
He rappresent the tree in this way:
tree(F, LIST_OF_SUBTREES).
So for example this is a tree composed by a root X and two leaves u and v:
tree(x, [tree(u,[]), tree(v,[])])
I think that the delta/3 predicate it is declined into the 3 possible cases:
1) T1 and T2 are two tree composed of only the root X so it is TRUE that they have exactly one common subtree
**2) T1 and T2 are DIFFERENT and are structured tree that have more levels so it is TRUE that T1 and T2 have N subtrees if it is TRUE that: ?!?!
3) Else, if both the prevuous delta\2 predicate are failed, whatever T1 and T2 it is true that they have 0 common tree
I think that this interpretation is correct (I hope so...) but I have some difficulties to understand the second rule: what could be sons/2 predicate (it seems to me that this is note a SWI Prolog built in predicate and I have no its implementation on the slide where I am studyin)
What is for you? And what is it's logic?
Tnx
Andrea
Your interpretation of the three rules seems reasonable to me. For comparison, I would rephrase them as:
delta(T1, T2, 1) holds if T1 and T2 have the same value and are empty (leaf nodes).
delta(T1, T2, N) holds if T1 and T2 have N common subtrees.
delta(T1, T2, 0) holds if T1 and T2 have 0 common subtrees.
I'm unclear on why these cuts are necessary. I suppose they're green cuts, because a pair of trees can't have 1, N and 0 common subtrees simultaneously.
sons/2 is interesting. I could imagine it working a few different ways. One thing we know for sure is that if two trees have common subtrees, sons/2 should generate the same value; it must work that way because otherwise sons(RX, SX), sons(RX1, SX) wouldn't ever work. (Note that there's a missing comma on that line).
One question that remains is, does sons/2 work by generating all the subtrees, or just the nearest pair? It seems likely to me that it generates the nearest pair only, because subdelta/3 calls delta/3, leading to indirect recursion. If sons/2 generated all subtrees, this would result in unbounded recursion or at least a lot of unnecessary work. So I would bet that sons/2 looks like this:
sons(tree(_,Children), X) :- member(X, Children).
This suggests at least one case where delta/3 is going to do something more intelligent than one would expect at first blush: the case where T1 and T2 are reflections of each other. sons/2 of T1 and T2 will unify the left with the right and then the right with the left, so you'll get the maximal similarity from sharing subtrees but not exact structure.
What's most surprising to me about this is that delta/3 doesn't seem to be counting differences, it seems to be counting similarities. This isn't what one would expect from the name, but it follows from the implementation. And it's hard to imagine how one would count differences directly--what is the upper limit? With files, for instance, you can count the differences by saying, each line could be the same (0) or different (1) and then adding up the differences.
Hope this is on the right track and helps!

Code in Prolog generate all structurally distinct full binary trees with n node

generate all structurally distinct full binary trees with n leaves in Prolog.
The problem is given the number of leaves, output all distinct full binary trees.
'Full' here means any internal node must have two children, left and right.
To build all the trees through backtracking:
full_tree(Leaves, [LTree, RTree]):-
Leaves > 1,
TLeaves is Leaves-1,
between(1, TLeaves, LLeaves),
RLeaves is Leaves-LLeaves,
full_tree(LLeaves, LTree),
full_tree(RLeaves, RTree).
full_tree(1, '.').
This recursive procedure has a base case that unifies the second argument with '.' when number of leaves is 1.
The recursive step applies when the number of leaves is greater than 1. It splits this number in two non-zero new numbers which sum the number of leaves and calls itself to build the left and right branches.
Then this procedure will dump all trees to console:
dump_all_trees(Leaves):-
full_tree(Leaves, Tree),
dump_full_tree(Tree),
nl,
fail.
dump_all_trees(_).
dump_full_tree([LTree, RTree]):-
write('('),
dump_full_tree(LTree),
dump_full_tree(RTree),
write(')'),
!.
dump_full_tree(Leaf):- write(Leaf).
Test case:
?- dump_all_trees(4).
(.(.(..)))
(.((..).))
((..)(..))
((.(..)).)
(((..).).)

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