Equating numbers of the same type? - recursion

I have four different node types.
leaf(Int)
node1(Leaf, Node1)
node2(Leaf, Node1, Node2)
node3(Leaf, Node1, Node2, Node3)
I'm looking to write a function, using mainly pattern matching, to check if we have the number of n nodes in a tree. For example, I run the function counter(Tree, c(1, 2, 1, 3)) would return true iff Tree has one leaf, two single nodes, one double nodes, and three triple nodes.
I'm trying to solve the problem in two different ways, but neither of them seem to be working.
The first method, is to use a helper function, where the helper function would go through Tree and counter the number of each type of node. Then simply run is on it.
The second method is to count down from tuple we check as soon we enter. Where we go from c(N1, N2, N3, N4) to c(N1, N2 - 1, N3, N4) if we hit a node with a single child.
The issue with the first method is, I'm trying to avoid using the unification function =, so any idea how I can go lower down the tree while updating the tuple in the helper function.
The issue with the second is that there is no way for me to know when it ends, as it could reach a leaf but I wouldn't be able to reach the other side of the tree to continue and relay that the tuple changed.
I figure the best way to get around this is the first one. Using a helper function and then trying to find the number of nodes in the tree by myself. I can believe that there are other methods to solve this, but this seems to be the most efficient.
Here's what my code for the first method looks like:
countNodes(leaf(_), c(N1, N2, N3, N4)) :-
c(N0 + 1, N1, N2, N3).
countNodes(node1(_, Node), c(N1, N2, N3, N4)) :-
countNodes(Node, c(N1, N2 + 1, N3, N4)).
countNodes(node2(_, Node1, Node2), c(N1, N2, N3, N4)) :-
countNodes(Node1, c(N1, N2, N3 + 1, N4)),
countNodes(Node2, c(N1, N2, N3 + 1, N4)).
And at that point it basically falls apart. I'm trying to add the count node twice, which means the further in we go, the worse it will get. Any ideas on how to rewrite it and avoid double counting when there are two or three children from a node?
Thank you, any help is appreciated :)

Starting from your code, I propose the following (caution: not tested)
countNodes(leaf(_), c(1, 0, 0, 0)).
countNodes(node1(_, Node), c(N1, N2, N3, N4)) :-
countNodes(Node, c(N1, N2a, N3, N4)),
N2 is N2a+1.
countNodes(node2(_, Node1, Node2), c(N1, N2, N3, N4)) :-
countNodes(Node1, c(N1a, N2a, N3a, N4a)),
countNodes(Node2, c(N1b, N2b, N3b, N4b)),
N1 is N1a+N1b,
N2 is N2a+N2b,
N3 is N3a+N3b+1,
N4 is N4a+N4b.
countNodes(node3(_, Node1, Node2, Node3), c(N1, N2, N3, N4)) :-
countNodes(Node1, c(N1a, N2a, N3a, N4a)),
countNodes(Node2, c(N1b, N2b, N3b, N4b)),
countNodes(Node3, c(N1c, N2c, N3c, N4c)),
N1 is N1a+N1b+N1c,
N2 is N2a+N2b+N2c,
N3 is N3a+N3b+N3c,
N4 is N4a+N4b+N4c+1.
As you can see, the case leaf is very simple: you only have to set the values 1, 0, 0 and 0.
For the other cases, you have to call countNodes recursively over subnodes. Next you can add the found values (using is) and adding +1 for the local node.

Related

Finding the binary tree height in Prolog

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.

Prolog recursively multiply

I'm trying to multiply two numbers in Prolog recursively i.e. 3*4 = 3+3+3+3 = 12.
My code is :
mult(0,Y,Y).
mult(X,Y,Z) :-
NewX is X-1,
Z is Y + mult(NewX,Y,Z).
but I keep either in an infinite loop or being told mult is not a function.
What you here constructed is a predicate. A predicate is not the same as a function in computer science, you can not write A is B + some_pred(C), or at least not as far as I know in ISO Prolog, and definitely not without adding some extra logic.
In order to pass values, one uses variables. We can thus call the mult/3 predicate recursively, and use a variable that will be unified with the result. We can then perform arithmetic with it, like:
mult(0, _, 0).
mult(X, Y, Z) :-
X1 is X - 1,
mult(X1, Y, Z1),
Z is Y + Z1.
Note that you can not reassign a (different) value to a variable. So if, like you did in the question, use Z twice, then given Y is not 0, this will fail.
The above is however still not sufficient, since it will produce a result, but then get stuck in an infinite loop since if it calls (eventually) mult(0, 4, Z) (4 is here just a value), there are two ways to resolve this: with the base case, and with the recursive case.
We thus need a "guard" for the second case, like:
mult(0, _, 0).
mult(X, Y, Z) :-
X > 0,
X1 is X - 1,
mult(X1, Y, Z1),
Z is Y + Z1.
We then obtain for example:
?- mult(14, 25, Z).
Z = 350 ;
false.
One can improve the speed of this mult/3 predicate by implementing a version with an accumulator. I leave this as an exercise.

