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

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.

Related

Prolog - Display prime numbers

I am new to Prolog programming so still learning. I'm tryingto create a program that accepts a value X and returns a list of all prime numbers between 6 and X. I'll also be later adding an error output if X is entered as 6 or lower.
I have come up with the below code so far to have the value of x entered, y as the first prime number and the counter as 1. Even this is not working, as I try to increment the values of Y. If i can get this working I plan to then add conditions to only show Y if it is a prime, by checking that it divides by itself and 1.
If anyone has any advice it would be greatly appreciated.
prime (X, Y, Counter) :-
X >= Y,
writeln(Y),
Next is Y + Counter,
prime (X, Next, Counter).
prime(X, Y, _) :-
Y > X.
Remove the spaces in prime ( here and here:
Then it works to call ?- prime(10, 3, 1). and have it count.

Recursive function for going through digits not progressing

I am trying to do a predicate called "all_even", with one parameter. It will take that parameter and check if it's even or odd using mod(); if it is odd then the predicate should stop working, which I persume will be done by the cut (!) feature.
But it seems like my recursive case seems to not be working. When I traced it, the number I inputted, 2968, doesn't change, but is eventually overwritten by some weird number that breaks the whole thing.
For context, here is my current code:
all_even(X) :- mod(X,2)\==0.%base case
all_even(X) :- mod(X,2)=:=0,
all_even(X1), X1 is X // 10. %recursive case
and here's the tracing feedback
Call:all_even(2968)
Call:2968 mod 2\==0
Exit:2968 mod 2\==0
Exit:all_even(2968)
1true
Redo:all_even(2968)
Call:2968 mod 2=:=0
Exit:2968 mod 2=:=0
Call:all_even(_5638)
Call:_5638 mod 2\==0
Exit:_5638 mod 2\==0
Exit:all_even(_5638)
Call:_5638 is 2968//10
Exit:296 is 2968//10
Exit:all_even(2968)
2true
Redo:all_even(_5638)
Call:_5638 mod 2=:=0
Exception:_5638 mod 2=:=0
Arguments are not sufficiently instantiated
I think there are a couple of problems with your code:
the first clause (your base case) succeeds when the number is not even
the recursive clause calls all_even(X1) without first computing X1, so later when doing arithmetic operations it will give you the exception that the argument is not sufficiently instantiated.
So you should first compute X1 and then do the recursive call:
all_even(X) :-
X \= 0,
mod(X,2)=:=0,
X1 is X // 10,
all_even(X1) . %recursive case
all_even(0). %base case
This procedure does not work as a generator because it cannot cope with unbound variables. For that you may use clp(FD):
all_even(0). %base case
all_even(X) :-
X #\= 0,
0 #= X mod 2,
X1 #= X // 10,
all_even(X1) . %recursive case
sample run:
?- all_even(X), label([X]).
X = 0 ;
X = -8 ;
X = -6 ;
X = -4 ;
X = -2 ;
X = 2 ;
X = 4 ;
X = 6 ;
X = 8 ;
X = -88 ;
X = -86
...

Trying to generate list of non-zero integers in Prolog

I'm trying to define the function int(?X) in prolog which is a non-zero integer number generator which works like this:
?- int(X). X = 1 ; X = -1 ; X = 2 ; X = -2 ;
I tried the following with no luck:
int(X):- positives(Y), Y is abs(X).
positives(1).
positives(X):- positives(Y), X is Y+1.
but I'm getting the following error:
ERROR: is/2: Arguments are not sufficiently instantiated
How can I make this work? Thanks!
There is an easy way to find and correct such problems.
Step one: Put clpfd constraints in your program. To do this, simply1 replace (is)/2 by the CLP(FD) constraint (#=)/2, i.e.:
int(X) :- positives(Y), Y #= abs(X).
positives(1).
positives(X):- positives(Y), X #= Y+1.
Step two: The query now completes without errors, and shows you what you are describing:
?- int(X).
X in -1\/1 ;
X in -2\/2 ;
X in -3\/3 ;
X in -4\/4 .
So, from the above, you see that what you are describing is not sufficient to obtain ground solutions: There is still a certain degree of freedom in your relations.
Step three: To actually fix the problem, we think about what we actually want to describe. Here is a start:
int(X) :- positives(Y), ( X #= Y ; X #= -Y).
Step four: We try it out:
?- int(X).
X = 1 ;
X = -1 ;
X = 2 ;
X = -2 ;
X = 3 ;
etc.
Seems to work OK, except for the fact that natural numbers are actually never negative. I leave fixing this discrepancy between the title of your question and the relation you are describing as an exercise for you.
TL;DR: When reasoning over integers, use your system's CLP(FD) constraints, then take it from there.
I am assuming that you have already put :- use_module(library(clpfd)). somewhere in your initial file, so that you can use CLP(FD) constraints in all your programs.

How does the recursing work in prolog for adding number

My aim is to take the numbers between X and Y and produce Z.
num_between(3,6, All)
For example, if X is 3 and Y is 6 then Z is a list of the numbers between X and Y inclusive. Something like num_between(3,6,[3,4,5,6]) should evaluate as true. Here's what I have so far:
num_between(0,0, []).
num_between(X,Y, All) :-
increase(X, New) , % increase number X++
\+(X = Y) , % check if X is not equal to Y
num_between(New,Y,[All|X]) . % requestion ???
increase(F,N) :- N is F+1 .
increase/1 is working and returns number that is required, but
when recursion is gone through num_between/3 it goes unlit: X is 6 then it fails as I want,
but I can not manage to keep numbers or to return them. All = [3,4,5,6].
All = All + F. Could anyone help please.
Your base clause is incorrect: since you never decrease X or Y, they would never get to zero (unless Y starts at zero, and X starts at a non-positive value). The base clause should look like this:
num_between(X, Y, []) :- X > Y.
This ensures that you get an empty result when the user enters an invalid "backward" range (say, from 6 to 3).
Now to the main clause: all you need to do is to check that the range is valid, get the next value, and make a recursive call, like this:
num_between(X, Y, [X|Tail]) :-
X =< Y,
Next is X + 1,
num_between(Next, Y, Tail).
Demo.
Your original code made an error when constructing a list - it tried to use X as the "tail" of the list, which is incorrect:
num_between(New,Y,[All|X]).
you pass on All, the result after an "expansion", down through the recursive chain of invocation. It should be the other way around - you need to pass in a Tail to collect the result, and then pre-pend X to it when the recursive invocation is over.
You have to change both your base case and your recursive clause:
num_between(X, X, [X]).
num_between(X, Y, [X|L]):-
X < Y,
increase(X, New),
num_between(New, Y, L).
First clause is the base case, it states that the number ranging from X and X is just [X].
The recursive clause states that a number X which is less than a number Y should have it in the output list (thus the [X|L] in the third argument of the head), then it increases the value (i'm just using your helper procedure for that) and recursively calling itself now with the New value for the first argument.
I would write this along these lines:
numbers_between( X , X , [X] ) . % if X and Y have converged, we have the empty list
numbers_between( X , Y , [X|Zs] ) :- % otherwise, add X to the result list
X < Y , % - assuming X is less than Y
X1 is X+1 , % - increment X
numbers_between(X1,Y,Zs) % - recurse down
. %
numbers_between( X , Y , [X|Zs] ) :- % otherwise, add X to the result list
X > Y , % - assuming X > Y
X1 is X-1 , % - decrement X
numbers_between(X1,Y,Zs) % - recurse down
. %

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