Euclidean recursive algorithm - prolog

Ok, I know it's really a stupid question, but I can't get it.
There is a task where I should find a recursive algorithm of
Euclid (gcd). I've done it for one case, here:
nondeterm nod (integer,integer,integer)
CLAUSES
nod (X,0,X):- !.
nod (0,X,X):- !.
nod (X,0,X):-X>0.
nod (X,Y,G):-Y>0, Z = X mod Y, nod (Y,Z,G).
I need to do another case, where recursion is beginnig from х0, when Xi then calling for function counting Xi+1.
It should be sort of it:
PREDICATES
nondeterm nod (integer,integer,integer)
nondeterm nod1 (integer,integer,integer,integer,integer)
CLAUSES
nod(X,Y,Z):- nod1(X,Y,Z,0,0).
nod1 (X,Y,Z,X,Y):- Otvet = Z, write("Otvet=", Otvet, "\n"), !.
nod1 (X,Y,X,Y):- nod1 (X,Y,X,Y).
nod1 (X,Y,Z,X1,Y1):-
X1>Y1, X>0, Y>0,
Y2 = X1 mod Y1,
X2 = Y1,
nod1(X,Y,Z,X2,Y2).
But it doesn't work. Please, help me with that.

The following code works for me. Please note the use of
rem, but I guess you could also use mod:
% sys_gcd(+Integer, +Integer, -Integer)
sys_gcd(X, 0, X) :- !.
sys_gcd(X, Y, Z) :-
H is X rem Y,
sys_gcd(Y, H, Z).
Here are some example runs with SWI-Prolog:
?- sys_gcd(20,30,X).
X = 10.
?- sys_gcd(-20,30,X).
X = 10.
?- sys_gcd(20,-30,X).
X = -10.
?- sys_gcd(-20,-30,X).
X = -10.
If you want a particular sign of the result, you
need additional code around it.
Bye

Related

Prolog predecessor math

I have an add2 predicate which resolves like this where s(0) is the successor of 0 i.e 1
?- add2(s(0)+s(s(0)), s(s(0)), Z).
Z = s(s(s(s(s(0)))))
?- add2(0, s(0)+s(s(0)), Z).
Z = s(s(s(0)))
?- add2(s(s(0)), s(0)+s(s(0)), Z).
Z = s(s(s(s(s(0)))))
etc..
I'm trying to do add in a predecessor predicate which will work like so
?- add2(p(s(0)), s(s(0)), Z).
Z = s(s(0))
?- add2(0, s(p(0)), Z).
Z = 0
?- add2(p(0)+s(s(0)),s(s(0)),Z).
Z = s(s(s(0)))
?- add2(p(0), p(0)+s(p(0)), Z).
Z = p(p(0))
I can't seem to find a way to do this. My code is below.
numeral(0).
numeral(s(X)) :- numeral(X).
numeral(X+Y) :- numeral(X), numeral(Y).
numeral(p(X)) :- numeral(X).
add(0,X,X).
add(s(X),Y,s(Z)) :- add(X,Y,Z).
add(p(X),Y,p(Z)) :- add(X,Y,Z).
resolve(0,0).
resolve(s(X),s(Y)) :-
resolve(X,Y).
resolve(p(X),p(Y)) :-
resolve(X,Y).
resolve(X+Y,Z) :-
resolve(X,RX),
resolve(Y,RY),
add(RX,RY,Z).
add2(A,B,C) :-
resolve(A,RA),
resolve(B,RB),
add(RA,RB,C).
In general, adding with successor arithmetic means handling successor terms, which have the shape 0 or s(X) where X is also a successor term. This is addressed completely by this part of your code:
add(0,X,X).
add(s(X),Y,s(Z)) :- add(X,Y,Z).
Now you have to make a decision; you can either handle the predecessors and the addition terms here, in add/3, or you can wrap this predicate in another one that will handle them. You appear to have chosen to wrap add/3 with add2/3. In that case, you will definitely need to create a reducing term, such as you've built here with resolve/2, and I agree with your implementation of part of it:
resolve(0,0).
resolve(s(X),s(Y)) :-
resolve(X,Y).
resolve(X+Y,Z) :-
resolve(X,RX),
resolve(Y,RY),
add(RX,RY,Z).
This is all good. What you're missing now is a way to handle p(X) terms. The right way to do this is to notice that you already have a way of deducting by one, by using add/3 with s(0):
resolve(p(X), R) :-
resolve(X, X1),
add(s(0), R, X1).
In other words, instead of computing X using X = Y - 1, we are computing X using X + 1 = Y.
Provided your inputs are never negative, your add2/3 predicate will now work.

getting out of local stack at prolog

p(0,0).
p(0,1).
p(0,2).
p(0,3).
p(0,4).
p(1,1).
p(1,2).
p(1,3).
p(1,4).
p(1,0).
p(2,0).
p(2,1).
p(2,2).
p(2,3).
p(2,4).
p(3,0).
p(3,1).
p(3,2).
p(3,3).
p(3,4).
p(4,0).
p(4,1).
p(4,2).
p(4,3).
p(4,4).
adjacent(p(X,Y),p(X,Z)) :-
p(X,Y),
p(X,Z),
Z is Y+1.
adjacent(p(X,Y),p(X,Z)) :-
p(X,Y),
p(X,Z),
Z is Y-1.
adjacent(p(X,Y),p(Z,Y)) :-
p(X,Y),
p(X,Z),
Z is X+1.
adjacent(p(X,Y),p(Z,Y)) :-
p(X,Y),
p(X,Z),
Z is X-1.
adjacentC(X,Y) :-
adjacent(X,Y).
adjacentC(X,Y) :-
adjacent(X,Z),
adjacentC(Z,Y).
I don't know why this code I wrote isn't working.
e.g.:
?- adjacentC((0,0),(4,4)). ERROR
Quick answer: The following works and terminates always using closure/3 defined elsewhere.
adjacentD(X,Y) :-
closure(adjacent,X,Y).
However, this approach is extremely slow, due to the inefficient definition of adjacent/3. Here is a better one / oh forget it, here is a more correct one, first:
adjacent2(p(X0,Y0),p(X,Y)) :-
p(X0,Y0),
( X0 = X,
p(X,Y),
abs(Y0-Y) =:= 1
; Y0 = Y,
p(X,Y),
abs(X0-X) =:= 1
).

