Check if a number is between 2 values - prolog

I am new to prolog and have am trying to write a program that will do the following tell me if a number is between 2 values I can do the following:
between(L, X, R) :-
X > L, X < R.
and doing between(1, 3, 5) works, but I would like it to be able to do between(1, X, 5) and have prolog return all the values in between so in this case X = 2, X = 3, X = 4, I get why my solution doesn't because it needs to be have been initialised, but I cannot think of a solution to this problem, can this type of thing just not be done in prolog?, and help would be great thanks

In case you don't want to predefine all numbers: let prolog create a list with possible entries and state your X has to be one of them. To understand the code you have to have knowledge about lists in prolog, especially Head and Tail notation of lists.
betweenList(L,R,[]):-
L>=R.
betweenList(L,R,[L|Rest]):-
L<R,
LL is L+1,
betweenList(LL,R,Rest).
between(L, X, R) :-
betweenList(L, R, [L| List]),
member(X, List).
?- between(1,X,5).
X = 2 ;
X = 3 ;
X = 4 ;
false.
betweenList(L,R,List) creates a List of all numbers between L and R, including L (as head element), excluding R. So if you want to generate a List without L, it is the easiest to just call betweenList(L, R, [L| List]) so List will not include L. Now X just has to be a member of List. The member/2 predicate can be easily written as well if you don't want to use the inbuild predicate.

One way to approach this:
digit(0).
digit(1).
digit(2).
digit(3).
digit(4).
digit(5).
digit(6).
digit(7).
digit(8).
digit(9).
between(L, X, U) :- digit(L), digit(X), digit(U), L < X, X < U.
Tests:
?- between(2, X, 5).
X = 3 ;
X = 4 ;
false.
?- between(2, 7, U).
U = 8 ;
U = 9.
Alternatively, you may want to look into Constraint logic programming.
Incidentally, Prolog already has a between/3:
?- between(1, 5, X).
X = 1 ;
X = 2 ;
X = 3 ;
X = 4 ;
X = 5.
although it's "illogical": you can't run it backwards, as the above definition.

Related

Why does this prolog rule using include/3 evaluate to false, but not when exploding it into individual comparisons?

