Resolve quadratic equation in prolog - prolog

I got problem with quadrating equation implementation in prolog.
I know some basics but at same point I can not understand output of swish.swi console.
I would appreciate any help or suggestions from your side about my errors.
delta(A, B, C, D):- D is B*B - 4*A*C.
equation(A,B,C,X):- D1<0,delta(A,B,C,D1),X is 0. % or false... but how to retur false there?
equation(A,B,C,X):- D1 =:= 0,delta(A,B,C,D1),X is -B/2*A.
equation(A,B,C,X): D1>0,delta(A,B,C,D1),X is -B-sqrt(D1)/2*A.
equation(A,B,C,X): D1>0,delta(A,B,C,D1),X is -B+sqrt(D1)/2*A.
I am getting two errors there after runnign equation(2, 0, 1, X).
Full stop in clause-body? Cannot redefine ,/2
</2: Arguments are not sufficiently instantiated

At the last 2 predicates (the ones where D>0), you forgot to write "-" after ":". Your code works good, it was just a sintax error. Below I corrected the code for you:
delta(A, B, C, D):- D is B*B - 4*A*C.
equation(A,B,C,X):- D1<0, delta(A,B,C,D1), X is 0.
equation(A,B,C,X):- D1 =:= 0, delta(A,B,C,D1), X is -B/2*A.
equation(A,B,C,X):- delta(A,B,C,D1), D1>0, X is ((-1*B-sqrt(D1))/2*A).
equation(A,B,C,X):- delta(A,B,C,D1), D1>0, X is ((-1*B+sqrt(D1))/2*A).

about
Arguments are not sufficiently instantiated
you must swap delta/4 and the test. Also, it's better to use if/then/else, to avoid recomputing the result:
equation(A,B,C,X) :-
delta(A,B,C,D1),
( D1 < 0
-> X is 0
; D1 =:= 0
-> X is -B/2*A
; X is -B-sqrt(D1)/2*A
).

Related

Why is my function returning a negative value?

So I drew a simple function in prolog that counts how many of a variable are in a matrix.
And it goes like this :
:-use_module(library(lists)).
:-use_module(library(clpfd)).
countOccurrences([],Y,0).
countOccurrences([X|T], Y, Z):-
countOccur(X, Y, N),
Acc #=N + Z,
countOccurrences(T, Y, Acc).
countOccur([],X,0).
countOccur([X|T],X,Y):- countOccur(T,X,Z), Y is 1+Z.
countOccur([X1|T],X,Z):- X1\=X,countOccur(T,X,Z).
countOccur seems to be working fine and returns the right value. The problem is countOccurences is returning the right absolute value but negative. I Just dont seem to understand why that is happening.
Can someone enlighten me ?
An input of [[a,a,a,a]] looking for a does countOccurrences of a in [] and sets Acc = 0 and then countOccur of a in [a,a,a,a] sets N=4 then Acc #= N + Z becomes 0 #= 4 + Z and so the result must be Z = -4.

How to stop backtracking and end the recursion in Prolog