Prolog Average Rules

The following set of Prolog rules work on an input such as average([3,4,5],A). Whereby A = 4.0.
However, if I try something like average([3,4,X],4). The following error is returned:
average([X|Xs],A) :- sum([X|Xs],S), length([X|Xs],L), {S/L=A}.
ERROR: is/2: Arguments are not sufficiently instantiated
How could I modify my code to allow average([3,4,X],4) to return the correct value for X?
The trivial solution with library(clpqr):
add(A, B, +(A,B)).
list_average([X|Xs], A) :-
length([X|Xs], Len),
foldl(add, Xs, X, Sum),
{Sum =:= A*Len}.
If for some reason you don't want to use the library, you can try the following code.
This will probably solve your problem, but I am not happy with this code. Certainly someone else knows better:
list_average(L, A) :-
( is_list(L)
-> length(L, Len),
term_variables(L-A, Vars),
solve(Vars, L, A, Len)
; instantiation_error(L)
).
solve([], L, A, Len) :-
sum_list(L, Sum),
A =:= Sum / Len. % Validate provided average
solve([X|Xs], L, A, Len) :-
partition(number, L, Nums, Vars),
length(Vars, T),
sum_list(Nums, Sum),
( var(A)
-> maplist(=(A), Vars), % all variables are as the average
A is Sum / (Len - T)
; maplist(=(X), Xs), % all free variables in list are same
X is (Len*A - Sum) / T
).
With this queries like this are possible:
?- list_average([2,3,4,5], A).
A = 3.5.
?- list_average([2,3,4,5], 3).
false.
?- list_average([2,X,4,5], 3).
X = 1.
?- list_average([2,X,4,Y], 3).
X = Y, Y = 3.
?- list_average([2,X,4,Y], A).
X = Y, Y = A, A = 3.
?- list_average([2,X,4,Y], 6).
X = Y, Y = 9.
It will automatically try to bind all free variables to a single free variable before solving numerically.
It's quite the same as Boris solution, but I use library lambda :
:- use_module(library(clpr)).
:- use_module(library(lambda)).
average(L, A) :-
length(L, Len),
foldl(\X^Y^Z^{Z = X+Y}, L, 0, TT),
{A * Len = TT}.
EDIT correction after false's remark.

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).

Solving CNF using Prolog

While learning Prolog, I tried to write a program solving CNF problem (the performance is not an issue), so I ended up with the following code to solve (!x||y||!z)&&(x||!y||z)&&(x||y||z)&&(!x||!y||z):
vx(t).
vx(f).
vy(t).
vy(f).
vz(t).
vz(f).
x(X) :- X=t; \+ X=f.
y(Y) :- Y=t; \+ Y=f.
z(Z) :- Z=t; \+ Z=f.
nx(X) :- X=f; \+ X=t.
ny(Y) :- Y=f; \+ Y=t.
nz(Z) :- Z=f; \+ Z=t.
cnf :-
(nx(X); y(Y); nz(Z)),
(x(X); ny(Y); z(Z)),
(x(X); y(Y); z(Z)),
(nx(X); ny(Y); z(Z)),
write(X), write(Y), write(Z).
Is there any simpler and more direct way to solve CNF using this declarative language?
Consider using the built-in predicates true/0 and false/0 directly, and use the toplevel to display results (independently, instead of several subsequent write/1 calls, consider using format/2):
boolean(true).
boolean(false).
cnf(X, Y, Z) :-
maplist(boolean, [X,Y,Z]),
(\+ X; Y ; \+ Z),
( X ; \+ Y ; Z),
( X ; Y ; Z),
( \+ X ; \+ Y ; Z).
Example:
?- cnf(X, Y, Z).
X = true,
Y = true,
Z = true .
EDIT: As explained by #repeat, also take a serious look at CLP(B): Constraint Solving over Booleans.
With CLP(B), you can write the whole program above as:
:- use_module(library(clpb)).
cnf(X, Y, Z) :-
sat(~X + Y + ~Z),
sat(X + ~Y + Z),
sat(X + Y + Z),
sat(~X + ~Y + Z).
Please see the answer by #repeat for more information about this.
Look up "lean theorem prover" (such as leanTAP or leanCoP) for simple, short theorem provers in Prolog. Those are designed to use Prolog features to the best possible advantage. Although provers like that use first-order logic, CNF is a subset of that. There are dedicated SAT solvers for Prolog as well, such as this one.
Use clpb!
:- use_module(library(clpb)).
To check if some Boolean expression is satisfiable, use sat/1:
% OP: "(!x||y||!z) && (x||!y||z) && (x||y||z) && (!x||!y||z)"
?- sat((~X + Y + ~Z)*(X + ~Y + Z)*(X + Y + Z)*(~X + ~Y + Z)).
sat(X=\=X*Y#Z).
No concrete solution(s) yet... but a residue that's a lot simpler than the term we started with!
To get to concrete truth values, use labeling/1:
?- sat(X=\=X*Y#Z), labeling([X,Y,Z]).
X = 0, Y = 0, Z = 1
; X = 0, Y = 1, Z = 1
; X = 1, Y = 0, Z = 0
; X = 1, Y = 1, Z = 1.

Resources