Finding the binary tree height in Prolog - recursion

So I have a task to create a binary tree using the following facts that define each node with its two child nodes:
node(root, a, b).
node(a, c, d).
node(b, z, y).
node(c, e, f).
node(d, x, w).
node(e, g, h).
node(z, v, u).
node(u, t, s).
node(t, r, q).
I want to define the rule height(RootNode, Height) to calculate the height of the binary tree that
starts at the RootNode. The height of a tree is the longest distance (number of nodes) from
the root node to the farthest away leaf node. A leaf node is a node that doesn’t have any
children. The height of a leaf node is 1.
The code I currently have is:
node(root, a, b).
node(a, c, d).
node(b, z, y).
node(c, e, f).
node(d, x, w).
node(e, g, h).
node(z, v, u).
node(u, t, s).
node(t, r, q).
height(nil, 0).
height(RootNode, Height):-
node(RootNode, Left, Right),
height(Left, LH),
height(Right, RH),
Height is max(LH, RH) + 1.
At the moment, I'm really stuck and would love to know what happens to this code when it runs, why I've done this incorrectly and where I should look to improve further? Appreciate any help.

The problem with your code is that your base case requires that each leaf node exists in the database in the form node(Leaf, nil, nil) but according to your example leaf nodes are just nodes that appear as the second or third argument of a node/3 fact but does not appear as the first argument of another node/3 fact.
So you may fix your code by changing your base case:
instead of
height(nil, 0).
use
height(Leaf, 1):-
\+node(Leaf, _, _).
(note that the base case has height 1 as per your description)
Test case:
?- height(root,A).
A = 6 ;
false.
You may also "join" both clauses in a single one:
height(RootNode, Height):-
node(RootNode, Left, Right) *->
(height(Left, LH),
height(Right, RH),
Height is max(LH, RH) + 1) ; Height = 1.
test run:
?- height(root,A).
A = 6.

Related

DFS trees and DFS forests

I was learning about DfS trees from:
http://rosalind.info/glossary/algo-depth-first-search/
In the "Depth-first search in directed graphs" section if we add a node Z with no edges pointing towards it but only one edge from Z to C, then where would Z appear in the resulting DFS tree?
Would its edge from Z to C be considered a tree edge or a cross edge?
Thanks!
When you build the new DFS tree for the given question it will be obvious:
The current DFS tree for exploration of A to H is the same. Z is not part of it since it is not connected by any Edge to Z. Due to lexicographic order in selecting vertices, it won't be selected before A.
After visiting A to H, Z is not visited and those will be - in lexicographic order - selected for exploration. It will be a new Tree in the DFS forest.
Be aware that in the unidirectional case, this is only a DFS forest when you ignore the non-tree edges as shown in the sample.
The Terminology states that Cross Edges ... lead to a node that has already been completely explored. Z has an Edge to the previously explored C, those it's edge is a Cross Edge.
You should check this answer for yourself.
How the tree (or forest) looks and what type of edge ZC is depends on where the DFS is run from, and what nodes are chosen first. If the DFS visits Z before it visits C, then ZC will be a tree edge as it is the only and Z will be a part of a tree with multiple nodes. If DFS starts at Z, then there will be one tree with Z as the root node. However, if Z is only discovered once C has already been visited, then C must also have been finished (completely explored) because Z cannot be reached by any other nodes. Thus in this case, ZC is a cross edge and Z would be in a tree by itself.

Swapping binary trees in prolog

