Prolog if then else logic (error: operator priority clash) - prolog

I'm new to prolog and doing so practice to pick it up. I'm confused at the moment with an error on line 5 saying Syntax error: Operator priority clash. This is probably due to the nesting of the logic, but I was wondering if there is a way to make this nesting work.
loopOver3(elt1, elt3, [H|T], sum):-
( =(elt1, elt2) =:= true ->
sum is sum + (elt1 + elt2),
; =(elt1, elt2) =\= false -> ( =(elt1, H) =:= true ->
sum is sum + (elt1 * H),
; =(elt1, H) =\= false -> ( =(elt2, H) =:= true ->
( \=(H, 0) =:= true ->
sum is sum + (100 / H)
)
)
)
)
loopOver3(elt1, elt3, T, sum).
Sudo code for what I'm trying to do:
for elt3 in list3:
if elt1 == elt2:
sum = sum + (elt1 + elt2)
else:
if elt1 == elt3:
sum = sum + (elt1 * elt3)
else:
if (elt2 == elt3) and (elt3 != 0):
sum = sum + (100 / elt3)

You have a bit of work to go to understand the concepts in Prolog. Your initial attempt is full of atoms (lowercase) rather than variables (uppercase). It's got mutability. You're thinking like Prolog has functions (it has predicates) that return values (they don't - they either succeed or fail).
I've made the assumption that you're peeling the first three values off of a list and then dropping the first item and recursing down.
So, if I have this list [1,2,1,2], I'd first be looking at [1,2,1] and then [2,1,2].
Or, in this longer example:
[1,2,1,2,2,1,1] => [1,2,1]
[2,1,2,2,1,1] => [2,1,2]
[1,2,2,1,1] => [1,2,2]
[2,2,1,1] => [2,2,1]
[2,1,1] => [2,1,1]
As soon as the list has only 2 elements I can then stop.
I'm assuming that each of the list of three values are your [Elt1, Elt2, Elt3].
To compute this we need to have an input list and an output sum, but to recurse down the list we need to have an accumulator to keep track of the current sum as we go. The first predicate is easy:
compute(List,Sum) :- compute(List,0,Sum).
Now, you have 5 predicates that we must match for.
the list containing 2 elements - we can return our accumulator
Elt1 = Elt2 then sum = sum + (elt1 + elt2)
Elt1 = Elt3 then sum = sum + (elt1 * elt3)
Elt2 = Elt3 and Elt3 \= 0 then sum = sum + (100 / elt3)
None of the above so we just pass along the current accumulator, i.e. sum = sum
compute([_,_],Sum,Sum).
compute([Elt1,Elt2,Elt3|Tail],AccNow,Sum) :-
Elt1 = Elt2,
!,
AccNext is AccNow + Elt1 + Elt2,
compute([Elt2,Elt3|Tail],AccNext,Sum).
compute([Elt1,Elt2,Elt3|Tail],AccNow,Sum) :-
Elt1 = Elt3,
!,
AccNext is AccNow + Elt1 * Elt3,
compute([Elt2,Elt3|Tail],AccNext,Sum).
compute([_,Elt2,Elt3|Tail],AccNow,Sum) :-
Elt3 \= 0,
Elt2 = Elt3,
!,
AccNext is AccNow + 100 / Elt3,
compute([Elt2,Elt3|Tail],AccNext,Sum).
compute([_,Elt2,Elt3|Tail],Acc,Sum) :-
compute([Elt2,Elt3|Tail],Acc,Sum).
If I try this on ?- compute([1,2,1,2],X). then I get X = 5. That's matching on the Elt1 = Elt3 predicate and giving me 0 + 1 * 1 and then again on the Elt1 = Elt3 predicate giving me 1 + 2 * 2 or 5.
If I try this on ?- compute([1,2,1,2,2,1,1],X). then I get X = 159. I'll leave it to you to see that it is the right result.
Just keep in mind that all Prolog is trying to do is succeed. If asked to prove a goal (i.e. compute/3) it finds the first predicate that matches and tries to prove that (by proving any subgoals) and when it fails it just backtracks to the previous choice point and tries another choice and to continue. If it proves the original goal then it succeed. If it didn't then it failed. There are no return values - only bound variables.

Related

Prolog program find sum of series and it's exponentiation

Sorry for the strange title of my question.
I just start learning prolog and i have come into a problem and it's calculating the sum of series of numbers and it's exponentiation , For example,
If i entered the number 3 , Prolog should output -> 3^2 + 2^2 + 1^2 = ?.
The only thing that worked for me was printing the numbers but not the final result
calculation(X):-
X>0,write(X),
(
X=\=1 -> write('^2 + '),Result is X-1,calculation(Result);
write('^2 =')
).
I did try some methods but all failed , Any help .
You should write as follows:
calculation(X) :-
calculation(X, 0).
calculation(X, Result):-
X >= 1 ->
(
writef('%w^2 + ', [X]),
X1 is X - 1,
Result1 is (2 ^ X) + Result,!,
calculation(X1, Result1)
)
;
writef('1^2 = %w',[Result]).

compare length of prolog lists

I have the following prolog program:
len([X],[Y],Count) :-
length(X,K),
length(Y,I),
K < I,
Count is 0
; I < K,
Count is 2
; I = K,
Count is 1.
When I enter :
len( [1,2], [5,2,4], X ).
I get: Singleton variable in branch: K and I
I looked up what this means here: http://www.swi-prolog.org/pldoc/man?section=singleton I tried doing _K & _I but you can only do that once.
This program should take two lists and compare the length of each list to determine the output value.
The first problem with your code is that the head of the clause has an error:
len([X],[Y],Count) :- ...
this means that the first and second list only can be singletons (lists with one element). So we need to rewrite this to:
len(X,Y,Count) :- ...
The second problem is that the ; has higher priority than ,, as a result the Prolog interpreter will interpret this as:
len(X,Y,Count) :-
(
length(X,K),
length(Y,I),
K < I,
Count is 0
);
(
I < K,
Count is 2
);
(
I = K,
Count is 1
).
So that means that in case the first condition fails, Prolog will backtrack, and now in that branch, it sees I < K, but for Prolog, those are new variables (since these are in a different branch). The Prolog interpreter will warn you that this is odd, especially in the case you write I < K, since it requires I and K to be grounded, so this will go wrong.
You need to rewrite your program to:
len(X,Y,Count) :-
length(X,K),
length(Y,I),
(
(
K < I,
Count is 0
);
(
I < K,
Count is 2
);
(
I = K,
Count is 1
)
).
or less verbose:
len(X,Y,Count) :-
length(X,K),
length(Y,I),
(
K < I,
Count is 0
; I < K,
Count is 2
; I = K,
Count is 1
).
But this is of course quite cumbersome. A more elegant solution is to write a compare/3 predicate first:
cmp(X,Y,0) :-
X < Y.
cmp(X,Y,2) :-
X > Y.
cmp(X,X,1).
and then write:
cmp(X,Y,0) :-
X < Y.
cmp(X,Y,2) :-
X > Y.
cmp(X,X,1).
len(X,Y,Cmp) :-
length(X,K),
length(Y,I),
cmp(K,I,Cmp).

pow(X,Y,Z) <=> Z = X^Y with add

Would it be possible to do "pow" with "add" predicate (or just X is Y + Z )?
I make this:
pow(0,1,1).
pow(_,0,1).
pow(X,Y,Z) :- Y1 is Y - 1, pow(X,Y1,Z1), Z is Z1 * X.
But I want also make it with " + " (just for practise) like 3^2 = 3 * 3 = 3 + 3 + 3
You can write the multiplication (mul/3) in terms of addition. Like:
pow(0,1,1).
pow(_,0,1).
pow(X,Y,Z) :-
Y > 1,
Y1 is Y - 1,
pow(X,Y1,Z1),
mul(Z1,X,Z). %% originally: Z is Z1 * X.
mul(0,_,0).
mul(I,A,R) :-
I > 0,
I1 is I-1,
mul(I1,A,R1),
R is R1 + A.
Usually a basic exercise is to write addition, multiplication, and power predictates with the Peano number representation. In that case addition is written with the successor functor.

How can I get this simple Prolog predicate to "return" the right way?

So I am learning Prolog. I need to write a predicate that finds the min/max value of an integer list. For example, the query minmaxArray([4,-1,5,4,1,2,3,-2],X,Y) would return X = -2 Y = 5. Here is what I have so far:
%min/max element of a 1 item list is that item.
minmaxArray([X], X, X).
%when there is only 2 items, put the smaller element in A and the
%larger element in B
minmaxArray([X,Y], A, B) :- mymin(X,Y,Min),
A is Min, mymax(X,Y,Max), B is Max.
%when there is more than two items make a recursive call to find the min/max
%of the rest of the list.
minmaxArray([X,Y|T], A, B) :- minmaxArray([Y|T], M, K),
mymin(X,M,Temp), A is Temp, mymax(X,K,Temp2), B is Temp2.
Assume mymin and mymax predicates work properly. They return the min and max of 2 numbers.
The issue here is that for example when I query minmaxArray([4,-1,5],X,Y) it returns X = -1 Y = 5 and then again X = -1 Y = 5. I know this must be because it hits the 2nd condition on the recursive call. I only want it to return X = -1 Y = 5 one time. I tried replacing condition 3 with this:
minmaxArray([X,Y,_|T], A, B) :- minmaxArray([Y,_|T], M, K),
mymin(X,M,Temp), A is Temp, mymax(X,K,Temp2), B is Temp2.
but that crashes the program. What can I do to fix this?
Note: I know that I may not be using the terminology correctly by saying returning and saying predicate when it should be rule, etc so I apologize in advance.
Seems that your code could be simpler. This predicate does all what's needed, and attempt to show how to use some standard construct (if/then/else)
minmaxArray([X], X, X).
minmaxArray([X|R], Min, Max) :-
minmaxArray(R, Tmin, Tmax),
( X < Tmin -> Min = X ; Min = Tmin ), % or mymin(X,Tmin,Min)
( X > Tmax -> Max = X ; Max = Tmax ).
You have provided 2 ways of solving the case where there are 2 items: one explicitly for 2 items, and your general case, which then employs the 1 element case.
Solution: remove the unneeded 2-element case.
Or, tail-recursive:
minmax([X|Xs],Min,Max) :- % we can only find the min/max of a non-empty list.
minmax(Xs,(X,X),Min,Max) % invoke the helper with the min/max accumulators seeded with the first item
.
minmax([],(Min,Max),Min,Max). % when the source list is exhausted, we're done: unify the accumulators with the result
minmax([X|Xs],(M,N),Min,Max) :- % when the source list is non-empty
min(X,M,M1) , % - get a new min value for the accumulator
max(X,N,N1) , % - get a new max value for the accumulator
minmax(Xs,(M1,N1),Min,Max) % - recurse down on the tail.
.
min(X,Y,X) :- X =< Y . % X is the min if it's less than or equal to Y.
min(X,Y,Y) :- X > Y . % Y is the min if it's greater than X.
max(X,Y,X) :- X >= Y . % X is the max if it's greater than or equal to Y.
max(X,Y,Y) :- X < Y . % Y is the max if it's greater than X.

Generalizing Fibonacci sequence with SICStus Prolog

I'm trying to find a solution for a query on a generalized Fibonacci sequence (GFS). The query is: are there any GFS that have 885 as their 12th number? The initial 2 numbers may be restricted between 1 and 10.
I already found the solution to find the Nth number in a sequence that starts at (1, 1) in which I explicitly define the initial numbers. Here is what I have for this:
fib(1, 1).
fib(2, 1).
fib(N, X) :-
N #> 1,
Nmin1 #= N - 1,
Nmin2 #= N - 2,
fib(Nmin1, Xmin1),
fib(Nmin2, Xmin2),
X #= Xmin1 + Xmin2.
For the query mentioned I thought the following would do the trick, in which I reuse the fib method without defining the initial numbers explicitly since this now needs to be done dynamically:
fib(N, X) :-
N #> 1,
Nmin1 #= N - 1,
Nmin2 #= N - 2,
fib(Nmin1, Xmin1),
fib(Nmin2, Xmin2),
X #= Xmin1 + Xmin2.
fib2 :-
X1 in 1..10,
X2 in 1..10,
fib(1, X1),
fib(2, X2),
fib(12, 885).
... but this does not seem to work.
Is it not possible this way to define the initial numbers, or am I doing something terribly wrong? I'm not asking for the solution, but any advice that could help me solve this would be greatly appreciated.
Under SWI-Prolog:
:- use_module(library(clpfd)).
fib(A,B,N,X):-
N #> 0,
N0 #= N-1,
C #= A+B,
fib(B,C,N0,X).
fib(A,B,0,A).
task(A,B):-
A in 1..10,
B in 1..10,
fib(A,B,11,885).
Define a predicate gfs(X0, X1, N, F) where X0 and X1 are the values for the base cases 0 and 1.
I'd say you're doing something terribly wrong...
When you call fib(1, X1), the variable X1 is the number that the function fib will return, in this case, it will be 1, because of the base case fib(1, 1)..
Without the base cases, fib/2 has no solution; no matter how you call it in fib2.
Note: if you use recursion, you need at least one base case.
Consider fib(N,F1,F2) so you'll be able to replace fib(Nmin1, Xmin1) and fib(Nmin2, Xmin2) with simple fib(Nmin2, Xmin2, Xmin1).
Maybe not a solution in the strict sense but I will share it never the less. Probably the only gain is to show, that this does neither need a computer nor a calculator to be solved. If you know the trick it can be done on a bearmat.
If F_n ist the n-th Term of the ordinary Fibo-sequence, starting with F_1=F_2=1, then the n-th Term of the generalized sequence will be G_n = F_{n-2}*a+F_{n-1}*b.
Define F_{-1}=1, F_0 = 0
(Indeed, by induction
G_1 = F_{-1}*a+F_0*b = 1*a+0*b=a
G_2 = F_0 * a + F_1 * b = 0*a + 1*b = b
G_{n+1} = F_{n-1}a + F_nb = (F_{n-3} + F_{n-2} )a + (F_{n-2} + F_{n-1})*b = G_n + G_{n-1}
)
Thus G_12 = F_10 * a + F_11 * b = 55a + 89b.
Now you can either search for solutions to the equation 55a + 89b = 885 with your computer
OR
do the math:
Residues mod 11 (explanation):
55a + 89b = 0 + 88b + b = b; 885 = 880 + 5 = 80*11 + 5 = 5
So b = 5 mod 11, but since 1 <= b <= 10, b really is 5. 89 * 5 = 445 and 885-445 = 440. Now, divide by 55 and get a=8.

Resources