Generate all pairs that sum to given number - prolog

I'm trying to generate all pairs X, Y that sum to given number Z using the following predicates:
genN(0).
genN(X) :-
genN(Xprev),
X is Xprev + 1.
sum2(X, Y, Z) :-
X + Y =:= Z.
allSum2(X, Y, Z) :-
genN(X),
X < Z,
genN(Y),
Y < Z,
sum2(X, Y, Z).
I'm using
genN to generate all natural numbers
sum2 checks if given 3 numbers X, Y, Z then X + Y = Z.
Then the logic of allSum2 is to
generate all pairs X and Y such that X and Y are smaller than Z and
to check if they sum up to Z.
Unfortunately I get stuck in generating infinitely many Ys and I do not understand why.
Can someone explain it to me?

Related

define predicate prolog by requirements

I have to define a predicate p(X, Y), where Y = f(X) where
How could I define the predicate, according to this requirements?
Almost the same way it's written there, three cases for Y's value given different X conditions:
f(X, Y) :- X < 4, Y is X ^ 2 - 1.
f(X, Y) :- X >= 4, X =< 6, Y is sqrt(X) + 1.
f(X, Y) :- X > 6, Y is 9 - X.
or the middle case
f(X, Y) :- between(4, 6, X), Y is sqrt(X) + 1.
which I had originally and find more readable, but changes the behaviour for that case, which is a tradeoff.
Then:
:- f(3, Y).
Y = 8
( zcompare/3 hints at a way to get rid of the choice points without using cut !, but only if you restrict to integers ).
Another way that doesn't leave choice points behind...
f(X,Y) :- X < 4 -> Y is X^2 - 1 ;
X =< 6 -> Y is sqrt(X) + 1 ;
Y is 9 - X .

Code difference in Prolog

What exactly is making these two seemingly identical pieces of code behave differently. My guess is I'm not taking a fundamental Prolog concept into account.
% creates list from X to Y (integers)
interval(X, X, [X]):- !.
interval(X, Y, [X|R]):- X < Y, X1 is X+1, interval(X1, Y, R).
The output from this is as desired, an interval with specific endpoints.
| ?- interval(2,5,L)
L = [2,3,4,5]
yes
But, this piece spits out a different result.
% creates list from X to Y (integers)
interval(X, X, [X]):- !.
interval(X, Y, [X|R]):- X < Y, interval(X+1, Y, R).
Output:
| ?- interval(2,5,L)
no

Generate multiple answers and put in list without using findall/3

the below code works perfectly but i want to get the multiple answers in a list without using the findall/3 function.
bet(N, M, K) :- N =< M, K = N.
bet(N, M, K) :- N < M, N1 is N+1, bet(N1, M, K).
pred([X, Y, S, P], N) :-
N1 is N - 1,
bet(2, N1, X),
X1 is X + 1,
N2 is N - X,
bet(X1, N2, Y),
S is X + Y,
P is X * Y.
s1(Q, N) :-
findall(X, pred(X, N), Q).
Had some help getting the above code work coz i'm new to Prolog.
Also, what the program is supposed to do is this:
X and Y are two integers with 1 < X < Y and X + Y ≤ 100. The goal
s1(Q,100) will bind Q with a list of quadruples [X, Y, S, P], where S
= X + Y and P = X * Y.
One way to do this is to break your pred/2 down to a recursive. auxiliary predicate that handles one case of X and Y on each recursive call. The following may not be optimized, but you can see in the logical tests how it achieves this:
pred(Q, N) :-
pred(Q, 2, 3, N). % Start with values X=2, Y=3
pred([], X, _, N) :- % Case in which X has reached max, so we're done
X >= N.
pred(Q, X, Y, N) :- % Case in which X is in range, but Y is at max, so next X, restart Y
X < N,
Y >= N - X,
X1 is X + 1,
Y1 is X1 + 1,
pred(Q, X1, Y1, N).
pred([[X, Y, S, P]|Qs], X, Y, N) :- % Case in which X and Y are within range
X < N,
Y < N - X,
S is X + Y,
P is X * Y,
Y1 is Y + 1,
pred(Qs, X, Y1, N). % Recurse using next Y

Generate list of numbers to fit certain criteria

