Prolog. How to output solution like Yes or No - prolog

I tried to solve the problem of a point belongs to the area. As a result, I need to get an answer: if a point belongs to the area or not.
Coordinates of the point entered by the user from the keyboard. When I try to transfer the coordinates of the point directly in a rule: belongsTo (1,1). I get the desired result (yes or no), but when I enter the coordinates with the keyboard
write ("Input X:"), readreal (X),
write ("Input Y:"), readreal (Y),
belongsTo (X, Y).
Then the answer will be 'no solutions' or just '2 solutions' (X = 0, Y = 0, X = 0, Y = 0, if you pass the point (0,0))
Here's the code completely:
PREDICATES
square(real,real)
semicircle(real,real)
belongsTo(real,real)
CLAUSES
square(X,Y):-
X>=-1,X<=0,
Y>=-1,Y<=0.
semicircle(X,Y):-
X>=0,Y>=0,
X*X+Y*Y<=1.
belongsTo(X,Y):-
square(X,Y);
semicircle(X,Y),!.
GOAL
write("Input X: "), readreal(X),
write("Input Y: "), readreal(Y),
belongsTo(X,Y).
As a result I need to get a solution like YES(if the point belongs to the area) or NO.

When you use the prompting method:
write("Input X:"), readreal(X),
write("Input Y:"), readreal(Y),
belongsTo(X, Y).
Prolog will display the values of X and Y along with the solution (yes or no) because these variables appear explicitly in your query. Any variables in your query it assumes you want to see the results of. If you just want to see yes or no, then you can make a predicate:
readuser :-
write("Input X:"), readreal(X),
write("Input Y:"), readreal(Y),
belongsTo(X, Y).
And then just query readuser. You'll then just get yes or no without the values of X and Y displayed.
As far as the different results, if you enter 0 and 0 for X and Y, this input will succeed twice: once for semicircle and once for square. Prolog faithfully finds both successful results.
When you are entering 1 and 1 and reading them as "real", I am suspecting that the internal representation is getting a little bit of floating point accuracy issue and internally becoming something like, 1.000000001 and these will fail both the semicircle and square tests.
As an aside, the semicircle is testing for the non-negative X and non-negative Y quadrant, not really a semicircle. Actual semicircle checks would be constraining just one of the coordinates in conjunction with X*X + Y*Y <= 1, e.g., X >= 0, X*X + Y*Y <= 1 would be the upper right and lower right quadrants of the semicircle.

Related

Prolog: Can't increase value of variable inside complex term

So I'm working on a prolog problem where a state is defined in a complex term, When I try to increase the value of x inside this complex term nothing happens for example
CurrentState(left, x, y).
test = CurrentState(left, x,y),
newX = x + 1,
write(newX).
Is there a workaround for this?
Facts and predicates need to start with a lowercase letter.
Variables need to start with an uppercase letter.
= is not assignment, and Prolog predicates aren't function calls, and you never use test anyway.
Even then, what do you want x + 1 to do when you haven't given any value for x? It makes no more sense than left + 1 written like that.
It would all be more like:
currentState(left, 5, 2). % fact
test(NewX) :-
currentState(Direction, X, Y), % search for the fact, fill the variables.
NewX is X + 1, % new variable for new value.
write(NewX).
Then
?- test(NewX).
6
NewX = 6
After that you still don't want to be storing the state as a fact in the Prolog database and removing/asserting it.

Checking all of facts in prolog

