How to write a prolog mathematical Function? - prolog

I am trying to convert a math function into prolog, but I keep getting error. Can anyone give me a hint that where is my mistake, please?
I want to convert f (x) = x ˆ 2 + f (x - 1). So I am assuming that this is a recursive procedure. Here is What I have done so far.
function(0,0) :- !.
function(1,1) :- !.
function(X,Y) :-
X1 is ((X * X) + (X - 1)),
function(X1, Y).
I have also tried
function(0,0) :- !.
function(1,1) :- !.
function(X,Y) :-
X1 is (X * X), X2 is (X - 1),
function(X1, N1),
function(X2, N2),
Y is N1 + N2.
Any help is appreciated.

Prolog works using predicate calculus.
A predicate can evaluate to true or false.
You need to write what is true (anything else is assumed false as prolog interpreters will use a closed world assumption).
for your function we can define a predicate:
func(X, Y)
where func is a predicate that evaluates to true if X is x and Y is f(X)
You need to tell prolog when func(X, Y) is true
func(0, 0).
func(X, Y) :- X > 0, U is X - 1, func(U, V), Y is X * X + V.
The above code can be thought of saying
your predicate func is true when X is 0 and Y is 0
This will be your base case. (You only need one since you only have 1 recursive call).
Next is your recursive case:
When is func true for a general X
we need X to be greater than 0
we need the result of f(x-1) which we called V
V is the result of f(X-1) when func(X-1, V) is true
prolog doesn't allow expressions inside predicates so we state U is X-1
Then we put everything together and state Y is X *X + V

Try this:
f(0,0) . % f(0) is 0.
f(X,Y) :- % otherwise...
integer(X) , % - constrain X to be an integer, and
X > 0 , % - constrain X to be positive,
X1 is X-1 , # - then decrement X
f(X1,Y1) , % - compute f(X-1) ,
Y is X*X + Y1 % - and add X*X to that to get the result.
. % Easy!

Related

define predicate prolog by requirements

I have to define a predicate p(X, Y), where Y = f(X) where
How could I define the predicate, according to this requirements?
Almost the same way it's written there, three cases for Y's value given different X conditions:
f(X, Y) :- X < 4, Y is X ^ 2 - 1.
f(X, Y) :- X >= 4, X =< 6, Y is sqrt(X) + 1.
f(X, Y) :- X > 6, Y is 9 - X.
or the middle case
f(X, Y) :- between(4, 6, X), Y is sqrt(X) + 1.
which I had originally and find more readable, but changes the behaviour for that case, which is a tradeoff.
Then:
:- f(3, Y).
Y = 8
( zcompare/3 hints at a way to get rid of the choice points without using cut !, but only if you restrict to integers ).
Another way that doesn't leave choice points behind...
f(X,Y) :- X < 4 -> Y is X^2 - 1 ;
X =< 6 -> Y is sqrt(X) + 1 ;
Y is 9 - X .

Rewrite the definition in order to avoid the recursive call

Given the following PROLOG predicate definition f(integer, integer), with the flow model (i,
o):
f(0, -1) :- !.
f(I,Y):-
J is I-1,
f(J,V),
V > 0,
!,
K is J,
Y is K+V.
f(I,Y):-
J is I-1,
f(J,V),
Y is V+I.
Rewrite the definition in order to avoid the recursive call f(J,V) in both clauses. Do NOT redefine
the predicate. Justify your answer
With inspiration from question:
ffast(0, -1) :- !.
ffast(1, 0) :- !.
ffast(2, 2) :- !.
ffast(X, Y) :-
X0 is X - 1,
ffast(X0, Y0),
Y is Y0 + X0.
... and then to:
ffast2(0, Y) :- !, Y = -1.
ffast2(1, Y) :- !, Y = 0.
ffast2(X, Y) :- Y is ((X * (X - 1)) / 2) + 1.
(Guarding against Y being an input, as per best-practices.)

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.

Prolog - if condition 1 AND condition 2 do x

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.

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).

Resources