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.
Related
This is my code:
% A The first link as a predicate
link(1,2).
link(2,3).
link(3,4).
link(3,6).
link(6,7).
link(6,5).
So what we did with the path predicate is check from a given starting point check if there exists a path from that point to the goal (which is defined at the top). This gives the correct outcome for all possible values.
What I need to do now is, I know there is a valid path from 1 to the goal, my path() predicate told me so, now i need to return a list of nodes that shows the that path to the goal, so with using path(L), path([2,3,6,5]) is true.
If I understand your problem statement, you
Have a directed graph (a digraph) defined by link(From,To).
Wish to be able to traverse that digraph from some origin node to some destination node and identify the path[s] between the 2 nodes.
This is a pretty straightforward problem that doesn't require assert/1 or retract/1.
A common pattern in Prolog programming is the use of helper predicates that carry extra arguments that track the persistent state required to accomplish the task at hand.
Graph traversal, as an algorithm, is pretty easy (and nicely recursive):
You can travel from node A to node B if nodes A and B are directly connected, or
You can travel from node A to node B if node A is connected to some other node X such that you can travel from node X to node B.
The trick here is that you need to track what nodes you've visited (and their order), and you'd want to do that anyway, so that you can detect cycles in the graph. Trying to traverse a cyclic graph like this::
a → b → c → b
leads to infinite recursion unless you check to see whether or not you've already visited node b.
That leads pretty direction to an implementation like this:
A traverse/3 predicate, traverse(Origin, Destination,Path), and,
A traverse/4 helper predicate, traverse(Origin,Destination,Visited,Path).
You can fiddle with it at https://swish.swi-prolog.org/p/oZUomEcK.pl
link(1,2).
link(2,3).
link(3,4).
link(3,6).
link(6,7).
link(6,5).
% ---------------------------------------------------------------------------
%
% traverse( Origin, Destination, ReversePath )
%
% traverse/3 traverses a directed graph defined by link(From,To).
% The path taken is listed in reverse order:
% [Destination, N3, N2, N1 , Origin]
%
% ---------------------------------------------------------------------------
traverse(A,B,P) :- % to traverse a graph
traverse(A,B, [], P) % - invoke the helper, seeding the visited list with the empty list
. %
% ---------------------------------------------------------------------------
% traverse( Origin, Destination, Visited, ReversePath )
% ---------------------------------------------------------------------------
traverse( A , B , V , [B,A|V] ) :- % Traversal of a graph from A to B,
link(A,B) % - succeeds if there exists an edge between A and B.
. %
traverse( A , B , V , P ) :- % otherwise, we can get from A to B if...
link(A,X) , % - an edge exists between A and some node X
\+ member(X,V) , % - that we have not yet visited,
traverse(X,B,[A|V],P) % - and we can get from X to B (adding A to the list of visited nodes
. %
Once you have that, invoking traverse/3 with all arguments unbound
?- traverse(A,B,P) .
results in finding all paths in the graph via backtracking.
If you want to know all the paths in the graph, beginning at a specific origin node, invoke it with the origin argument bound:
?- traverse(1,B,P) .
And if you want to know if two specific nodes are connected, invoke it with both origin and destination bound:
?- traverse(1,5,P) .
Note: because we're building the list of visited nodes by prepending them to the list of visited nodes, the path thus build is in reverse (destination-first) order. If you want the path in proper (origin-first) order, just use reverse/2 in the main predicate:
traverse(A,B,P) :- traverse(A,B, [], RP ), reverse(RP,P) .
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) .
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!
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).
(.(.(..)))
(.((..).))
((..)(..))
((.(..)).)
(((..).).)
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.