This is exercise 3.5 from Learn Prolog Now. They put it before explaining lists so I need a procedure that doesn't involve lists.
The task is to swap the leaves of nested binary trees. If the query is
swap(tree(tree(leaf(1), leaf(2)), leaf(4)), T).
the answer should be
T = (tree(leaf(4), tree(leaf(2), leaf(1))).
With
swap((X, Y), (Y, X)).
swap(tree(X, Y), T) :-
swap((X, Y), (Y, X)),
T = (Y, X).
I get
T = (leaf(4), tree(leaf(1), leaf(2))).
As you see the leaf(1) and leaf(2) didn't get swapped. I want some hints or even your procedure and it should work with any depth of the nodes. Thanks.
You have a base case swap a leaf, and a general case swap a tree!
For a leaf, nothing to do :
swap(leaf(X), leaf(X)).
When you swap a tree, you must swap its leaves too, so
swap(tree(X,Y), tree(Y1,X1)) :-
swap(X,X1),
swap(Y,Y1).

Out of local stack when applying recursion

The context, first. What I am trying to modelate with prolog are two separated graphs, both represent a group of friends, so in both of them I can put the relation friend(X,Y), and, because it's doesn't have sense the friendship isn't mutual in this model, I also put the relation friend(Y, X).
So this means that both graphs have bidirectional relationships between their elements.
For example:
friend(foo1, foo2).
friend(foo2, foo1).
friend(foo3, foo4).
friend(foo4, foo3).
In which foo1 is related with foo2, and the same goes for foo3 and foo4, but the first two are not related with the another two ones.
Because it is a group of friends, it also doesn´t have sense that in the same group of friends, two people of the same group aren't friends, so I am using recursion to determine if one person is friend of another.
definitivefriend(X, Z) :- friend(X, Z).
definitivefriend(X, Z) :- friend(X, Y), definitivefriend(Y, Z).
The problem I have is when I try to check if one person of one group is friend of a person of the other group. In other words, check if one element of of a graph is related with another element of the other graph.
Instead of getting false, which is the expected result, the compiler (SWI-Prolog, in this case), gives me an error of out of local stack.
I want to know how to solve this.
Edit
So thanks to CapelliC I have an approach of this problem. Because the main objective is complete, but there's a secondary problem I will describe it from now on.
These are the two graphs I am working with. Remember that I said before, both graphs are biredirectional.
Here's my program in prolog:
writeit :- write('Frienship').
definitivefriend(X, Z) :- friend(X, Z), friend(Z, X).
definitivefriend(X, Y) :- friend(X, Z), X #< Z, definitivefriend(Z, Y), Y \= X.
friend(amanda, ryan). % graph1 %
friend(ryan, amanda).
friend(ryan, lisa).
friend(lisa, ryan).
friend(bryan, ryan).
friend(ryan, bryan).
friend(sara, ryan).
friend(ryan, sara).
friend(sara, simone).
friend(simone, sara). % graph2 %
friend(sandra, jeff).
friend(jeff, sandra).
friend(betty, jeff).
friend(jeff, betty).
friend(jeff, antonia).
friend(antonia, jeff).
friend(jeff, oskar).
friend(oskar, jeff).
friend(jeff, leslie).
friend(leslie, jeff).
And here is some of the outputs I got
?- definitivefriend(amanda, ryan).
true . % It's correct, both nodes are neighbours %
?- definitivefriend(amanda, simone).
true . % It's correct, both nodes are in the same graph %
?- definitivefriend(ryan, simone).
true . % It's correct, same explanation as before %
?- definitivefriend(simone, amanda).
false. % It's wrong, expected result is true %
?- definitivefriend(ryan, jeff).
false. % It's correct, nodes are in different graphs %
?- definitivefriend(amanda, leslie).
false. % It's correct, same explanation as before %
?- definitivefriend(sandra, oskar).
false. % It's wrong, expected result is true %
?- definitivefriend(oskar, sandra).
false. % It's wrong, expected result is true %
?- definitivefriend(betty, oskar).
true . % It's correct, both nodes are in the same graph %
?- definitivefriend(oskar, betty).
false. % It's wrong, expected result is true %
As I said in the comments, even with some elements of the same graph (excepting the neighbour ones), definitivefriend gives me false. And are some cases when I execute definitivefriend(X, Y) I get true, but when I execite definitivefriend(Y, X) I get false.
I feel that you are not modelling in the right way, anyway this seems working (abusing of the suggestion by Jean-Bernard, +1)
definitivefriend(X, Y) :-
friend(X, Y),
friend(Y, X).
definitivefriend(X, Y) :-
friend(X, Z), X #< Z,
definitivefriend(Z, Y), Y \= X.
edit: this cannot work with your model. I can't see any other way than following Daniel suggestion (+1).
For your second definitivefriend rule, add a condition that X < Y. This will avoid cycles. Then simply add a rule for:
definitivefriend(X,Y) :- definitivefriend(Y,X)
As it is now, you could have:
definitivefriend(1,2) :- friend(1,3), definitivefriend(3,2)
definitivefriend(3,2) :- friend(2,1), definitivefriend(1,2)
Which leads to infinite recursion
The problem, basically, is cycles. Your graph is acyclic, but your code is not. Here's the question. Suppose I give the query :- definitivefriend(foo1, foo2).. What's to stop Prolog from expanding that like this:
definitivefriend(foo1, foo2)
:- friend(foo1, foo2), definitivefriend(foo2, foo2). % by clause 2
:- friend(foo1, foo2), friend(foo2, foo1), definitivefriend(foo1, foo2). % by clause 2
:- friend(foo1, foo2), friend(foo2, foo1), friend(foo1, foo2),
definitivefriend(foo2, foo2). % by clause 2
etc.
#Jean-Bernard Pellerin provides one useful way to prevent cycles, by forcing a total ordering. I don't think that's the right approach here, but I can't quite put my finger on why. However, one thing you can do is provide a visited list to check against and not re-enter nodes you've already been to. That code's going to look like this:
definitivefriend(X, Z) :- definitivefriend(X, Z, [X]).
definitivefriend(X, Y, Visited) :-
friend(X, Y), \+ memberchk(Y, Visited).
definitivefriend(X, Z, Visited) :-
friend(X, Y), \+ memberchk(Y, Visited),
definitivefriend(Y, Z, [Y|Visited]).

partially reconstruct information of function convoluted with boxcar kernel

the function (f) I want to reconstruct partially could look like this:
The following properties are known:
It consists only of alternating plateau (high/low).
So the first derivation is zero respectively undefined at the edges.
The function was convoluted with a kernel fulfilling the following conditions:
It is a boxcar function
Its center is at x=0
Its integral is 1.
I want to reconstruct only the positions of the edges of the original function (f) from the convolution result (c). So just these positions are of interest to me:
If the convolution kernel width (k) is less than the minimum plateau width (b, 40 in the example above) of f, c looks as follows:
(The width of the box car convolution kernel here is k=31.)
In that case it is easy to reconstruct the edge positions:
I look for (possibly broad) extrema, and in between to neighbours [e1_x, e1_y] and [e2_x, e2_y] (one of them is a minimum and one a maximum of course), I search the x0 fulfilling: c(x0) = (e1_y + e2_y) / 2.
The reconstructed edge positions look like that:
But if k > b my approach fails:
(k=57)
Is there a possibility to calculate the original edge positions in f, if g (and so k) and c are known, also for the k>b cases?

Bipartite connected graph proof

A friend presented me with a conjecture that seems to be true but neither of us can come up with a proof. Here's the problem:
Given a connected, bipartite graph with disjoint non-empty vertex sets U and V, such that |U|<|V|, all vertices are in either U or V, and there are no edges connecting two vertices within the same set, then there exists at least one edge which connects vertices a∈U and b∈V such that degree(a)>degree(b)
It's trivial to prove that there is at least one vertex in U with degree higher than one in V, but to prove that a pair exists with an edge connecting them is stumping us.
For any edge e=(a,b) with a∈U and b∈V, let w(e)=1/deg(b)-1/deg(a). For any vertex x, the sum of 1/deg(x) over all edges incident with x equals 1, because there are deg(x) such edges. Hence, the sum of w(e) over all edges e equals |V|-|U|. Since |V|-|U|>0, w(e)>0 for som edge e=(a,b), which means that deg(a)>deg(b).
Prove it by contradiction, i.e. suppose that deg(a) ≤ deg(b) ∀(a,b)∈E, where E is the edgeset of the graph (with the convention that the first element is in U and the second in V).
For F⊆E, designate by V(F) the subset of V which is reachable through edgeset F, that is:
V(F) = { b | (a,b)∈F }
Now build an edgeset F as follows:
F = empty set
For a ∈ U:
add any edge (a,b)∈E to F
Keep adding arbitrary edges (a,b)∈E to F until |V(F)| = |U|
The set V(F) obtained is connected to all nodes in U, hence by our assumption we must have
∑a∈U deg(a) ≤ ∑b∈V(F) deg(b)
However, since |U|=|V(F)| and |U|<|V| we know that there must be at least one "unreached" node v∈V\V(F), and since the graph is connected, deg(v)>0, so we obtain
∑a∈U deg(a) < ∑b∈V deg(b)
which is impossible; this should be an equality for a bipartite graph.

Resources