I have a number of facts that represents a cell with a row,Column and the number in that certain cell, And I want to check those facts just like checking a normal array .
I tried this function but it doesn't seem to work ,I don't think I am checking all my facts.
allcolored(X,Y) :-
cell(X,Y,_),
X1 is X - 1,
Y1 is Y - 1,
allcolored(X1,Y1).
If I understand you correctly, you want to check if, given a pair of X/Y coordinates, all positions in the grid spanned by those coordinates are covered by cell/3 facts. For arguments sake, let's consider that the following facts are currently present:
cell(1,1,100).
cell(1,2,200).
cell(1,3,300).
cell(2,1,110).
cell(2,2,120).
cell(2,3,130).
Looking at your attempt for a recursive rule, you try to check if, for a given pair, say 2/2, there are facts cell/3 for the pairs 2/2 and 1/1. But you probably want to check if the following pairs are covered: 2/2, 1/2, 2/1 and 1/1. As you can see in this sequence, the X-coordinate is being reduced to 1, then the Y-coordinate is decreased while the X-coordinate starts over at 2 again. So you need to preserve the original value of X somehow. This can be done with an auxiliary predicate with an additional argument. Your predicate allcolored/2 would then be the calling predicate for such a predicate, let's call it allcolored_/3:
allcolored(X,Y) :-
allcolored_(X,Y,X).
As #lurker already pointed out, your predicate is lacking a base case, where the recursion can stop. An obvious candidate for that would be the pair 1/1:
allcolored_(1,1,_) :-
cell(1,1,_).
Then a rule is needed to describe that all values between X and 2 have to be covered by cell/3:
allcolored_(X,Y,Max) :-
cell(X,Y,_),
X > 1,
Y >= 1,
X0 is X-1,
allcolored_(X0,Y,Max).
And an additional rule to describe the change to the next lower Y-coordinate, once X reached 1:
allcolored_(1,Y,Max) :-
cell(1,Y,_),
Y > 1,
Y0 is Y-1,
allcolored_(Max,Y0,Max).
Now you can test if a grid, spanned by the coordinates you provide, is covered by facts cell/3:
?- allcolored(2,2).
true ;
false.
?- allcolored(2,3).
true ;
false.
?- allcolored(3,3).
false.
Note that the above code assumes that the smallest coordinate in the grid is 1. To change that, to e.g. 0, you have to replace the 1's in the goals X >1, Y >= 1 and Y > 1 by 0's. Also note that due to the ordering of the goals (the cell/3 goals first) you can also ask questions like What grids are there that are covered by the facts of cell/3? :
?- allcolored(X,Y).
X = Y, Y = 1 ;
X = 2,
Y = 1 ;
X = Y, Y = 2 ;
X = 2,
Y = 3 ;
X = 1,
Y = 2 ;
X = 1,
Y = 3 ;
false.
Instead of checking for the existence of a fact for every pair of indices in range, check for the non-existence of non-existence of the fact for some pair of indices in range:
allcolored(X,Y) :-
\+ (between(1,X,A), between(1,Y,B), \+ cell(A,B,_)).
this says: allcolored(X,Y) holds if there are no indices A, B in allowed ranges (1..X, 1..Y) for which the fact cell(A,B) doesn't exist.
In other words, "there are no empty cells in the given area" is the same thing as "all cells in the given area are full".

SWI Prolog if statements, how do they work? Generating a simple grid