I had a predicate to generate a list of numbers,
generate_numbers(0,[]).
generate_numbers(N,[Head|Tail]):-
N > 0,
Head is N,
N1 is N-1,
generate_numbers(N1,Tail).
I am trying to modify it so that it generates numbers X and Y up to a limit. The conditions are that 1 < X < Y and S = X + Y and S < 100.
I'm struggling to work out how to do it, I've tried but it's nowhere near correct.
generate_numbers(1,[]).
generate_numbers(X,[[Head,Y,S]|Tail]):-
X > 1,
Head is X,
Y is X+1,
S is X + Y,
X1 is X-1,
generate_numbers(X1,Tail).
I did have a check for S > 100 but that stopped the code from working at all.
The output I'm after would be along the lines of [1,2,3], [2,4,6], [3,9,12], [20,25,45]. Obviously that's just a few examples, there will be 1000s in reality.
I think that I might need to recurse twice. So add 1 to X then keep adding 1 to Y until the limit is reached, add 1 to X and keep adding 1 to Y again until the limit is reached and keep doing this recursively. This should make sure that every possible pair is created.
There are a couple of ways to approach this. The brute force way is to have a second layer of base case to iterate over one of the two addends in the summation. This solution will provide the list first in order of total sum, then by value of X:
gen_numbers(MaxSum, Result) :-
MaxSum > 1,
gen_numbers(2, MaxSum, 1, Result).
gen_numbers(Sum, Sum, Sum, []). % 'Sum' has reached max value
gen_numbers(Sum, MaxSum, Sum, Result) :- % 'X' has reached max value
Sum < MaxSum,
Sum1 is Sum + 1,
gen_numbers(Sum1, MaxSum, 1, Result).
gen_numbers(Sum, MaxSum, X, [[X, Y, Sum]|Result]) :-
Sum =< MaxSum,
X < Sum,
Y is Sum - X,
X1 is X + 1,
gen_numbers(Sum, MaxSum, X1, Result).
By counting up instead of down, I could keep the list in forward order and maintain tail recursion without the use of an auxiliary list. I constrained by X and the Sum and let Y vary. I think you could easily modify this to vary based upon whatever variables you wish.
A cleaner approach is to use the CLPFD library and specify the conditions as constraints:
:- use_module(library(clpfd)).
summation(Sum, [X, Y, S]) :-
[X, Y] ins 1..Sum,
sum([X, Y], #=<, Sum),
label([X, Y]),
S is X + Y.
gen_numbers(MaxSum, Result) :-
findall([X, Y, S], summation(MaxSum, [X, Y, S]), Result).
Here, summation/2 presents one of each solution at a time, and findall/3 collects them. This solution is easily scalable to support more addends.

program for finding Gcd in Prolog

I tried to write a code in Prolog for finding GCD (without using modulo)
can anyone tell me what's wrong with this program?
gcd(X,Y,Z):- X>=Y, X1=X-Y, gcd(X1,Y,Z).
gcd(X,Y,Z):- X<Y, X1=Y- X, gcd(X1,X,Z).
gcd(0,X,X):- X>0.
As to why the original implementation doesn't work, there are two reasons:
The predicate =/2 is for unification, not arithmetic assignment
The expression X1 = X - Y doesn't subtract Y from X and store the result in X1. Rather, it unifies X1 with the term, -(X,Y). If, for example, X=5 and Y=3, then the result would be, X1=5-3, not X1=2. The solution is to use is/2 which assigns evaluated arithmetic expressions: X1 is X - Y.
Other predicates, besides the base case predicate, successfully match the base case
The clause, gcd(0,X,X) :- X > 0. is a reasonable base case, but it is never attempted because the second clause (gcd(X,Y,Z):- X<Y,...) will always successfully match the same conditions first, leading to infinite recursion and a stack overflow.
One way to fix this is to move the base case to the first clause, and use a cut to avoid backtracking after it successfully executes:
gcd(0, X, X):- X > 0, !.
gcd(X, Y, Z):- X >= Y, X1 is X-Y, gcd(X1,Y,Z).
gcd(X, Y, Z):- X < Y, X1 is Y-X, gcd(X1,X,Z).
This will work now:
| ?- gcd(10,6,X).
X = 2 ? ;
(1 ms) no
| ?- gcd(10,5,X).
X = 5 ? ;
no
(NOTE: the "no" here means no more solutions found after finding the first one)
ADDENDUM
There are still a couple of remaining "gaps" in the above implementation. One is that it doesn't handle gcd(0, 0, R) gracefully (it overflows). Secondly, it doesn't handle negative values. One possible solution would be to elaborate these cases:
gcd(X, Y, Z) :-
X < 0, !,
gcd(-X, Y, Z).
gcd(X, Y, Z) :-
Y < 0, !,
gcd(X, -Y, Z).
gcd(X, 0, X) :- X > 0.
gcd(0, Y, Y) :- Y > 0.
gcd(X, Y, Z) :-
X > Y, Y > 0,
X1 is X - Y,
gcd(Y, X1, Z).
gcd(X, Y, Z) :-
X =< Y, X > 0,
Y1 is Y - X,
gcd(X, Y1, Z).
Try the following instead:
gcd(X, 0, X):- !.
gcd(0, X, X):- !.
gcd(X, Y, D):- X =< Y, !, Z is Y - X, gcd(X, Z, D).
gcd(X, Y, D):- gcd(Y, X, D).
Taken from rosettacode.org on GCD in all kinds of languages.
Prolog code for GCD
gcd(X,Y,G) :- X=Y, G=X.
gcd(X,Y,G) :- X<Y, Y1 is Y-X, gcd(X,Y1,G).
gcd(X,Y,G) :- X>Y ,gcd(Y,X,G).
?- gcd(24,16,G).
G = 8
gc(X,Y,Z):- (
X=0 -> (
Z is Y
);
Y=0 -> (
Z is X
);
X=Y -> (
Z is X
);
X>Y -> (
Y1 is X-Y,
gc(Y1,Y,Z)
);
X<Y->(
Y1 is Y-X,
gc(X,Y1,Z)
)
).
gcd(A,B,X):- B=0,X=A.
gcd(A,B,X):- A>B, gcd(B, A, X).
gcd(A,B,X) :- A<B, T is B mod A, gcd(A, T, X).
prolog answer is:-
gcd(X,0,X).
gcd(X,Y,R):-
Y>0,
X1 is X mod Y,
gcd(Y,X1,R).
Simple and Readable Prolog Code for GCD of Two Numbers using the Euclidean Algorithm.
gcd(A,B,X):- A=0,X=B. % base case
gcd(A,B,X):- B=0,X=A. % base case
gcd(A,B,X):- A>B, gcd(B, A, X).
gcd(A,B,X):- A<B, T is B mod A, gcd(A, T, X).
Query as follows:
gcd(147,210,GCD).
Output:
GCD = 21
This code worked.
gcd(X,X,X).
gcd(X,Y,D):-X<Y, Y1 is Y-X, gcd(X,Y1,D).
gcd(X,Y,D):-Y<X, gcd(Y,X,D).

Resources