Dijsktra worst-case complexity sequence of inputs

I am looking for a sequence of inputs for the Dijsktra algorigthm implemented with a regular heap, where Dijsktras actual complexity would be Θ((e+v)logv).
I know how to implement Dijsktra and how it works, I also understand that the most time consuming operations are adding a vertex to the heap and changing the distance of a vertex. However, I am not sure how to find a graph (sequence of graphs) that would be the worst case inputs for Dijkstra.
Also if you had any general tips on how to find a sequence of inputs for the worst case complexity, that would be helpful.
Let vertices be numbered from 1 to n and you want to find path from vertex 1 to vertex n. Let e[i][j] be length of edge, connecting i and j. Initially e[1][2] = e[2][3] = ... = e[n - 1][n] = 1. Now we iterate through the vertices from n - 2 to 1. In i-th vertex for each j in [i + 2, n] we make e[i][j] = e[i][i + 1] + e[i + 1][j] + 1.
Now we have full graph. In each iteration dijkstra will update O(n) vertices, so it's O(n ^ 2) = O(E) actions working in O(log n).
So final asymptotics will be O(n log(n) + E log(n))

Shortest keyboard distance typing

Can anyone help me with this problem?
We have a grid of MxN characters from some specific aplhabet, S={A,B,C,D} for example.
The cursor is positioned on (1,1) position, and we can move cursor using the arrow keys, up, down, left, right, and press enter to select the character ( just like selecting nick in old games ). What is minimum cost of operations where they are weighted same, (e.g. move right is equally costly as selecting the char) given some input string from aplhabet S? There can also be multiple occurences of the same character in the matrix.
Example:
alphabet S={A,B,C,D}
matrix :
ABDC
CADB
ABAA
and input string ADCABDA.
My incomplete solution would be:
Construct directed grid graph and find shortest path from 1,1 to end character, with inbetween characters similar to towns in TSP, and from optimal subpaths construct optimal final path using dynamic programming. Problem is that you could end with many possible end characters, and I totally have no idea how to construct longer optimal path from smaller optimal subpaths.
You should construct a graph with nodes something like this:
A1 A1 A1
A2 D1 C1 A2 B1 D1 A2
Start A3 D2 C2 A3 B2 D2 A3 End
A4 A4 B3 A4
A5 A5 A5
where there are edges connecting each node in a column to each node in the next column. Start is (1,1) and End is wherever. The edge weights are the "taxicab" distances between each pair of keys.
Now it's a fairly straightforward dynamic programming problem. You can start at either end; it's probably conceptually simpler to start at Start. Keep track of the minimum cost so far to reach each node.
You could use 3D dynamic programming, where each state is (x, y, l) - (x, y) representing current position and l representing what letter you are at.
To explain further. You start at position (0, 0, 0). First letter is "A". You can try all A's and we know that distance will be Manhattan distance (http://en.wikipedia.org/wiki/Taxicab_geometry). Solution for (0, 0, 0) would be minimum of all possibilities.
At each step repeat the above process. Note that importance of memorising each step. In the below sample code memo acts as function, you would use array in reality.
Here is sample pseudo-code:
f(x, y, l):
if memo(x, y, l) != -1:
return memo(x, y, l) # Check if already calculated.
if l == length(word):
return memo(x, y, l) = 0 # Ending condition.
memo(x, y, l) = inf
next_letter = word[l]
for each (x2, y2) in grid that contains next_letter:
distance = |x2 - x| + |y2 - y|
next_calc = f(x2, y2, l+1)
memo(x, y, l) = min(memo(x, y, l), distance + next_calc)
return memo(x, y, l)
Set all memo to -1, so we know that no states are calculated.
Solution is f(0, 0, 0).
Let me know which steps I need to clarify further.

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