Prolog - if condition 1 AND condition 2 do x - prolog

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.

Related

Why do both predicates get evaluated?

I have this predicate with two clauses:
abs(X, Y) :- X < 0, Y is -X.
abs(X, X) :- X >= 0.
and I submit this to the interpreter:
?- abs(-5,W).
W = 5 ;
false.
?-
Why does it evaluate the second clause and return false? Is there a way around that?
You wrote two clauses that are disjoint on the 1st argument(X) and were surprised that Prolog backtracked into the 2nd one even though the first one was satisfied.
abs(X, Y) :- X < 0, Y is -X.
abs(X, X) :- X >= 0.
When the 1st clause was satisfied, the Prolog engine only knew that there was a 2nd clause that hadn't been evaluated; when you typed ";", it tried the 2nd clause, which failed. To see why, consider a slightly different (and not as good) version of your code:
abs2(X, Y) :- X =< 0, Y is - X.
abs2(X, Y) :- X >= 0, Y = X.
?- abs2(0, Y).
Y = 0 ;
Y = 0 ;
In this situation, even though the 1st clause succeeds, the 2nd clause can also succeed.
So, how to avoid this? It depends on what you want to accomplish. If you want to get all the answers, do something like this:
?- setof(W, abs(-5, W), Ws).
Ws = [5].
To print them all:
?- forall(abs(-5, W), format('W = ~q~n', [W])).
W = 5
If you want to tell the Prolog engine that your predicate is deterministic, you can use an if-then-else:
abs(X, Y) :-
( X < 0
-> Y is -X
; Y = X
).
This can also be written with a cut("!"), but it's often easier to understand with if-then-else.
And, if you're using the latest version of SWI-Prolog, you can use the "=>" notation:
abs(X, Y), X < 0 => Y is -X.
abs(X, Y) => true.

Boolean unification in Prolog?

I am struggling alreay for a long time with the
following problem. I want to make the usual unification
of Prolog more smart.
Basically I want that certain variables understand that
for example 0 = ~1 and 1 = ~0. This doesn't work normally:
?- op(300, fy, ~).
true.
?- X = ~Y, Y = 0.
X = ~0,
Y = 0.
I know that that CLP(B) can do it:
Welcome to SWI-Prolog (threaded, 64 bits, version 8.3.7)
:- use_module(library(clpb)).
true.
?- sat(X=:= ~Y), Y = 0.
X = 1,
Y = 0.
But I require something more lightweight than loading a full CLP(B) library. Any ideas?
It seems that SWI-Prologs when/2 does the job. I am using
the Quine algorithm from here to partially evaluate a boolean expression.
I can then define a Boolean let/2 predicate:
let(X, Y) :-
eval(Y, H),
term_variables(H, L),
( L== [] -> X = H;
cond(L, R),
when(R, let(X, H))).
cond([X], nonvar(X)) :- !.
cond([X,Y|Z], (nonvar(X);T)) :-
cond([Y|Z], T).
The above predicate will reevaluate the expression assigned
to the variable X when ever some variable inside the expression
changes. The expression is associate with the variable X through when/2. Since we see when/2 in the top-level, we see the associated expression:
?- let(X, ~Y).
when(nonvar(Y), let(X, ~Y))
?- let(X, Y+Z).
when((nonvar(Y); nonvar(Z)), let(X, Y+Z))
And we can also do our use case and even more:
?- let(X, ~Y), Y = 0.
X = 1,
Y = 0.
?- let(X, Y+Z), Y = 0.
Y = 0,
when(nonvar(Z), let(X, Z))
?- let(X, Y+Z), Y = 0, Z = 1.
X = 1,
Y = 0,
Z = 1

Multiple values of a variable inbetween 0 and a number prolog

So I've been trying to teach myself prolog and I think I'm coming along nicely. However, I'm sort of stuck at this one method I'm trying to make.
toN(N,A) A is equal to the integer values between 0 and N-1, generated in ascending order.
so
toN(5,A) would be
A = 0;
A = 1;
A = 2;
A = 3;
A = 4.
I'm still new to prolog so I'm not exactly sure how to do this with multiple values. I had something like this:
toN(N,A) :- 0 < N, Nx is N-1, toN(Nx,A).
toN(N,A) :- 0 =< N, Nx is N-1, A = Nx.
However this just returns false. Nothing else. It seems perfectly fine to me
Check if the Prolog implementation that you are using supports clpfd!
:- use_module(library(clpfd)).
The implementation of toN/2 gets declarative and super-concise:
toN(N,A) :-
A #>= 0,
A #< N,
labeling([up],[A]).
You'll find more labeling options in the clpfd manual: SWI-Prolog clpfd, SICStus Prolog clpfd.
Something like this should generate the sequence of integers between any two arbitrary endpoints:
sequence(X,Y,X) :- % to generate the integers between X and Y,
integer(X) , % - the starting point must be bound
integer(Y) , % - the endpoint must be bound
range(X,Y,Z) % - then we just invoke the worker
. %
range(X,X,X) . % hand back the last item in the sequence if X and Y have converged.
range(X,Y,X) :- % otherwise, return an item
X =\= Y . % - if X and Y haven't converged.
range(X,Y,Z) :- % otherwise,
X < Y , % - if X < Y ,
X1 is X+1 , % - increment X
range(X1,Y,Z) % - and recurse down.
. %
range(X,Y,Z) :- % otherwise
X > Y , % - if X > Y
X1 is X-1 , % - decrement X
range(X1,Y,Z) % - and recurse down
. %
With that general-purpose tool, you can simply say:
to_n(N,A) :- sequence(0,N,A).
Your implementation does not fail: by backtracking it yields numbers from -1 to N-1
?- toN(5,A).
A = -1 ? ;
A = 0 ? ;
A = 1 ? ;
A = 2 ? ;
A = 3 ? ;
A = 4 ? ;
no
To eliminate the -1 you should just replace =< by < in your second clause as #false commented above.
An alternative implementation, maybe more readable, would be
Edit: inserted condition N>=0 in answer to #false comment below.
toN(N,A) :-
N >= 0,
toN(0,N,A).
toN(K,N,K).
toN(K,N,A) :-
K < N-1,
Kn is K+1,
toN(Kn,N,A).