I have a prolog rule position_that_is_equals_to_two that sets X to the position at which the number 2 was found in the provided list of three elements [X, Y, Z]:
position_that_is_equals_to_two([X, Y, Z], X) :-
include(==(2), [X, Y, Z], AllElementsWhichHaveAValueOfTwo),
nth0(0, AllElementsWhichHaveAValueOfTwo, X).
When querying it, I immediately get false:
?- position_that_is_equals_to_two([X, _, _], X)
false
However, when I replace include/3 with individual comparisons, prolog gives three possible values for X, which is the output I would expect:
position_that_is_equals_to_two([X, Y, Z], X) :-
(
( X == 2 ; X #= 1)
; ( Y == 2 ; X #= 2)
; ( Z == 2 ; X #= 3)
).
Querying it:
?- position_that_is_equals_to_two([X, _, _], X)
X = 1
X = 2
X = 3
Why is the first variant returning false? How can it me modified to (1) still use include and (2) list possible values for X, like the second variant does?
How can it be modified to still use include?
It can't. Include shrinks the original list and throws away information you need to answer the question. With AllElementsWhichHaveAValueOfTwo = [2] what is the index of that two? Was it 0, 1, 2 or 50,000? You can't know.
Worse, include/3 has the signature include(:Goal, +List1, ?List2) and the + means the List1 must be provided, you can't give it unground variables like [X,Y,Z] and have it fill them in. So it can't be used for that reason also.
Take this query:
?- position_that_is_equals_to_two([X, _, _], X)
What you expect out of it is that X in the list has value two and X as the index has value zero. You want 2 = 0. That can't work.
Your other code is giving the right answer for the wrong reasons; the code (X == 2 ; X #= 1) says "variable X must be two OR variable X must be one" which is allowed but for your indexing you need them both at the same time, not either/or. What you want it to say is "first list item must be two AND the index must be one".
Change the code to (X = 2, X = 1) which is logically how it should be and you're back to asking for 2 = 1 which can't work.
In your example code, X is being used for 2 different purposes and values - that's a conflict.
== is not clpfd.
Looks like this would be sufficient (without using clpfd):
pos_2(Pos, L) :-
length(L, 3),
nth1(Pos, L, 2).
Result in swi-prolog:
?- pos_2(Pos, L).
Pos = 1,
L = [2, _, _] ;
Pos = 2,
L = [_, 2, _] ;
Pos = 3,
L = [_, _, 2].

Prolog: How do I list the different values that X and Y could be using prolog's clpfd library?

test(X, Y) :-
X ins 1..3,
Y ins 1..3,
X #\= Y.
Here is my attempt at doing it. The goal would be to type this into SWI-Prolog so that this output comes out.
?- test(X, Y).
X = 1
Y = 2 ;
X = 2,
Y = 1;
X = 3,
Y = 1 ;
... etc.
I'm actually trying to solve the 8-queens problem using prolog and have this so far.
eight_queens(Qs, L) :-
Qs = [ [X1,Y1], [X2, Y2], [X3, Y3], [X4, Y4], [X5, Y5], [X6, Y6], [X7, Y7], [X8, Y8], [X9, Y9] ],
Qs ins 1..9,
X1 #\= X2,
X1 #\= X3,
...
etc.
But I keep getting this error: "Arguments are not sufficiently instantiated" for both the test function and the eight_queens problem.
Besides the observation about in/2 and ins/2 posted by #coder, that solve your imminent problem, I would add the following points that are good to keep in mind when using CLP(FD):
1. Always make labeling the last goal
First let's observe the answers for the variant marked as 2nd way using ins in #coder's post but without the goal label/1:
test(X, Y) :-
[X,Y] ins 1..3,
X #\= Y.
?- test(X,Y).
X in 1..3, % residual goal
X#\=Y, % residual goal
Y in 1..3. % residual goal
Since there is no unique answer to the query, Prolog answers with residual goals (see section A.8.8 of the CLP(FD) manual) for more information). These residual goals are constraints that are being propagated and with every additional (non-redundant) constraint the domain is narrowed. If this does not lead to a unique solution like in the example above you can get concrete values by labeling the constrained variables (e.g. with label/1). This observation suggests to use labeling as the last goal:
?- test(X,Y), label([X,Y]).
X = 1,
Y = 2 ;
X = 1,
Y = 3 ;
X = 2,
Y = 1 ;
X = 2,
Y = 3 ;
X = 3,
Y = 1 ;
X = 3,
Y = 2.
This is obviously the same result as with #coders version but the three pairs (X,Y) = (1,1) ∨ (2,2) ∨ (3,3) are not considered when labeling due to the constraint X#\=Y being posted before the goal label([X,Y]). In #coder's version it is the other way around: label([X,Y]) is delivering all three pairs as possible solutions and the last goal X#\=Y is eliminating them subsequently. To see this just leave the last goal as a comment and query the predicate:
test(X,Y):- [X,Y] ins 1..3, label([X,Y]). %, X#\=Y.
?- test(X,Y).
X = Y, Y = 1 ; % <- (1,1)
X = 1,
Y = 2 ;
X = 1,
Y = 3 ;
X = 2,
Y = 1 ;
X = Y, Y = 2 ; % <- (2,2)
X = 2,
Y = 3 ;
X = 3,
Y = 1 ;
X = 3,
Y = 2 ;
X = Y, Y = 3. % <- (3,3)
The difference is minuscule in this example, so there's nothing wrong with #coder's version. But in general this might lead to a big difference if the constraints posted after labeling exclude a lot of candidates. So it's good practice to always put labeling as the last goal.
2. Separate labeling from the actual relation
Coming from the previous observations it is opportune to divide the predicate into a core relation that is posting all the constraints and labeling. Consider the restructured predicate test/2 as a template:
test(X,Y) :-
test_(X,Y,L), % the core relation
label(L). % labeling
test_(X,Y,L) :-
L=[X,Y], % variables to be labeled in a flat list
L ins 1..3,
X#\=Y.
The predicate test_/3 is describing the actual relation by posting all the necessary constraints and has a list as an additional argument that contains all the variables to be labeled. Obtaining the latter might not be trivial, depending on the data structures your arguments come with (consider for example a list of lists as an argument that you want to turn into a flat list for labeling). So the predicate test/2 is only calling test_/3 and subsequently the labeling goal. This way you have a clean and easily readable separation.
3. Try different labeling strategies
The goal label(L) is the simplest way to do labeling. It is equivalent to labeling([],L). The first argument of labeling/2 is a list of options that gives you some control over the search process, e.g. labeling([ff],L) labels the leftmost variable with the smallest domain next, in order to detect infeasibility early. Depending on the problem you are trying to solve different labeling strategies can lead to results faster or slower. See the documentation of labeling/2 for available labeling strategies and further examples.
ins is used for lists, in is used for single variable so in your example:
test(X, Y) :-
X ins 1..3,
Y ins 1..3,
X #\= Y.
X,Y are assumed to be lists. This does not produces a syntax error, but produces error when trying to run it with X,Y not being lists.
Also when using in Low..High doesn't mean that the variable is int just X=<High and X>=Low. In order to put the constraint to be integers use label/1:
:- use_module(library(clpfd)).
%using in/
test(X,Y):- X in 1..3,Y in 1..3,label([X,Y]), X#\=Y.
%2nd way using ins
test(X,Y):- [X,Y] ins 1..3, label([X,Y]), X#\=Y.
Example:
?- test(X,Y).
X = 1,
Y = 2 ;
X = 1,
Y = 3 ;
X = 2,
Y = 1 ;
X = 2,
Y = 3 ;
X = 3,
Y = 1 ;
X = 3,
Y = 2 ;
false.

What does this wildcard do in this prolog scenario?

I've come across this code:
connectRow(_,_,0).
connectRow([spot(_,R,_,_)|Spots],R,K) :- K1 is K-1, connectRow(Spots,R,K1).
/*c*/
connectRows([]).
connectRows(Spots) :-
connectRow(Spots,_,9),
skip(Spots,9,Spots1),
connectRows(Spots1).
How does the wildcard in the connectRow(Spots,_,9) work? How does it know which values to check and how does it know that it checked all the possible values?
Edit: I think I understand why this works but I'd like it if someone could verify this for me:
When I "call" the connectRow with the wildcard it matches the wildcard with the "R" in the connectRow predicate. Could this be it?
The _ is just like any other variable, except that each one you see is treated as a different variable and Prolog won't show you what it unifies with. There's no special behavior there; if it confuses you about the behavior, just invent a completely new variable and put it in there to see what it does.
Let's talk about how Prolog deals with variables. Here's an experiment you can follow along with that should undermine unhelpful preconceived notions if you happen to have them.
?- length([2,17,4], X)
X = 3.
A lot of Prolog looks like this and it's easy to fall into the trap of thinking that there are designated "out" variables that work like return values and designated "in" variables that work like parameters. After all:
?- length([2,17,4], 3).
true.
?- length([2,17,4], 5).
false.
Here we begin to see that something interesting is happening. A faulty intuition would be that Prolog is somehow keeping track of the input and output variables and "checking" in this case. That's not what's happening though, because unification is more general than that. Observe:
?- length(X, 3).
X = [_G2184, _G2187, _G2190].
We've now turned the traditional parameter/return value on its head: Prolog knows that X is a list three items long, but doesn't know what the items actually are. Believe it or not, this technique is frequently used to generate variables when you know how many you need but you don't need to have them individually named.
?- length(X, Y).
X = [],
Y = 0 ;
X = [_G2196],
Y = 1 ;
X = [_G2196, _G2199],
Y = 2 ;
X = [_G2196, _G2199, _G2202],
Y = 3
It happens that the definition of length is very general and Prolog can use it to generate lists along with their lengths. This kind of behavior is part of what makes Prolog so good at "generate and test" solutions. You define your problem logically and Prolog should be able to generate logically sound values to test.
All of this variation springs from a pretty simple definition of length:
length([], 0).
length([_|Rest], N1) :-
length(Rest, N0),
succ(N0, N1).
The key is to not read this like a procedure for calculating length but instead to see it as a logical relation between lists and numbers. The definition is inductive, relating the empty list to 0 and a list with some items to 1 + the length of the remainder of the list. The engine that makes this work is called unification.
In the first case, length([2,17,4], X), the value [17,4] is unified with Rest, N0 with 2 and N1 with 3. The process is recursive. In the final case, X is unified with [] and Y with 0, which leads naturally to the next case where we have some item and Y is 1, and the fact that the variable representing the item in the list doesn't have anything in particular to unify with doesn't matter because the value of that variable is never used.
Looking at your problem we see the same sort of recursive structure. The predicates are quite complex, so let's take them in pieces.
connectRow(_, _, 0).
This says connectRow(X, Y, 0) is true, regardless of X and Y. This is the base case.
connectRow([spot(_, R, _, _)|Spots], R, K) :-
This rule is matching a list of spots of a particular structure, presuming the first spot's second value (R) matches the second parameter.
K1 is K-1, connectRow(Spots, R, K1).
The body of this clause is essentially recurring on decrementing K, the third parameter.
It's clear now that this is basically going to generate a list that looks like [spot(_, R, _, _), spot(_, R, _, _), ... spot(_, R, _, _)] with length = K and no particular values in the other three positions for spot. And indeed that's what we see when we test it:
?- connectRow(X, Y, 0).
true ;
(infinite loop)^CAction (h for help) ? abort
% Execution Aborted
?- connectRow(X, Y, 2).
X = [spot(_G906, Y, _G908, _G909), spot(_G914, Y, _G916, _G917)|_G912] ;
(infinite loop)^CAction (h for help) ? abort
So there seem to be a few bugs here; if I were sure these were the whole story I would say:
The base case should use the empty list rather than matching anything
We should stipulate in the inductive case that K > 0
We should use clpfd if we want to be able to generate all possibilities
Making the changes we get slightly different behavior:
:- use_module(library(clpfd)).
connectRow([], _, 0).
connectRow([spot(_, R, _, _)|Spots], R, K) :-
K #> 0, K1 #= K-1, connectRow(Spots, R, K1).
?- connectRow(X, Y, 0).
X = [] ;
false.
?- connectRow(X, Y, 1).
X = [spot(_G906, Y, _G908, _G909)] ;
false.
?- connectRow(X, Y, Z).
X = [],
Z = 0 ;
X = [spot(_G918, Y, _G920, _G921)],
Z = 1 ;
X = [spot(_G918, Y, _G920, _G921), spot(_G1218, Y, _G1220, _G1221)],
Z = 2
You'll note that in the result we have Y standing in our spot structures, but we have weird looking automatically generated variables in the other positions, such as _G918. As it happens, we could use _ instead of Y and see a similar effect:
?- connectRow(X, _, Z).
X = [],
Z = 0 ;
X = [spot(_G1269, _G1184, _G1271, _G1272)],
Z = 1 ;
X = [spot(_G1269, _G1184, _G1271, _G1272), spot(_G1561, _G1184, _G1563, _G1564)],
Z = 2
All of these strange looking variables are there because we used _. Note that all of the spot structures have the exact same generated variable in the second position, because Prolog was told it had to unify the second parameter of connectRow with the second position of spot. It's true everywhere because R is "passed along" to the next call to connectRow, recursively.
Hopefully this helps explain what's going on with the _ in your example, and also Prolog unification in general.
Edit: Unifying something with R
To answer your question below, you can unify R with a value directly, or by binding it to a variable and using the variable. For instance, we can bind it directly:
?- connectRow(X, 'Hello, world!', 2).
X = [spot(_G275, 'Hello, world!', _G277, _G278), spot(_G289, 'Hello, world!', _G291, _G292)]
We can also bind it and then assign it later:
?- connectRow(X, R, 2), R='Neato'.
X = [spot(_G21, 'Neato', _G23, _G24), spot(_G29, 'Neato', _G31, _G32)],
R = 'Neato'
There's nothing special about saying R=<foo>; it unifies both sides of the expression, but both sides can be expressions rather than variables:
?- V = [2,3], [X,Y,Z] = [1|V].
V = [2, 3],
X = 1,
Y = 2,
Z = 3.
So you can use R in another predicate just as well:
?- connectRow(X, R, 2), append([1,2], [3,4], R).
X = [spot(_G33, [1, 2, 3, 4], _G35, _G36), spot(_G41, [1, 2, 3, 4], _G43, _G44)],
R = [1, 2, 3, 4] ;
Note that this creates opportunities for backtracking and generating other solutions. For instance:
?- connectRow(X, R, 2), length(R, _).
X = [spot(_G22, [], _G24, _G25), spot(_G30, [], _G32, _G33)],
R = [] ;
X = [spot(_G22, [_G35], _G24, _G25), spot(_G30, [_G35], _G32, _G33)],
R = [_G35] ;
X = [spot(_G22, [_G35, _G38], _G24, _G25), spot(_G30, [_G35, _G38], _G32, _G33)],
R = [_G35, _G38] ;
Hope this helps!

Prolog: pythagorean triple

I have this code that uses an upper bound variable N that is supposed to terminate for X and Y of the pythagorean triple. However it only freezes when it reaches the upper bound. Wasn't sure how to use the cut to stop the backtracking. Code is:
is_int(0).
is_int(X) :- is_int(Y), X is Y+1.
minus(S,S,0).
minus(S,D1,D2) :- S>0, S1 is S-1, minus(S1,D1,D3), D2 is D3+1.
pythag(X,Y,Z,N) :- int_triple(X,Y,Z,N), Z*Z =:= X*X + Y*Y.
int_triple(X,Y,Z,N) :- is_int(S), minus(S,X,S1), X>0, X<N,
minus(S1,Y,Z), Y>0, Y<N.
Will be called, for example with,
?- pythag(X,Y,Z,20).
First, let us test your solution:
?- pythag(X,Y,Z,20).
X = 4, Y = 3, Z = 5
; X = 3, Y = 4, Z = 5
; X = 8, Y = 6, Z = 10
; X = 6, Y = 8, Z = 10
; X = 12, Y = 5, Z = 13
; X = 5, Y = 12, Z = 13
; X = 12, Y = 9, Z = 15
; X = 9, Y = 12, Z = 15
; X = 15, Y = 8, Z = 17
; X = 8, Y = 15, Z = 17
; X = 16, Y = 12, Z = 20
; X = 12, Y = 16, Z = 20
; loops.
Looks perfect to me! All answers are correct solutions! ... up to and including this last solution. After that, your program loops.
Before we try to identify the problem, just hold on for a moment: You must be pretty patient to go through 12 (that is: twelve) answers only to find that loop. Do you think that this method will also work for bigger cases? How many answers are you willing to look at before you give up? Isn't there a simpler way to find out about the problem?
There is one interesting observation here: The answers found have (almost) nothing to do with the looping of the program! That is: By looking at the answers, you get (frequently – as in this case) no clue about the actual cause of the loop! So why not turn off all the answers and concentrate on the relevant part! In fact, we can do this as follows:
?- pythag(X,Y,Z,20), false.
loops.
Now, all answers have been removed due to the goal false. What remains is just the final outcome: either termination, or non-termination, or some error. Nothing else. This should facilitate our observations about termination a bit - no more blinding answers scrolling over the screen. Note that this does not solve the problem in general. After all, how long are we willing to wait? 1s ? 1m?
The actual reason of non-termination can be best understood by looking at a relevant failure slice. That is a fragment of the program whose non-termination implies the non-termination of the whole program. See this answer for more details. Here is the relevant failure slice of your program for query pythag(X,Y,Z,20), false:
pythag(X,Y,Z,N) :-
int_triple(X,Y,Z,N), false,
Z*Z =:= X*X + Y*Y.
int_triple(X,Y,Z,N) :-
is_int(S), false,
minus(S,X,S1), X>0, X<N,
minus(S1,Y,Z), Y>0, Y<N.
is_int(0) :- false.
is_int(X) :-
is_int(Y), false,
X is Y+1.
Note that there are not many things left of your program. E.g., the actual equation is gone (that's more or less the logic part...). Still, this fragment is relevant. And as long as you do not change something within that fragment, the problem will persist! That is guaranteed for a pure monotonic program as this one...
Here is my preferred solution: It uses length/2 and between/3, two frequently supported predicates of the Prolog prologue.
pythag2(X,Y,Z,N) :-
length(_, N),
between(1,N,X),
between(1,N,Y),
between(1,N,Z),
Z*Z =:= X*X + Y*Y.
I was recently as well thinking about a Prolog solution to
find Pythagorean triples. I came up with a slightly different
code. Assume we have a function:
isqrt(a) = floor(sqrt(a))
It is then enough to enumerate x and y, and to check whether
x*x+y*y is the square of some z. Namely to check for:
h = x*x+y*y, z = isqrt(h), z*z = h ?
The function isqrt can be implemented via bisection. For
symmetry breaking we can enumerate y after x. Assuming
N = 99 the resulting code is:
% between(+Integer, +Integer, -Integer)
between(Lo, Hi, _) :-
Lo > Hi, !, fail.
between(Lo, _, Lo).
between(Lo, Hi, X) :-
Lo2 is Lo+1, between(Lo2, Hi, X).
% bisect(+Integer, +Integer, +Integer, -Integer)
bisect(Lo, Hi, X, Y) :-
Lo+1 < Hi, !,
M is (Lo+Hi) // 2,
S is M*M,
(S > X -> bisect(Lo, M, X, Y);
S < X -> bisect(M, Hi, X, Y);
M = Y).
bisect(Lo, _, _, Lo).
% pythago(-List)
pythago(X) :-
X = [A,B,C],
between(1, 99, A),
between(A, 99, B),
H is A*A+B*B,
bisect(0, H, H, C),
C =< 99, H =:= C*C.
There should be 50 such Pythagorean tripples, see also Sloan's A046083:
?- findall(-, pythago(_), L), length(L, N).
N = 52.
One might like to cross check with the following
CLP(FD) solution.
:- use_module(library(clpfd)).
% pythago3(-List)
pythago3(X) :-
X = [A,B,C],
X ins 1..99,
A*A+B*B #= C*C,
A #=< B,
label(X).
It gives the same number of solutions:
?- findall(-, pythago3(_), L), length(L, N).
N = 50.

Understanding prolog [lists]

I am to write a program that does this:
?- pLeap(2,5,X,Y).
X = 2,
Y = 3 ;
X = 3,
Y = 4 ;
X = 4,
Y = 5 ;
X = 5,
Y = 5 ;
false.
(gives all pairs X,X+1 between 2 and 5, plus the special case at the end).
This is supposedly the solution. I don't really understand how it works, could anyone guide me through it?
pLeap(X,X,X,X).
pLeap(L,H,X,Y) :-
L<H,
X is L,
Y is X+1.
pLeap(L,H,X,Y) :-
L=<H,
L1 is L+1,
pLeap(L1,H,X,Y).
I'd do it simply like this:
pLeap(L,H,X,Y) :-
X >= L,
X =< H,
Y is X+1.
Why doesn't it work (ignoring the special case at the end)?
You could use library clpfd for you problem.
:- use_module(library(clpfd)).
pLeap(L,H,X,Y) :-
X in L..H,
Y #= min(H, X+1),
label([X]).
Here is the output:
?- pLeap(2,5,X,Y).
X = 2,
Y = 3 ;
X = 3,
Y = 4 ;
X = 4,
Y = 5 ;
X = 5,
Y = 5.
The >= and =< operators don't instantiate their arguments, and you can only use them once the arguments have already been instantiated.
Put another way, in the given solution, X and Y are given values with is, and the < and =< operators are only used on L and H, whose values are given by the user. (On the given solution, try pLeap(L,H,2,3) and you'll get the same problem as you're having.)
In your case, though, you try to use >= and =< on X, which has no value yet, and so the interpreter complains.

Resources