Prolog - writing successive numbers_ [duplicate] - math

This question already has an answer here:
Hanoi Tower(Towers of Hanoi)
(1 answer)
Closed 8 years ago.
My task is this: Make this hanoi program write a successive number before it writes each sentence.
The hanoi program is this:
hanoi(N):-move(N,left,middle,right).
move(0,_,_,_):- !.
move(N,A,B,C):- M is N-1, move(M,A,C,B), inform(A,B), move(M,C,B,A).
inform(A,B):- write('MOVING DISK FROM '), write(A),write(' TO '),write(B),nl.
And I want the output to look like this:
1: MOVING DISK FROM left TO middle
2: MOVING DISK FROM left TO right
3: MOVING DISK FROM middle TO right
4: MOVING DISK FROM left TO middle
5: MOVING DISK FROM right TO left
6: MOVING DISK FROM right TO middle
7: MOVING DISK FROM left TO middle

First consider using a DCG to describe the list of moves:
hanoi(N, Moves) :- phrase(moves(N,left,middle,right), Moves).
moves(0,_,_,_) --> [].
moves(N,A,B,C) --> { N #> 0, M #= N-1 }, moves(M,A,C,B), [A->B], moves(M,C,B,A).
This lets you separate the program logic from side-effects like printing results. Once you have a list of moves, it is easy to write them, for example with:
write_moves([], _).
write_moves([From->To|Ms], N) :-
format("~w: move disk from ~w to ~w\n", [N,From,To]),
N1 #= N + 1,
write_moves(Ms, N1).
Example query and its result:
?- hanoi(3, Moves), write_moves(Moves, 1).
1: move disk from left to middle
2: move disk from left to right
3: move disk from middle to right
4: move disk from left to middle
5: move disk from right to left
6: move disk from right to middle
7: move disk from left to middle
Moves = [ (left->middle), (left->right), (middle->right), ...].

A straight-forward approach would be to use a dynamic predicate representing the line number. Using assert/retract isn't real-time friendly, but it works fine for an application like this. I reformatted your working Hanoi code for readability, and I added the lines noted with comments:
% hanoi
%
:- dynamic(line/1). % Define a dynamic predicate "line"
hanoi(N) :-
assertz(line(1)), % Assert the first line as 1
move(N, left, middle, right).
move(0, _, _, _) :- !.
move(N, A, B, C) :-
M is N-1,
move(M, A, C, B),
inform(A, B),
move(M, C, B, A).
inform(A, B) :-
line(N), % get the current line number
NextN is N + 1, % next line number will be current one plus 1
retract(line(_)), % retract the old line number
assertz(line(NextN)), % assert the next line number for next time
write(N), % write the line number
write(': '), % and a delimiter
write('MOVING DISK FROM '),
write(A),
write(' TO '),
write(B),
nl.
There are other ways to generate successive numbers, such as the following simplest case.
sequence(1).
sequence(X) :- sequence(Y), X is Y + 1.
| ?- sequence(X).
X = 1 ? ;
X = 2 ? ;
X = 3 ? ;
X = 4 ?
In some cases, something like this can be integrated in with a predicate to give you sequence numbers. Since the hanoi predicate has a tree-like recursion, I found it easier to use an assertz mechanism.

Related

What is the exact meaning of the equal sign in Elixir?

I don't get what exactly means the equal sign in Elixir.
What is unclear is that it looks like a mix between assignment and a pattern matching operation.
iex(1)> x=4
4
iex(2)> y=5
5
iex(3)> 3=y
** (MatchError) no match of right hand side value: 5
iex(3)> y=3
3
iex(4)> y=x
4
I understand that in Elixir, the equals operator means to match the left side of the = sign to the the right side. First two lines make sense to me. x and y are unbound variables, hence they could match anything. They are bound as they match. Consequently, I understand the third line. You can't match 3 with 5.
Where I start to loose my head is why the hell the two last lines are executed without giving the same error. It looks like the equal sign is back to being an assignment operator only.
I've try to accept this behaviour as a fact without full understanding and tried to go further in the learning of the language. But as pattern matching is one of the core mechanism of Elixir, I'm constantly lock and feel I should go back to this original question. I will not go any further before I fully understand what exactly happens with the "=" sign and what is the logic.
The equals sign means: "try to fit the value of expression on the right to the shape on the left and assigning values accordingly". So left and right side are different and you cannot switch them. On the right side all variables have to be bound, because it is an expression. On the left side even if you use variables that are already bound they will be reassigned.
So first thing is that on the right you can have any expression your want:
{:error, :enoent} = File.open("foo")
but you can't have an expression on the left side:
iex(1)> File.open("foo") = {:error, :enoent}
** (CompileError) iex:1: cannot invoke remote function File.open/1 inside match
In case of
y=3
5=y # y gets evaluated to 3 and then you pattern match 3=5
and it fails. But you can do
y=3
y=5 # y gets reassigned.
On the left hand side you can only have "shape" which may be arbitrarly nested datastructure:
[a, b, %{"a" => {1, c}}] = [1, 2, %{"a" => {1, 2}]
# c is now assigned value of 2
So pattern matching is used to either destructure data or to assert some condition like
case File.open("foo") do
{:ok, contents} -> enjoy_the_file(contents)
{:error, reason} -> print_error(reason)
end
or if you want to assert that there is only one entity in the database instead of firstly asserting it exists and then that there is only one you can pattern match:
[entity] = Repo.all(query)
If you want to assert that the first value in a list is one, you can pattern match:
[1 | rest] = [1, 2, 3]
There are some gotchas when pattern matching. For example this:
%{} = %{a: "a"}
will match, because shape on the left side is a map and you don't require anything more so any map will match. However this won't match:
%{a: "a"} = %{}
because shape on the left says "give me a map with a key of atom :a.
If you would like to match on a variable you may write something like this:
a = 1
{a, b} = {2, 3}
but this will assign a the value 2. Instead you need to use pin operator:
a = 1
{^a, b} = {2, 3} #match fails
I wrote more about pin operator in this answer: What is the "pin" operator for, and are Elixir variables mutable?
Where I start to loose my head is why the hell the two last lines are executed without giving the same error. It looks like the equal sign is back to being an assignment operator only.
That's because a variable name on the left side is not matched by its value in Elixir. Instead, the variable is reassigned to the matching value on the right side.
This is different from Erlang where exactly what you expect happens:
1> X = 4.
4
2> Y = 5.
5
3> 3 = Y.
** exception error: no match of right hand side value 5
4> Y = 3.
** exception error: no match of right hand side value 3
5> Y = X.
** exception error: no match of right hand side value 4
To get the same behavior in Elixir, you need to use the "pin" operator on each variable you want to match by value on the left side:
iex(1)> x = 4
4
iex(2)> y = 5
5
iex(3)> 3 = y
** (MatchError) no match of right hand side value: 5
iex(3)> ^y = 3
** (MatchError) no match of right hand side value: 3
iex(3)> ^y = x
** (MatchError) no match of right hand side value: 4
Two cases:
1) Left hand side is placeholder/variable:
Whatever in right will get assigned
Example:
x = 5
y = x (y gets value 5)
x = y (x gets value 5)
2) Left hand side is value
Match with the right hand value/variable's value
Example:
5 = x (Error: as x is undefined)
x = 5
5 = x (5 matches with 5)
6 = x (Error: 6 is not matches with 5)

