Let's say we have two variables X and Y. X is 53 and Y is 52. What I want to do is compare them by adding 1 to the Y, so that it would be 53 - therefore X would be equal to Y + 1.
I am trying to do it by simply using equal operator and addition for Y variables, like so:
X == Y + 1
Even though this looks simple enough, I am getting false as the result. What am I missing?
?- X = 50+2, Y = 50+1, X =:= Y + 1.
as you can see, (=:=)/2 evaluates both sides, as do (>)/2, etc
If you are reasoning over integers, use your Prolog system's CLP(FD) constraints to compare and evaluate arithmetic integer expressions.
For example, in SICStus, SWI and YAP, after use_module(library(clpfd):
?- 53 #= 52 + 1.
true.
This works in all directions.
Other examples:
?- X #= 52 + 1.
X = 53.
?- 53 #= Y + 1.
Y = 52.
?- 53 #= 52 + 1.
true.
In order to evaluate expression trees, the is predicate is used:
X is Y+1.
you must be careful however, this will only work as a test if both X and Y are grounded. And will always error if variables on the right hand side (Y in this case) is not grounded.
swipl demo:
?- X = 53, Y = 52, X is Y+1.
X = 53,
Y = 52.
?- X = 53, Y = 52, X is Y.
false.
?- X = 53, X is Y+1.
ERROR: is/2: Arguments are not sufficiently instantiated
?- Y = 52, X is Y+1.
Y = 52,
X = 53.
Related
Trying to calculate the triangular number sequence in Prolog.
This is my solution:
where X is the nth position of the sequence and Y is the result.
triang(1, 1).
triang(X, Y) :-
X>0,
A is X - 1,
triang(A, B),
Y is B + X.
?- triang(5,X).
X = 15
But when i try to do for example triang(X,10) I receive an error
Arguments are not sufficiently instantiated.
I guess this is because X is not defined in the consult.
is there any recommendation how to solve this problem,thank you.
First of all, the result you got is not that bad. It says: sorry, I am unable to come to a conclusion and before producing an incorrect result, I prefer to produce an error.
The actual reason is the following goal
?- X > 0.
error(instantiation_error,(is)/2).
So here we ask for X that are greater than zero. And there are many, in fact infinitely many. There is no direct way to enumerate that set for this built-in and thus it prefers the error.
However, with library(clpz) or clpfd, there is a better way:
:- use_module(library(clpz)). % use clpfd for SWI instead
:- op(150, fx, #).
triang(0, 0).
triang(X, Y) :-
#X #>0,
#Y #>0,
#A #= #X - 1,
#Y #= #B + #X,
triang(A, B).
?- triang(X,15).
X = 5
; false.
?- triang(X,14).
false.
?- triang(X,X).
X = 0
; X = 1
; false.
?- triang(X,Y).
X = 0, Y = 0
; X = 1, Y = 1
; X = 2, Y = 3
; X = 3, Y = 6
; X = 4, Y = 10
; X = 5, Y = 15
; X = 6, Y = 21
; ... .
?- #X #> 0.
clpz:(X in 1..sup).
So now there is an answer to #X #> 0. The answer is often called a constraint. In this case it tells us that X must be in the interval 1 up to (kind of) infinity.
I am trying to solve first linear programming problem example on http://www.zweigmedia.com/RealWorld/tutorialsf4/framesLinProGr.html. X and Y are zero or positives, their sum can be upto 50, 2X+Y can be upto 60. The function X+3Y has to be maximized.
I am using following code:
mysol2(X,Y,Z):-
X in 0..sup, % Error: Syntax error: Operator expected
Y in 0..sup,
X + Y =< 50,
2 * X + Y =< 60,
Z is max(X + 3*Y).
However, it does not even load (error is indicated above).
With following code:
mysol2(X,Y,Z):-
X >= 0,
Y >= 0,
X + Y =< 50,
2 * X + Y =< 60,
Z is max(X + 3*Y).
The program loads, but on running:
ERROR: >=/2: Arguments are not sufficiently instantiated
How can I correct these errors?
(>=)/2 and (is)/2 are very low-level predicates. You can only use them in very special circumstances. In most cases, these predicates will lead to instantiation errors because one or both arguments are not sufficiently instantiated.
Constraints are a declarative solution in such cases, working correctly in all cases.
For example, you can use CLP(Q) as available in SICStus Prolog with minimal modifications of your code:
:- use_module(library(clpq)).
solution(X, Y) :-
{ X >= 0,
Y >= 0,
X + Y =< 50,
2*X + Y =< 60 }.
Sample query and result:
| ?- solutionX, Y), maximize(X+3*Y).
X = 0,
Y = 50 ? ;
no
The most widely used Prolog and Prolog-like systems (SICStus, ECLiPSe etc.) all ship with powerful constraint libraries, which are meant to be used notably when reasoning over integers and rationals.
I could not find division (/) symbol on this page of CLP(FD): http://www.swi-prolog.org/man/clpfd.html
Also this simple code give error:
:-use_module(library(clpfd)).
afn(A,B,C):-
C #= B / A.
?- afn(23, 56, C).
ERROR: Domain error: `clpfd_expression' expected, found `56/23'
Where is the problem and how can this be solved? Thanks.
In ISO Prolog (/)/2 yields a float result. SWI-Prolog is not ISO compliant here, it casts to an integer where possible. But basically (/)/2 is viewed as an operation between machine real numbers, that gives a new approximated machine real number.
On the other hand CLP(FD) works only with integers. Therefore, I guess, this is the reason that CLP(FD) usually don't support the (/)/2 operator. On the otherhand the div operator (//)/2 from ISO Prolog, works also for CLP(FD). Supported are:
Expr // Expr Truncated integer division
Expr div Expr Floored integer division
Here is an example run:
Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.4)
?- use_module(library(clpfd)).
true.
?- X #= 100 // Y, Y = 7.
X = 14,
Y = 7.
?- X #= Z // 7, X = 14.
X = 14,
Z in 98..104.
If you have a CLP(FD) without the (//)/2 operator, you can simulate it. Instead of X #= Y//Z, you can write X*Z+R #= Y, 0 #=< R, R #< Z. When negative arguments are involved you need a more complex formula.
Here are some example runs that show that this approach also works:
?- X*Y+R #= 100, 0 #=< R, R #< Y, Y = 7.
X = 14,
Y = 7,
R = 2.
?- X*7+R #= Z, 0 #=< R, R #< 7, X = 14.
X = 14,
R in 0..6,
-98+Z#=R,
Z in 98..104.
I want to write the equivalent psudo-function in prolog:
function underhundred(X){
if (X >= 0 && X <=100) return 1;
else return 0;
}
I tried writing this but it does not compile:
underhundred(X,L) :- L is (X => 0, X =< 100 -> L = 1; L = 0) .
What would be the proper way of writing this without using prolog between predicate?
If you indeed want to use the goals L=1 and L=0 and X is an integer, use clpfd!
:- use_module(library(clpfd)).
Reification works like a charm!
?- X in 0..100 #<==> L.
L in 0..1, X in 0..100#<==>L.
What if X gets instantiated?
?- X in 0..100 #<==> L, X=(-7).
L = 0, X = -7. % out of bounds: -7 < 0 =< 100
?- X in 0..100 #<==> L, X=55.
L = 1, X = 55. % within bounds: 0 =< 55 =< 100
?- X in 0..100 #<==> L, X=111.
L = 0, X = 111. % out of bounds: 0 =< 100 < 111
A Prolog query succeeds or fails. If it succeeds it will return the bindings it made to be true.
You can write this predicate using clpfd as:
:-use_module(library(clpfd)).
under_hundred_clpfd(X):-
X in 0..100.
(You might prefer a name such as between_0_100?, if you literally want under 100 then you can use X in inf..99).
Some queries:
?-under_hundred_clpfd(5).
true.
?-under_hundred_clpfd(101).
false.
?-under_hundred_clpfd(X).
X in 0..100.
A traditional way to write this is:
under_hundred(X):-
X>=0,
X=<100.
But this way does not work for uninstantiated variables.
?-under_hundred(X).
ERROR: >/2: Arguments are not sufficiently instantiated
So like you say you might have to put a between/3 or length/2 goal to get a solution or similar construct.
underhundred(X):-
length(_,X),
X>=0,
X=<100.
This is not a very good solution as on back tracking it will get into an infinite loop. between/3 behaves better but you don't want it :).
If the main point of the question is how to write an if-then-else construct in Prolog, then a reasonable answer along the lines of the proposed definition is:
underhundred(X,L) :-
( X >= 0, X =< 100 )
-> L = 1
; L = 0.
This will only be useful if underhundred(X,L) is called after X has been sufficiently instantiated.
I am very new to prolog and I am trying to code a simple program which will display the first 100 integers.
is_integer(0).
is_integer(X) :-
is_integer(Y),
( Y >= 100, ! ; X is Y + 1 ).
It works well but when we ask if 2.1 is an integer then it replies "true". This is because 2.1 is between 0 and 100.
But I want a program which will strictly display the first 100 Integers only.Could someone help me with this please.
Thanks!
I think this matches your style in the question if you don't want to use predefined functions like between(0, 100, X):
between0_100(X) :-
(var(X) -> true ; X >= 0), % either X is unbound or >= 0.
between0_100(0, X).
between0_100(X, X).
between0_100(X, Y) :-
Z is X + 1, % increment X
Z =< 100, % and test if it is <= 100
between0_100(Z, Y). % recurse
?- between0_100(X).
X = 0 ;
X = 1 ;
X = 2 ;
…
X = 98 ;
X = 99 ;
X = 100 ;
false.
?- between0_100(2.1).
false
What do you mean by "display"?
The (very standard) predicate between/3 is defined along the lines of:
between(Lower, Upper, N) is true when N >= Lower and N =< Upper. If N is an integer, it will succeed or fail, and throw an error if it is not an integer. If N is a free variable it will enumerate solutions by backtracking. I am quite certain you can find reasonable implementations of between/3 elsewhere on StackOverflow.
Or do you mean that you type in:
?- first_100_ints.
And you get:
0
1
2
3
4
...
99
?
You could do this as follows:
first_100_ints :-
next_int(0, 100).
next_int(X, Upper) :-
( X < Upper
-> format('~d~n', [X]),
succ(X, X1),
next_int(X1, Upper)
; true
).
This is one "cheap" way to do it. But keep in mind that this is not how you would want to write a Prolog program, normally. One somewhat better way would be to use the built-ins between/3 and forall/3:
?- forall(between(0, 99, X), format('~d~n', [X])).
This is equvalent to:
?- \+ (between(0, 99, X), \+ format('~d~n', [X])).
which reads something along the lines of, "There is no number between 0 and 99 (inclusive) for which you cannot print out the number". See here.
There are other things you can do, depending on what your exact goal is.
I second #Kay's answer. If it is possible, don't use side-effects and use the prolog-toplevel instead!
If your Prolog implementation offers clpfd, you could do it like this:
:- use_module(library(clpfd)).
?- X in 0..100, indomain(X).
X = 0. ;
X = 1 ;
X = 2 ;
% % ... lots of more answers ...
X = 99 ;
X = 100 ;
false. % query terminates universally