I've written prolog program which takes initial, pickup and final (x,y,z) coordinates. The agent should reach the final coordinates through the pickup coordinates. When I run the query, the program runs indefinitely. I'm assuming this is because there are a huge number of combinations to search through. So i decreased my constraints in in_range(X,Y,Z). I'm new to prolog, any help would be appreciated. Thanks
in_range(X,Y,Z):-
X > -5,
X < 5,
Y >= 0,
Y < 10,
Z > -5,
Z < 5.
deliver(Ix,Iy,Iz,Px,Py,Pz,Fx,Fy,Fz):-
in_range(Ix,Iy,Iz),
in_range(Px,Py,Pz),
in_range(Fx,Fy,Fz),
move(Ix,Iy,Iz,Px,Py,Pz),
move(Px,Py,Pz,Fx,Fy,Fz).
move(X1,Y1,Z1,X2,Y2,Z2):-
X is X1-1,
Y is Y1,
Z is Z1,
in_range(X,Y,Z),
X =:= X2,
Y =:= Y2,
Z =:= Z2;
X is X1-1,
Y is Y1,
Z is Z1,
in_range(X,Y,Z),
move(X,Y,Z,X2,Y2,Z2).
move(X1,Y1,Z1,X2,Y2,Z2):-
X is X1,
Y is Y1-1,
Z is Z1,
in_range(X,Y,Z),
X =:= X2,
Y =:= Y2,
Z =:= Z2;
X is X1,
Y is Y1-1,
Z is Z1,
in_range(X,Y,Z),
move(X,Y,Z,X2,Y2,Z2).
move(X1,Y1,Z1,X2,Y2,Z2):-
X is X1,
Y is Y1,
Z is Z1-1,
in_range(X,Y,Z),
X =:= X2,
Y =:= Y2,
Z =:= Z2;
X is X1,
Y is Y1,
Z is Z1-1,
in_range(X,Y,Z),
move(X,Y,Z,X2,Y2,Z2).
move(X1,Y1,Z1,X2,Y2,Z2):-
X is X1+1,
Y is Y1,
Z is Z1,
in_range(X,Y,Z),
X =:= X2,
Y =:= Y2,
Z =:= Z2;
X is X1+1,
Y is Y1,
Z is Z1,
in_range(X,Y,Z),
move(X,Y,Z,X2,Y2,Z2).
move(X1,Y1,Z1,X2,Y2,Z2):-
X is X1,
Y is Y1+1,
Z is Z1,
in_range(X,Y,Z),
X =:= X2,
Y =:= Y2,
Z =:= Z2;
X is X1,
Y is Y1+1,
Z is Z1,
in_range(X,Y,Z),
move(X,Y,Z,X2,Y2,Z2).
move(X1,Y1,Z1,X2,Y2,Z2):-
X is X1,
Y is Y1,
Z is Z1+1,
in_range(X,Y,Z),
X =:= X2,
Y =:= Y2,
Z =:= Z2;
X is X1,
Y is Y1,
Z is Z1+1,
in_range(X,Y,Z),
move(X,Y,Z,X2,Y2,Z2).
move(6,_,_,_,_,_).
move(-6,_,_,_,_,_).
move(_,11,_,_,_,_).
move(_,-1,_,_,_,_).
move(_,_,6,_,_,_).
move(_,_,-6,_,_,_).
The query I'm running is
?-deliver(0,0,0,1,1,1,4,4,4).
You're hitting an infinite recursion because you're doing a depth-first search without tracking visited nodes, by tracing it you'll see for the example that your search gets lost in a (0, 0, 4) <> (0, 0, 5) loop, based on the first move predicate.
Tabling will work for SWI-Prolog, but let's take this opportunity to explore portable solutions as they'll aid your Prolog (and broader CS) learning.
First, let's look at that in_range/3 predicate and turn our locations into terms (if you bump into the word "reification", this is doing that). We want to consider our locations as terms so we can pass them around as whole entities. It also helps us think! We can define what a location is in your world like so:
% loc(X, Y, Z) is a location in 3D integer co-ordinate space
loc(X, Y, Z) :-
between(-5, 5, X),
between(0, 10, Y),
between(-5, 5, Z).
Thus in_range/3 becomes in_range/1:
in_range(Loc) :- call(Loc).
As a bonus, you can generate locations: ?- loc(X, Y, Z).
Now those move predicates can be tidied up to make them much easier to read, trace and think about. To that end, they only define a single move, best to keep journeys
to their own predicate so we can use these individually when we only want a single step. (?- move(loc(1, 1, 2), Step).)
%! move(Loc1, Loc2)
move(loc(X1, Y, Z), loc(X2, Y, Z)) :- X2 is X1 + 1, in_range(loc(X2, Y, Z)).
move(loc(X1, Y, Z), loc(X2, Y, Z)) :- X2 is X1 - 1, in_range(loc(X2, Y, Z)).
move(loc(X, Y1, Z), loc(X, Y2, Z)) :- Y2 is Y1 + 1, in_range(loc(X, Y2, Z)).
move(loc(X, Y1, Z), loc(X, Y2, Z)) :- Y2 is Y1 - 1, in_range(loc(X, Y2, Z)).
move(loc(X, Y, Z1), loc(X, Y, Z2)) :- Z2 is Z1 + 1, in_range(loc(X, Y, Z2)).
move(loc(X, Y, Z1), loc(X, Y, Z2)) :- Z2 is Z1 - 1, in_range(loc(X, Y, Z2)).
Now let's define our delivery predicate. in_range/1 can be used to check the From is valid, whereas Pickup and Dest are expected to take care of that themselves:
deliver(From, Pickup, Dest) :-
in_range(From),
go_to(From, Pickup),
go_to(Pickup, Dest).
So far I've only refactored your code to break predicates down into smaller definitions for more versatility and easier readability. The big change to prevent the infinite recursion is in go_to/2, which is not yet defined. Given that you're doing a search in integer 3D coordinate space, the most suitable search algorithm is A*, which will not only exclude search locations already visited, but will first search locations closest to the intended goal.
go_to(Origin, Destination) :-
a_star(Origin, Destination).
% A* for SWI-Prolog
:- use_module(library(heaps)).
% Use to order search, 3D euclidean distance squared
heuristic_distance(loc(X1, Y1, Z1), loc(X2, Y2, Z2), Distance) :-
Distance is (X1 - X2)^2 + (Y1 - Y2)^2 + (Z1 - Z2)^2.
% Add a list of nodes to the heap
open_add_nodes(Heap, [], _, Heap).
open_add_nodes(Heap, [ToAdd|Tail], Dest, Out) :-
heuristic_distance(ToAdd, Dest, Dist),
add_to_heap(Heap, Dist, ToAdd, Heap1),
open_add_nodes(Heap1, Tail, Dest, Out).
% Get an ordered list of reachable locations from the origin
get_reachable(Loc, Locations) :-
setof(L, move(Loc, L), Locations).
% A* search setup
a_star(Origin, Dest) :-
% Create heap of open search nodes
heuristic_distance(Dest, Origin, Dist),
singleton_heap(Open, Dist, Origin),
% Do the search
a_star(Open, Dest, [Origin]).
% Do the A* search
a_star(Open, Dest, Closed) :-
% Get the most promising Node
get_from_heap(Open, _, Loc, RemainingSearch),
% If we've reached the goal, return the Answer
( Dest = Loc
% Otherwise keep searching
; get_reachable(Loc, ReachableLocations),
% Exclude visited nodes
ord_union(Closed, ReachableLocations, Closed1, ToSearch),
% Add new open nodes to search heap
open_add_nodes(RemainingSearch, ToSearch, Dest, Open1),
% Carry on searching
a_star(Open1, Dest, Closed1)
).
Now A* might take a bit to read and understand, but it'd be much more difficult if we were having to deal with the X, Y, Z coordinates than with locations: every Loc, Dest, Origin and ToAdd is a location. It's also only possible to code because our move/2 predicate only takes a single step, so we can choose not to use Prolog's implicit Depth-First Search.
All this code is in a SWISH Notebook so you can explore it. To learn more about search algorithms I'd recommend the MIT AI lectures on YouTube, 4 and 5 cover search. For Prolog implementations, "The Craft of Prolog", also out of MIT, is excellent.
Related
Suppose, we have the following game:
There is a pair of numbers (x, y), 2 players are making moves. During the move a player can increase any number by 1 or multiply it by 2.
The player, who makes a move after which (x + y) >= 77 wins.
The initial position is (8, x), find the minimal x such as the second player wins in minimal number of turns.
This problem can be easily solved analytically: both players multiply x by 2 and we get the following inequality:
8 + 2*2*x >= 77 => 4*x >= 69 => x >= (69 / 4) => x >= 17,25
x = ceil(17,25)
x = 18
Now we tried to solve it using Prolog:
:- use_module(library(clpfd)).
top(77).
% possible moves for player
next_state(X1, X2, Y1, Y2) :- Y1 #= X1 + 1,
Y2 #= X2.
next_state(X1, X2, Y1, Y2) :- Y1 #= X1,
Y2 #= X2 + 1.
next_state(X1, X2, Y1, Y2) :- Y1 #= 2*X1,
Y2 #= X2.
next_state(X1, X2, Y1, Y2) :- Y1 #= X1,
Y2 #= 2*X2.
% winning pair
win(X1, X2) :- top(X),
X1 + X2 #>= X.
% we have a sequence of states
sequence_correct([[X1, X2]]) :- win(X1, X2).
sequence_correct([[X1, X2], [Y1, Y2] | T]) :- next_state(X1, X2, Y1, Y2),
sequence_correct([[Y1, Y2] | T]).
% find X such as there is a sequence of 3 states, and there is no Y such as
% Y < X => X is minimum
min(X) :- sequence_correct([[8, X], _, _]), \+ (sequence_correct([[8, Y], _, _]), Y #< X).
But unfortunately when we try to find minimal X, it fails:
?- min(X).
false.
?- min(18). % <- this is good
true.
?- min(17).
false.
?- min(19).
false.
What is wrong?
How to fix?
You are using (\+)/1 which explains:
?- min(X).
false.
No position is negative [X0,Y0] ins 0..sup. Assuming the game doesn't start in the winning position (X0+Y0 #< 77), only the last move is winning (X+Y #>= 77).
move_(s(X,Y), s(X0,Y0), s(X,Y)) :-
[X0,Y0] ins 0..sup,
X0+Y0 #< 77,
next_state(X0, Y0, X, Y).
moves([S0|Ss]) :-
foldl(move_, Ss, S0, s(X,Y)),
X+Y #>= 77.
min(Y) :-
Y0 in 0..77,
labeling([min], [Y0]),
moves([s(8,Y0),_,_]),
!, % commit to the minimum.
Y = Y0.
The search for the minimum is done with labeling([min], [Y0]).
Improved solution for any depth:
move_(s(P,X,Y), s(P0,X0,Y0), s(P,X,Y)) :-
P #= 1-P0,
X0+Y0 #< 77,
next_state(X0, Y0, X, Y).
min(Depth, s(P0,X0,Y0), s(P,X,Y)) :-
[X0,Y0] ins 0..sup,
X0+Y0 #< 77,
length(Ss, Depth),
foldl(move_, Ss, s(P0,X0,Y0), s(P,X,Y)),
X+Y #>= 77.
min(Y) :-
length(_, Depth),
Y0 in 0..77,
labeling([min], [Y0]),
min(Depth, s(0,8,Y0), s(P,_,_)), % Start with player 0. Player 1-P wins.
P = 0,
!, % commit to the minimum.
Y = Y0.
Without clpfd:
move(A, B, A1, B1) :-
( move_num(A, A1), B1 = B
; move_num(B, B1), A1 = A
).
move_num(N, N1) :-
( N1 is N + 1
; N1 is N * 2
).
won(A, B) :-
Tot is A + B,
% Fast integer comparison
Tot #>= 77.
turns(v(A, B), []) :-
% Second player has won
won(A, B).
turns(v(A, B), [state(first(A1,B1),second(A2,B2))|T]) :-
% First player
move(A, B, A1, B1),
\+ won(A1, B1),
% Second player
move(A1, B1, A2, B2),
turns(v(A2, B2), T).
?- time(findall(v(N, Len), (between(0, 20, N), once(( length(T, Len), turns(v(8, N), T) )) ), Vs)).
% 9,201 inferences, 0.001 CPU in 0.001 seconds (99% CPU, 17290920 Lips)
Vs = [v(0,2),v(1,2),v(2,2),v(3,2),v(4,2),v(5,2),v(6,2),v(7,2),v(8,2),v(9,2),v(10,2),v(11,2),v(12,2),v(13,2),v(14,2),v(15,2),v(16,2),v(17,2),v(18,1),v(19,1),v(20,1)].
... which shows that N=18 is the first to have length 1.
Could then use e.g. https://www.swi-prolog.org/pldoc/man?predicate=aggregate_all/3
Can improve efficiency by restricting the length of the turns to be best-so-far:
under_best_length(Len) :-
nb_getval(best_turns, Best),
( integer(Best) ->
Len is Best - 1
; Len = inf
).
best_length_update(Len, N) :-
nb_getval(best_turns, Best),
once(Best == undefined ; Len < Best),
nb_setval(best_turns, Len),
% Potentially useful
nb_setval(best_n, N).
Result in swi-prolog, annotated:
?- nb_setval(best_turns, undefined), between(-80, 80, N),
under_best_length(Best),
once(( between(1, Best, Len), length(T, Len), turns(v(8, N), T) )),
best_length_update(Len, N).
% The first solution becomes best-so-far
N = -80,
Best = inf,
Len = 3,
T = [state(first(9,-80),second(10,-80)),state(first(20,-80),second(40,-80)),state(first(80,-80),second(160,-80))] ;
% Narrowing down to length 2
N = -51,
Best = Len, Len = 2,
T = [state(first(16,-51),second(32,-51)),state(first(64,-51),second(128,-51))] ;
% Length 1 is first seen with N=18
N = 18,
Best = Len, Len = 1,
T = [state(first(8,36),second(8,72))] ;
% There is no solution with a length lower than 1
false.
Here is a one-liner to show the desired 18 answer:
?- time(( nb_setval(best_turns, undefined), between(0, 78, N),
under_best_length(Best),
once(( between(1, Best, Len), length(T, Len), turns(v(8, N), T) )),
best_length_update(Len, N), false ; nb_getval(best_n, BestN) )).
% 3,789 inferences, 0.001 CPU in 0.001 seconds (99% CPU, 5688933 Lips)
BestN = 18.
How can I find the result of an arithmetic expression composed of pluses and minuses without using 'is'?
For example, to find the result of 1+2+3+4-6, I do: X is 1+2+3+4-6 and I get: X = 4.
What I've tried so far:
eval(EXPR, EXPR) :-
integer(EXPR),
!.
eval(X+Y, RES) :-
eval(X, X1),
eval(Y, Y1),
plus(X1, Y1, RES).
eval(X-Y, RES) :-
eval(X, X1),
eval(Y, Y1),
Y2 = -Y1,
plus(X1, Y2, RES).
but when I try to compute an expression containing negative numbers, I get the error: `integer' expected, found `- number` (a compound).
How can I solve it?
Add plus(Y1,Y2,0) instead of Y2 = -Y1.
In the latter case, Y2 is a structure with functor - and Argument Y1, whereas in the former case, Y1 is a number.
Take Y1 = 3 for example. [Just for fun: try it with Y1 = -3]
?- Y1 = 3, Y2 = -Y1, Y2 =.. L.
Y1 = 3,
Y2 = - 3,
L = [-, 3].
?- Y1 = 3, plus(Y1,Y2,0), Y2 =.. L.
Y1 = 3,
Y2 = -3,
L = [-3].
However, Y2 is supposed to be an argument in the predicate plus/3, which does not allow structures as arguments.
Maybe you prefer this solution:
eval(X-Y, RES) :-
eval(X, X1),
eval(Y, Y1),
plus(Y1, RES, X1).
I currently have to make some sort of Wumpus World implementation in SWI Prolog and give all possible paths over a board of size NxN, I have done several prolog tutorials but I can't figure how to solve this particular task in Prolog. I'm trying to get all possible paths for my agent to the gold and nothing else. It has to start from the initial position (X0, Y0).
I attach the code that I've managed to write so far. I have tried to do a simple DFS which sort of works but I struggle with the variable "parsing" to complete the code.
:- dynamic getAllPathsRec/2, agent/2, visited/2, visited/2.
gold(5,5).
worldSize(10).
agent(1,1).
getAllPaths :-
getAllPathsRec(1,1).
getAllPathsRec(X,Y) :-
format(X), format(Y), format('~n'),
gold(X1,Y1),
\+visited(X,Y),
assert(visited(X,Y)),
(X = X1, Y = Y1) -> print('Found GOLD');
move(_,X,Y).
move(right, X, Y) :-
X1 is X + 1,
X1 > 0 , X1 < 11,
getAllPathsRec(X1,Y).
move(left, X, Y) :-
X1 is X - 1,
X1 > 0 , X1 < 11,
getAllPathsRec(X1,Y).
move(up, X, Y) :-
Y1 is Y + 1,
Y1 > 0 , Y1 < 11,
getAllPathsRec(X,Y1).
move(down, X, Y) :-
Y1 is Y - 1,
Y1 > 0 , Y1 < 11,
getAllPathsRec(X,Y1).
I expect to find the gold in any possible way, ideally printing each path the algorithm has taken. Thank you in advance.
EDIT:
I've noticed that this solution has some efficiency problems for boards of enough size. It's being discussed here. I'll update the answer when we come up with a result.
Take care with assert/1 predicate, as it adds the fact to the knowledge base permanently and it's not undone while trying other combinations, so you won't be able to visit the same cell twice.
Instead of that, I approached it with an extra parameter V (that stands for visited), in which you can append the element treated in each exploration step. Also I stored the chosen directions in every step into a list L to print it when the target is found.
The or operator ; allows to not keep exploring the same path once the target is found and goes back to keep trying other combinations.
Notes:
If you face any use case where you can use assert/1, take care, because it's deprecated.
The _ variable it's not necessary in the move function as you can simply add 4 different "implementations" and just append the four directions.
As an advice use the facts or knowledge (a.k.a. World Size, Target position and Player position) as variables and don't hard code it. It'll be easier to debug and try different parameters.
Here you have the working code and some output example:
:- dynamic
getAllPathsRec/2,
agent/2,
visited/2.
gold(3, 3).
worldSize(5).
agent(1, 1).
getAllPaths :-
agent(X, Y),
getAllPathsRec(X, Y, [], []).
getAllPathsRec(X, Y, V, L) :-
hashPos(X, Y, H), \+member(H, V), append(V, [H], VP),
((gold(X, Y), print(L)) ; move(X, Y, VP, L)).
% Hash H from h(X, Y)
hashPos(X, Y, H) :- H is (X*100 + Y).
% Left
move(X, Y, V, L) :-
XP is X - 1, XP > 0,
append(L, [l], LP),
getAllPathsRec(XP, Y, V, LP).
% Right
move(X, Y, V, L) :-
XP is X + 1, worldSize(MS), XP =< MS,
append(L, [r], LP),
getAllPathsRec(XP, Y, V, LP).
% Up
move(X, Y, V, L) :-
YP is Y + 1, worldSize(MS), YP =< MS,
append(L, [u], LP),
getAllPathsRec(X, YP, V, LP).
% Down
move(X, Y, V, L) :-
YP is Y - 1, YP > 0,
append(L, [d], LP),
getAllPathsRec(X, YP, V, LP).
?- getAllPaths.
[r,r,r,r,u,l,l,l,l,u,r,r]
true ;
[r,r,r,r,u,l,l,l,l,u,r,u,l,u,r,r,r,r,d,l,l,d]
true ;
[r,r,r,r,u,l,l,l,l,u,r,u,l,u,r,r,r,r,d,l,d,l]
true ;
[r,r,r,r,u,l,l,l,l,u,r,u,l,u,r,r,r,r,d,d,l,l]
true ;
[r,r,r,r,u,l,l,l,l,u,r,u,l,u,r,r,r,r,d,d,l,u,l,d]
true ;
[r,r,r,r,u,l,l,l,l,u,r,u,l,u,r,r,r,d,l,d]
true ;
[r,r,r,r,u,l,l,l,l,u,r,u,l,u,r,r,r,d,r,d,l,l]
true ;
[r,r,r,r,u,l,l,l,l,u,r,u,l,u,r,r,r,d,d,l]
...
Basically I have a predicate pair(Z,X,Y)
I want to output all pairs of X and Y from 0 to Z
For example I want a call to look like
pair(3,X,Y).
X=0
Y=0;
X=0
Y=1;
X=0
Y=2;
X=0
Y=3;
X=1
Y=0;
X=1
Y=1;
...
X=3
Y=3;
So far I have
pair(_,0,0).
pair(Z,X,Y) :-
...
pair(S,X2,Y2)
...
I am new to Prolog so I am unsure how to fill in the areas separated by ...
What I think I should do is say something along the lines of
(In psuedocode)
"If Y2 = S then say X is X1 + 1 and Y is 0"
Or something along those likes.
But this seems like a very roundabout way of doing things. So I was wondering if there is a more elegant way.
A simpler way is to use the built-in predicate between/3:
pair(S, X, Y):-between(0, S, X), between(0, S, Y).
Edit:
If you want to build the pairs in sequence as you said, you may try something along this line:
pair(_, 0, 0).
pair(S, X, Y):- pair(S, X1, Y1),
(
S =:= Y1, (S =:= X1, !, false ; X is X1 + 1, Y is 0)
;
S =\= Y1, X is X1, Y is Y1 + 1
).
So, given a pair (X1, Y1) you infer the next one (X, Y) using the rules you described. If Y1 is equal to S, then you either terminate execute if X1 is equal to S too or you produce the pair (X1+1, 0). If Y1 is not equal to S, then you infer (X1, Y1+1).
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).