Writing a Recurrence Equation

I am confused on where the 2nd term [T(n) = 2T(n/2) + THETA(n)] is derived from when writing the recurrence equation for Merger Sort.
From the Coursera class, it was stated that the 2nd term is due to what occurs outside of the recursive calls. So my guess is because it is due to the 2 For Loops, each would go up to n/2, so the total would be counting to n:
function mergesort(m)
var list left, right
if length(m) ≤ 1
return m
else
middle = length(m) / 2
for each x in m up to middle
add x to left
for each x in m after middle
add x to right
left = mergesort(left)
right = mergesort(right)
result = merge(left, right)
return result
Any help would be appreciated.
Thanks
Yes, that's right. There's linear work done to iterate across the elements of the input list, distributing each element into either the left or right subarray. That accounts for the Θ(n) term in the recurrence.
Hope this helps!

Prolog query fails

This is supposed to calculate the sum of two lists. The lists can be of different size.
sum([],[],[]).
sum(A,[],A).
sum([],B,B).
sum([A|Int1],[B|Int2],[C|Int3]) :-
(
C =:= A + B
;
((C =:= A), B = [])
;
((C =:= B), A = [])
),
sum(Int1,Int2,Int3).
It seems to work correctly, except when trying to find the sum of two lists. Then it gives the following error:
ERROR: =:=/2: Arguments are not sufficiently instantiated
I don't see why. There's a recursive and a basis step, what exactly is not yet instantiated and how do I fix it?
[1] While your disjunctions in the last clause are -- to some extent -- conceptually correct, Prolog considers these disjunctions in sequence. So it first considers C =:= A + B. But either A or B can be the empty list! This is what causes the error you reported, since the empty list is not allowed to occur in a numeric operation.
[2] You need to use C is A + b (assignment) i.o. C =:= A + B (numeric equivalence).
[3] If you say [A|Int1] and then A = [], then this means that [A|Int1] is not (only) a list of integers (as you claim it is) but (also) a list of lists! You probably intend to check whether the first or the second list is empty, not whether either contains the empty list.
Staying close to your original program, I would suggest to reorder and change things in the following way:
sumOf([], [], []):- !.
sumOf([], [B|Bs], [C|Cs]):- !,
C is B,
sumOf([], Bs, Cs).
sumOf([A|As], [], [C|Cs]):- !,
C is A,
sumOf(As, [], Cs).
sumOf([A|As], [B|Bs], [C|Cs]):-
C is A + B,
sumOf(As, Bs, Cs).
For example:
?- sumOf([1,2,3], [1,-90], X).
X = [2, -88, 3]
Notice my use of the cut (symbol !) in the above. This makes sure that the same answer is not given multiple times or -- more technically -- that no choicepoints are kept (and is called determinism).
You should read a tutorial or a book. Anyway, this is how you add two things to each other:
Result is A + B
This is how you could add all elements of one list:
sum([], 0). % because the sum of nothing is zero
sum([X|Xs], Sum) :-
sum(Xs, Sum0),
Sum is X + Sum0.
And this is how you could add the sums of a list of lists:
sums([], 0).
sums([L|Ls], Sums) :-
sums(Ls, Sums0),
sum(L, S),
Sums is Sums0 + S.