I'm currently learning SWI-Prolog. I want to implement a function factorable(X) which is true if X can be written as X = n*b.
This is what I've gotten so far:
isTeiler(X,Y) :- Y mod X =:= 0.
hatTeiler(X,X) :- fail,!.
hatTeiler(X,Y) :- isTeiler(Y,X), !; Z is Y+1, hatTeiler(X,Z),!.
factorable(X) :- hatTeiler(X,2).
My problem is now that I don't understand how to end the recursion with a fail without backtracking. I thought the cut would do the job but after hatTeilerfails when both arguments are equal it jumps right to isTeiler which is of course true if both arguments are equal. I also tried using \+ but without success.
It looks like you add cuts to end a recursion but this is usually done by making rule heads more specific or adding guards to a clause.
E.g. a rule:
x_y_sum(X,succ(Y,1),succ(Z,1)) :-
x_y_sum(X,Y,Z).
will never be matched by x_y_sum(X,0,Y). A recursion just ends in this case.
Alternatively, a guard will prevent the application of a rule for invalid cases.
hatTeiler(X,X) :- fail,!.
I assume this rule should prevent matching of the rule below with equal arguments. It is much easier just to add the inequality of X and Y as a conditon:
hatTeiler(X,Y) :-
Y>X,
isTeiler(Y,X),
!;
Z is Y+1,
hatTeiler(X,Z),
!.
Then hatTeiler(5,5) fails automatically. (*)
You also have a disjunction operator ; that is much better written as two clauses (i drop the cuts or not all possibilities will be explored):
hatTeiler(X,Y) :- % (1)
Y > X,
isTeiler(Y,X).
hatTeiler(X,Y) :- % (2)
Y > X,
Z is Y+1,
hatTeiler(X,Z).
Now we can read the rules declaratively:
(1) if Y is larger than X and X divides Y without remainder, hatTeiler(X,Y) is true.
(2) if Y is larger than X and (roughly speaking) hatTeiler(X,Y+1) is true, then hatTeiler(X, Y) is also true.
Rule (1) sounds good, but (2) sounds fishy: for specific X and Y we get e.g.: hatTeiler(4,15) is true when hatTeiler(4,16) is true. If I understand correctly, this problem is about divisors so I would not expect this property to hold. Moreover, the backwards reasoning of prolog will then try to deduce hatTeiler(4,17), hatTeiler(4,18), etc. which leads to non-termination. I guess you want the cut to stop the recursion but it looks like you need a different property.
Coming from the original property, you want to check if X = N * B for some N and B. We know that 2 <= N <= X and X mod N = 0. For the first one there is even a built-in called between/2 that makes the whole thing a two-liner:
hT(X,B) :-
between(2, X, B),
0 is (X mod B).
?- hT(12,X).
X = 2 ;
X = 3 ;
X = 4 ;
X = 6 ;
X = 12.
Now you only need to write your own between and you're done - all without cuts.
(*) The more general hasTeiler(X,X) fails because is (and <) only works when the right hand side (both sides) is variable-free and contains only arithmetic terms (i.e. numbers, +, -, etc).
If you put cut before the fail, it will be freeze the backtracking.
The cut operation freeze the backtracking , if prolog cross it.
Actually when prolog have failed, it backtracks to last cut.
for example :
a:- b,
c,!,
d,
e,!,
f.
Here, if b or c have failed, backtrack do not freeze.
if d or f have failed, backtrack Immediately freeze, because before it is a cut
if e have failed , it can backtrack just on d
I hope it be useful

Why can't my rule solve for X in a simple algebraic equation?

I'm new to Prolog, so please be gentle.
This is my rule:
solve(X) :- A = B, A is (7 * (X - 2)), B is (3 * (X + 4)).
Obviously, the correct answer here is 6.5. If I give that to Prolog, it confirms:
| ?- solve(6.5).
yes
However, if I ask Prolog to do the dirty work, it throws an error:
| ?- solve(X).
uncaught exception: error(instantiation_error,(is)/2)
I fully concede that whatever is going on here is due to my misunderstanding of Prolog. Can someone explain to me how I might get this to work or why it won't work?
In Prolog, is is an arithmetic evaluation operator. It calculates the result of an expression on its right side, and assigns it to a variable on its left side.
The expression to be evaluated must contain only numbers and arithmetic operators/functions. In other words, to evaluate an expression, is must already know all the numbers in it.
Another way of saying this is that is is "unidirectional", unlike the = which is bi-directional. Which is what you expected. And that is the meaning of the error that you got.
Solving such equations - constraints - is a job for a constraint solver.
You can use a library for this, available in SWI-Prolog at least: library(clpr) and library(clpq).
Here from the top level for Reals:
?- use_module(library(clpr)).
true.
?- {7 * (X - 2) = 3 * (X + 4)}.
X = 6.5 ;
false.
Or, if you use Rationals:
?- use_module(library(clpq)).
true.
?- {7 * (X - 2) = 3 * (X + 4)}, R is float(X).
X = 13 rdiv 2,
R = 6.5.
If you want to do it yourself, it will be of course much more work. You would have to write code like
...,
( ground(X)
-> 7 * (X - 2) =:= 3 * (X + 4)
; X is (3*4 + 2*7) / (7 - 3)
),
...
By the way, what you are doing: A = B, A is ..., B is ....
This is a bit dangerous, for example:
?- A = B, A is 3 - 2, B is sin(pi/2).
false.
?- 3 - 2 =:= sin(pi/2).
true.
3 - 2 evaluates to the integer 1; then, sin(pi/2) evaluates to the floating point number 1.0, and this does not unify with the integer 1. So, the first query fails!
?- 1 = 1.0.
false.
Prolog works by unification. It tries to make structures the same.
So, for example, if I try to unify [3, X, 5] with [3, 4, 5] that works fine and X = 4.
In your code you are first saying A = B. That's fine as initially A and B are not instantiated so you are basically tying their destinies to each other - if A is later instantiated then B automatically is too, or visa-versa.
Then you go on to ask A is (7 * (X - 2)). Now if you have already unified X with 6.5 then this can be evaluated - A is then unified with 7 * (6.5 - 2) or 31.5. But remember that A was already unified with B, so B now also is 31.5.
Now you say B is (3 * (X + 4)). So with X unified to 6.5 and B unified with 31.5 this is the same as 31.5 is (3 * (6.5 + 4)). The right hand side is 31.5 so this is 31.5 is 31.5 which is true.
So, solving for solve(6.5) works.
However, if you try to solve for X then the first predicate works just fine. But the second one doesn't. It's like me asking "What's 7 times the number that is 2 less than the number I'm thinking of?" Unless I tell you the number I'm thinking of you can't give me an answer. The same for Prolog. It gets stuck and reports an error.