I realize I've edited out the if statements out of the original code which doesn't help readability and question clarity. Just skip to the answers for the explanation on how they work with a small example program.
To learn about more complex programs using if statements in Prolog, I'm creating a simple platformer that generates some objects and places them in a grid. First I'm trying to generate a simple 'world' with the idea of trying out generating things in prolog. The plan is to create a grid of 50 lists with 10000 items, which really shouldn't be that complicated but I can't get the if statements to work as I get the impression that I'm fundamentally misunderstanding how they work vs how I think they work. What happens is the condition isn't met, the if statement isn't called but the whole predicate is recalled with empty variables and evaluations are not instantiated.
Create a simple accumulator which has an X and Y axis, and limits to
how far they go before failing the predicate.
If the number of Y rows has been reached, terminate
Create a new [id, point(X,Y), Image] to be later filled with something
If X = end of the row, X is 0, else create the next point
Code:
generate(WorldList) :- generate_world(WorldList,0,_,10000,0,_,50).
generate_world([H|T],X,_,XEnd,Y,_,YEnd) :-
%Y has been filled with 50 rows, end recursion
not(Y > YEnd),
%iterate X by 1, store in XNew
XNew is X + 1,
%create a new [id,point(X,Y), Image]
H = [XNew,point(_,_)],
%if X has reached 10k, add 1 to Y and create a new row
X = XEnd -> YNew is Y + 1,
generate_world(T,0,_,XEnd,YNew,_,YEnd);
%continue adding items to current row Y
generate_world(T,XNew,_,XEnd,Y,_,YEnd).
generate_world([],_,_,_,_,_,_).
Am I doing something blatantly wrong or how are you supposed to use prolog conditional statements and can they even be used like this at all?
The way I expect it to work is a term is evaluated, then do what is to the left of the following OR if it's true, or the right if it's false. That happens, but I don't understand why the entire predicate is called again as it also empties the variables being evaluated. My brain hurts.
What the docs say: http://www.swi-prolog.org/pldoc/man?predicate=-%3E/2
#damianodamiano identified the problem, if statements in prolog need to be surrounded by () tags. I'd still like a more detailed explanation of how they actually work in regards to choice points, backtracking and other Prolog specific things I might not even know about.
Your predicate stops as soon as you run it because in not(By > YEnd), By is not instantiated (note that By is also a singleton variable and each singleton variable is useless and can drive to errors). Here i post two implementation, the first without if statement (which personally prefer), the second with if statement (i've put 2 and 2 as bound for brevity...).
First implementation:
generateList(L):-
generateWL(L,0,2,0,2).
generateWL([],0,_,Y,Y). %you can add a ! here
generateWL(L,MaxX,MaxX,R,MaxR):- %you can add a ! here
R1 is R+1,
generateWL(L,0,MaxX,R1,MaxR).
generateWL([H|T],X,MaxX,R,MaxR):-
X < MaxX,
R < MaxR,
X1 is X+1,
H = [X1,point(X1,R)],
generateWL(T,X1,MaxX,R,MaxR).
?- generateList(WL).
WL = [[1, point(1, 0)], [2, point(2, 0)], [1, point(1, 1)], [2, point(2, 1)]]
false
If you want to prevent backtracking, just add the two cuts i've annotated.
Second implementation
generateList2(L):-
generateWLIf(L,0,2,0,2).
generateWLIf([H|T],X,MaxX,R,MaxR):-
( X < MaxX, R < MaxR ->
X1 is X+1,
H = [X1,point(X1,R)],
generateWL(T,X1,MaxX,R,MaxR)
; X = MaxX, R < MaxR ->
R1 is R+1,
generateWL([H|T],0,MaxX,R1,MaxR)
; R = MaxR -> T = []).
?- generateList2(WL).
WL = [[1, point(1, 0)], [2, point(2, 0)], [1, point(1, 1)], [2, point(2, 1)]]
(Continuing from the comments)
The way I expect [conditional statements] to work is a term is
evaluated, then do what is to the left of the following OR if it's
true, or the right if it's false. That happens, but I don't understand
why the entire predicate is called again as it also empties the
variables being evaluated.
You probably mean that it back-tracks, and the reason is that the comparison not(Y > YEnd) eventually fails, and there is no else-clause (and no if either).
Also, your base case makes no sense, as the list is output not input. And you want to compare against XNew not X.
generate(WorldList) :-
generate_world(WorldList,1,10000,1,50).
generate_world(T,X,XEnd,Y,YEnd) :-
( Y = YEnd ->
T = []
; T = [point(X,Y)|Rest], XNew is X + 1,
( XNew = XEnd -> YNew is Y + 1,
generate_world(Rest,1,XEnd,YNew,YEnd)
; generate_world(Rest,XNew,XEnd,Y,YEnd) ) ).
This would seem to work in the sense that it does what you describe, but it is not good design. Now you have to pass this enormous list around all the time, and updating one location means deconstructing the list.
Your problem:
I'm creating a simple platformer that generates some objects and
places them in a grid. First I'm trying to generate a simple 'world'
with the idea of trying out generating things in prolog. The plan is
to create a grid of 50 lists with 10000 items
is much better solved in Prolog by having a predicate location/3 (for example) where the parameters are the coordinates and the content.
location(1,1,something).
location(1,2,something).
location(1,3,somethingelse).
...
And this predicate is created dynamically, using assert/3.
This is based on my understanding of ISO-prolog and the other answers given, boiled down to the essence of how if then else works in Prolog.
The if predicate -> forces evaluation its the surrounding complex terms grouped by ( and ). The outer brackets identify the if-statement as ( if -> then ; else ), where if,then and else are each goals in the form of terms to be evaluated, which return yes or no, also grouped by ( and ). Whether then or else is called, separated by the OR operator ;, depends on the yes or no result from the evaluated term represented by if. The outer groupings are strictly necessary while the inner ones are optional, BUT it's good practice in my opinion to add them anyway, given that you can nest another if statement as a term surrounded by () in the result of the first, which likely produces unwanted result and makes the code much harder to read, and any non-grouped nested ; will identify the right side as the else.
Choice points are created where there are variables that can have multiple possible answers as a possible solution to the posed goal. This means within an if, if a term can be satisfied in multiple ways, Prolog will try to satisfy that goal as a separate goal and then use the result to determine the outcome of the surrounding term. If a goal fails, it behaves like normal code and doesn't try to satisfy the goals further right.
If a choice point is before the whole if statement section, the whole section will be checked again.
Example program to clarify the idea.
fact(a).
fact(f).
start :-
(
%The entire complex term is evaluated as yes
(fact(a), write('first if'), nl) ->
%triggers the first line
(write('first then'),nl) ;
(write('first else'),nl)
),
(
%The entire complex term is evaluated as no
(fact(B), write('second if'), B = b, nl) ->
(write('second then'),nl) ;
%triggers the second line
(write('second else'),nl)
).
And the output for ?- start.
first if
first then
second ifsecond ifsecond else

Prompt does not come back

I try to do some exercise - to represent numbers in "s representation" which means '0' is zero, s(0) is 1, s(s(0)) is 2 and so on.
I tried to write predicate for adding "s numbers":
the predicate s2int convert "s number" to int.
s2int(0, 0).
s2int(s(X), Y) :-
s2int(X, Y1),
Y is 1 + Y1.
add(X, Y, Z) :-
s2int(X, SX),
s2int(Y, SY),
s2int(Z, SZ),
SZ is SX + SY.
When I query add it writes the correct answer but the prompt does not come back.
What's the problem?
Your definition of add/3 works fine, and also terminates, if all three arguments are given. If you leave one of them as a variable, one of the goals s2int(XYZ, SXYZ) has then two uninstantiated variables as arguments. It describes thus an infinitely large set, whose complete enumeration takes infinitely long.
Not sure what you are after, but probably you want to define add/3 for successor arithmetics. You can do this, without resorting to the 0,1,2 integers! Try it! Otherwise search of successor-arithmetics.

using arithmetic operations in Prolog

I have the following code:
position(0,0).
move(f):-
position(X,Y),
number(X),
number(Y),
Y is Y+1,
X is X+1.
but when i call move(f) it returns false. number(X) and number(Y) returns true but whem i add the other two lines the function doesn't work. what's the problem?
Elaborating on some of the comments your question has received, variables in Prolog stand for a possible instantiation of a single value, just like variables in mathematics and mathematical logic, and once they are instantiated within a context they must remain consistent. If we're dealing with a formula 0 = (a + b) - (a + b), we know that it can only express its intended sense if any value assigned to the first a is also assigned to the second. That is, we can substitute any value for a, but it must be the same value throughout. Prolog works with variables in this same way. If x = x + 1, then 2 = 3; but then math would be broken.
Addressing mat's caution against using dynamic predicates, here is a possible way of handling moves, but accomplished by passing around a list of previous moves. With this method, the most recent move will always be the first element of List in the compound term moves(List).
Supposing the current history of moves is as follows:
moves([position(0,0), position(0,1), position(1,1)]).
move/3 takes a direction, a complex term representing the previous moves, and tells us what the updated list of moves is.
move(Direction, moves([From|Ms]), moves([To,From|Ms])) :-
move_in_direction(Direction,From,To).
move_in_direction/3 takes a direction, and a position, and tells us what the next position in that direction is:
move_in_direction(left, position(X1,Y1), position(X2,Y1)) :- X2 is X1 - 1.
move_in_direction(right, position(X1,Y1), position(X2,Y1)) :- X2 is X1 + 1.
move_in_direction(up, position(X1,Y1), position(X1,Y2)) :- Y2 is Y1 + 1.
move_in_direction(down, position(X1,Y1), position(X1,Y2)) :- Y2 is Y1 - 1.
Notice that, using this method, you get a back-trackable history of moves for free. I'd imagine you could use this in interesting ways -- e.g. having the player explore possible series of moves until a certain condition is met, at which point it commits or backtracks. I'd be interested to know what kind of solution you end up going with.

Resources