Display first 100 Integers in Prolog

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

code for multiplication in Prolog doesn't work

This is my attempt for creating the multiplication operator in Prolog.
times1(X,Y,Z) :- Z=X*Y.
But it doesn't work and I don't know why. Could anyone recognize the problem ?
times1(0,Y,0):-!.
times1(X,0,0):-!.
times1(X,Y,Z):- X<0,Y<0,!, times1(-X,-Y,Z).
times1(X,Y,Z):- X>0,!,times1(X-1,Y,Z1),Z is Z1+Y.
times1(X,Y,Z):- X<0,Y>0,times1(Y,X,Z).
Second try:
times1(0,ֹ_,0):-!.
times1(_,0,0):-!.
times1(X,Y,Z):- X<0,Y=\=0,X1 is -X, times1(X1,Y,Z1), Z is -Z1.
times1(X,Y,Z):- X>0,Y=\=0, X2 is X-1, times1(X2,Y,Z1),Z is Z1+Y.
still doesn't work...
In your first solution:
times1(X,Y,Z) :- Z=X*Y.
The problem is the use of unification instead of expression evaluation. Use is/2 for expression evaluation:
times1(X,Y,Z) :- Z is X*Y.
In the second solution:
times1(0,Y,0):-!.
times1(X,0,0):-!.
times1(X,Y,Z):- X<0,Y<0,!, times1(-X,-Y,Z).
times1(X,Y,Z):- X>0,!,times1(X-1,Y,Z1),Z is Z1+Y.
times1(X,Y,Z):- X<0,Y>0,times1(Y,X,Z).
In the expression times1(X-1,Y,Z1) Prolog will not evaluate X-1 before using it as the argument to the recursive call. You need to do this explicitly: X1 is X-1, times1(X1,Y,Z1).
Also, you don't need so many cuts. Since you are already, for example, checking the X and Y condition for 0 in the other predicate clauses, the base cases can be just:
times1(0, _, 0). % 0 times anything is 0
times1(_, 0, 0). % Anything times 0 is 0
You don't need to check both X and Y for negative because X*Y, if Y is negative, can be just X number of the Y values added together anyway, regardless of the sign of Y. And then, after negating X to get a result, you still need to negate the final sum (to compensate for the negated X):
times1(X, Y, Z) :- X < 0, Y =\= 0, times1(-X, Y, Z1), Z is -Z1.
times1(X, Y, Z) :- X > 0, Y =\= 0, X1 is X-1, times1(X1, Y, Z1), Z is Z1+Y.
These really are almost just like what you have, except that your Y < 0 and Y > 0 cases have been consolidated into one with Y =\= 0, I have the extra check for Y =\= 0 in the X > 0 case to avoid cuts, and finally the Z is -Z1 to compensate for negative X.
Note that times1(-X,Y,Z1) works without first doing X1 is -X because when -X is passed to times1, times1 first evaluates X < 0 or X > 0 which will evaluate an expression for X, so the - will be evaluated as desired. Although it still may be safer to first do X1 is -X and not make the assumption. So that first clause would become:
times1(X, Y, Z) :- X < 0, Y =\= 0, X1 is -X, times1(X1, Y, Z1), Z is -Z1.
Testing:
| ?- times1(3,5,L).
L = 15 ? a
(1 ms) no
| ?- times1(-3,5,L).
L = -15 ? a
(1 ms) no
| ?- times1(-3,-5,L).
L = 15 ? a
no
| ?- times1(3,-5,L).
L = -15 ? a
no
| ?- times1(3,0,L).
L = 0 ? a
no
| ?- times1(0,0,L).
L = 0 ? a
L = 0
no
| ?- times1(0,5,L).
L = 0 ? a
no
Multiplying 0 with 0 shows two solutions since it matches two cases. You can eliminate that with the cuts if you need to as you had in your original solution, or you can adjust the predicate logic such that it enforces non-overlapping cases.

Resources