Prolog infinite loop

I'm fairly new to Prolog and I hope this question hasn't been asked and answered but if it has I apologize, I can't make sense of any of the other similar questions and answers.
My problem is that I have 3 towns, connected by roads. Most are one way, but there are two towns connected by a two way street. i.e.
facts:
road(a, b, 1).
road(b, a, 1).
road(b, c, 3).
where a, b and c are towns, and the numbers are the distances
I need to be able to go from town a to c without getting stuck between a and b
Up to here I can solve with the predicates: (where r is a list of towns on the route)
route(A, B, R, N) :-
road(A, B, N),
R1 = [B],
R = [A|R1],
!.
route(A, B, R, N) :-
road(A, C, N1),
route(C, B, R1, N2),
\+ member(A, R1),
R = [A | R1],
N is N1+N2.
however if I add a town d like so
facts:
road(b, d, 10)
I can't get Prolog to recognize this is a second possible route. I know that this is because I have used a cut, but without the cut it doesn't stop and ends in stack overflow.
Furthermore I will then need to be able to write a new predicate that returns true when R is given as the shortest route between a and c.
Sorry for the long description. I hope someone can help me!
This is a problem of graph traversal. I think your problem is that you've got a cyclic graph — you find the leg a-->b and the next leg you find is b-->a where it again finds the leg a-->b and ... well, you get the picture.
I would approach the problem like this, using a helper predicate with accumulators to build my route and compute total distance. Something like this:
% ===========================================================================
% route/4: find the route(s) from Origin to Destination and compute the total distance
%
% This predicate simply invoke the helper predicate with the
% accumulator(s) variables properly seeded.
% ===========================================================================
route(Origin,Destination,Route,Distance) :-
route(Origin,Destination,[],0,Route,Distance)
.
% ------------------------------------------------
% route/6: helper predicate that does all the work
% ------------------------------------------------
route(D,D,V,L,R,L) :- % special case: you're where you want to be.
reverse([D|V],R) % - reverse the visited list since it get built in reverse order
. % - and unify the length accumulator with the final value.
route(O,D,V,L,Route,Length) :- % direct connection
road(O,D,N) , % - a segment exists connecting origin and destination directly
L1 is L+N , % - increment the length accumulator
V1 = [O|V] , % - prepend the current origin to the visited accumulator
route(D,D,V1,L1,Route,Length) % - recurse down, indicating that we've arrived at our destination
. %
route(O,D,V,L,Route,Length) :- % indirect connection
road(O,X,N) , % - a segment exists from the current origin to some destination
X \= D , % - that destination is other than the desired destination
not member(X,V) , % - and we've not yet visited that destination
L1 is L+N , % - increment the length accumulator
V1 = [O|V] , % - prepend the current origin to the visited accumulator
route(X,D,V1,L1,Route,Length) % - recurse down using the current destination as the new origin.

How would you code a program in Prolog to print numbers from 1 to 10 using recursion?

How would you code a program in Prolog to print numbers from 1 to 10 using recursion?
I've tried the following but it doesn't work, can you tell me why?
print_numbers(10) :- write(10).
print_numbers(X) :- write(X),nl,X is X + 1, print_numbers(X).
Your code is very close to working. The problem is that you cannot reuse X, once it is instantiated, it cannot be changed (see here for more details). Use a new variable, like this:
print_numbers(10) :- write(10), !.
print_numbers(X) :- write(X), nl, Next is X + 1, print_numbers(Next).
Adding the cut (!) to the end will prevent the interpreter from asking if you want to see more results.
?- print_numbers(1).
1
2
3
4
5
6
7
8
9
10
Yes
?-
print_from_1_to_10 :-
print_from_X_to_10(1).
print_from_X_to_10(X) :-
(
X > 10
->
fail
;
writeln(X),
NewX is X + 1,
print_from_X_to_10(NewX)
).
Been a seriously long time since I wrote any prolog but I'd probably do things just a little differently. Something like this, though I can't test it at the momment.
print_increasing_numbers(From, To):- From > To, !, write('ERROR: From > To').
print_increasing_numbers(To, To):- !, write(To).
print_increasing_numbers(From, To):- write(From),
nl,
Next is From + 1,
print_increasing_numbers(Next, To).
A key difference here is the !, or cut operation, which stops backtracking. If you don't include it then you will get a solution with the first clause when X is 10,but if you ask for a second solution it will backtrack and match the second clause as well. That would result in a much larger list of numbers than you want.
Just call defineXandY from terminal
defineXandY :-
print_one_to_ten(1,10).
print_one_to_ten(X,Y) :-
X<Y,
write(X),nl,
NewX is X+1,
print_one_to_ten(NewX,Y).

Resources