int_log2(X,Y) which sets Y to the integer log2 of X, where X is assumed to be a nonnegative integer

I got the following task:
int_log2(X,Y) which sets Y to the integer log2 of X, where X is assumed to be a non-negative integer. For example int_log(133,X) will set X to 7. The integer log base 2 of X means the number of times you divide Xby 2 to get down to one. Where divide means integer division. Use nothing more than + and div to code it.
This is what I got so far. I am not 100% sure if I should do it like this. When I run query int_log(133,Z), it only shows answer in true or false.
div(0,X).
div(X,Z) :- X \=0, X1 is X-1, div(X1,W), Z is floor(X/2).
int_log(0,X).
int_log(X,Z) :- X \= 0, X1 is X-1, int_log(X1,W), div(W,Z).
As it is with such exercises, the problem statement already contains the answer.
X is assumed to be a non-negative integer
% precondition( integer(X) ).
% precondition( X > 0 ).
... the number of times you divide X by 2 to get down to one
int_log2(1, 0).
int_log2(X, Y) :-
... the number of times you divide X by 2...
... Use nothing more than + and div to code it.
X0 is X div 2, % used `div`
int_log2(X0, Y0),
Y is Y0 + 1. % used `+`
So this works like this:
?- int_log2(133, X).
X = 7 .
?- int_log2(256, X).
X = 8 .
?- int_log2(255, X).
X = 7 .
What will happen if you try to look for more solutions? Where does the choice point come from? How can you get rid of it? How can you get rid of it without using a cut?
Is this for a math course or a "Prolog" course? If it is meant to teach you Prolog, you will have a bad time.
As for how one would solve it: if you are using an implementation that has the arithmetic function msb(), you just say:
Y is msb(X).
for example:
?- X is msb(133).
X = 7.
?- X is msb(256).
X = 8.

Basic PROLOG counting

I'm new to prolog I'm trying to write a predicate which counts the following:
the predicates name is s2int when given:
s2int(0,Y) it shoud "return" Y=0.
s2int(s(0),Y) => Y=1.
s2int(s(s(0)),Y) => Y=2.
s2int(S(s(s(0))),Y) => Y=3.
and so on..
here is what i tried to write(very poorly),
at first i tried this code:
s2intAux(0,Y).
s2intAux(X,Y):- X = s(Z) ,Y1 is Y+1, s2intAux(Z,Y1).
but whenever i try to run it by typing s2intAux(s(0),Y) i get an error saying :"ERROR: is/2: Arguments are not sufficiently instantiated"
i get that error well because Y is undefined.
then i tried this one:
s2intAux(0,Y).
s2intAux(X,Y):- X = s(Z) ,Y1 is Y+1, s2intAux(Z,Y1).
s2int(X,Y):- Y1 is 0, s2intA(X,Y1).
(i tried to start Y with the value zero but this one didn't work at all)
I've been stuck for a couple of hours now which is why I'm turning to you guys, please help!
thank you.
You need the following to resolve the most trivial case:
s2intAux(0,0).
This will cause s2intAux(0,Y) to be true when Y is instantiated to 0.
In your subsequent lines, you don't have a statement that resolves Z to 0 when you run out of the s(.). For that, you need to take care of the single s(0) case. Then you can do the general case:
s2intAux(X,Y) :- X = s(0), Y is 1.
s2intAux(X,Y) :- X = s(Z), s2intAux(Z,Y1), Y is Y1 + 1.
Note that on the general case, we have to traverse down to get to the Y is 1 before we can unravel back up and finally assign Y to Y1 + 1.
You can also write that first line as just:
s2intAux(s(0),Y) :- Y is 1.
Final answer looks like this:
s2intAux(0,0).
s2intAux(s(0),Y) :- Y is 1.
s2intAux(X,Y) :- X = s(Z), s2intAux(Z,Y1), Y is Y1 + 1.

Resources