Recursive function for going through digits not progressing - prolog

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

Related

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.

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.

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

Collect all elements of binary tree that are power of 2

I can't get the following to work. This is what I got so far:
stepen(2).
stepen(X):-
X mod 2=:=0,
X1 is X/2,
stepen(X1).//stepen means power(in Serbian).
spoji([],Y,Y).
spoji([X|Xs],Y,[X|Z]):-spoji(Xs,Y,Z).//spoji means append lists
vadi(nil,[]).
vadi(t(X,L,R),[X|Xs]) :-
stepen(X),
vadi(L,SL),
vadi(R,SR),
spoji(SL,SR,Xs).//list of nodes that are power of 2.
You might find this method of determine whether or not N is a a power of 2 a little more efficient. It's a bit-twiddling hack that takes advantage of the two's complement representation of integer values:
is_power_of_two( N ) :-
integer(N) ,
N \= 0 ,
0 is N /\ (N-1)
.
Edited to note that the property holds true regardless of the sign of the integer: with one exception — 0, hence the test for non-zero — the only two's-complement integer values for which this property is true are powers of two:
?- between(-1025,+1025,N),pow2(N).
N = 1 ;
N = 2 ;
N = 4 ;
N = 8 ;
N = 16 ;
N = 32 ;
N = 64 ;
N = 128 ;
N = 256 ;
N = 512 ;
N = 1024 ;
false.
(So far nobody commented your code. So I will try)
stepen/1 loops
I assume you refer here to the non-negative powers of two. That is, 2^(-1) and the like are not considered.
First of all, your stepen/1 definition produces an error in ISO conforming systems like gnu-prolog or sicstus-prolog.
| ?- stepen(6).
! Type error in argument 2 of (is)/2
! expected an integer, but found 3.0
! goal: _193 is 3.0 mod 2
This is due to X1 is X/2 which always produces a float or an error, but never an integer. You may replace this by X1 is X div 2 or equivalently X1 is X >> 1.
Will this program now always terminate? After all X div 2 will approach zero. From the negative side, it will end at -1 which then will fail. But from the positive side, it will stay at 0!
Here is the looping program (failure-slice) reduced to its minimum:
?- stepen(0).
stepen(2) :- false.
stepen(X):-
X mod 2=:=0,
X1 is X div 2,
stepen(X1), false. % stepen means power(in Serbian).
As Nicholas Carey has suggested, you can simplify this predicate to:
stepen(X) :-
X > 0,
X /\ (X-1) =:= 0.
vadi/2 logic
In your definition, this predicate is true, if all nodes of the trees are powers of two. I assume you wanted to "filter out" the powers. The easiest way to do this is by using DCGs instead of spojii/3 vl. append/3. Let's first consider a simpler case, just the nodes of a tree:
nodes(nil) --> [].
nodes(t(X, L, R)) -->
[X],
nodes(L),
nodes(R).
?- T = t(1,nil,t(2,t(3,nil,t(4,nil,nil)),t(5,nil,nil))), phrase(nodes(T),L).
T = t(1,nil,t(2,t(3,nil,t(4,nil,nil)),t(5,nil,nil))), L = [1,2,3,4,5].
Now, you no longer want all elements, but only certain, I will use a separate nonterminal for that:
st(E) --> {stepen(E)}, [E].
st(E) --> {\+stepen(E)}. % nothing!
Or more compactly:
st(E) --> {stepen(E)} -> [E] ; [].
Now, the final non-terminal is:
stepeni(nil) --> [].
stepeni(t(X,L,R)) -->
st(X),
stepeni(L),
stepeni(R).
?- T = t(1,nil,t(2,t(3,nil,t(4,nil,nil)),t(5,nil,nil))), phrase(stepeni(T),L).
T = t(1,nil,t(2,t(3,nil,t(4,nil,nil)),t(5,nil,nil))), L = [1,2,4].
If you consider that 1 is 2^0, you need to change the base case of stepen/1 predicate.
A more important correction is required because your vadi/2 predicate will fail when any node not power of 2 is found in the tree.
Then you should add a clause
vadi(t(X,L,R),Xs) :-
% \+ stepen(X), this test is not mandatory, but it depends on *where* you add the clause
vadi(L,SL), vadi(R,SR), spoji(SL,SR,Xs).

How to Print numbers from 1 to 100 in Prolog?

The following code is a Prolog code which gives all integers greater than 0. Each time i put ; in the interpreter, it gives the next number:
is_integer(0).
is_integer(X) :- is_integer(Y),X is Y+1.
Is there a way where it gives numbers between 0 and 100 only. When it reaches 100 it should stop.
There is a built-in predicate between/3 for that purpose in B, Ciao, SICStus (library), SWI, YAP, XSB (library).
?- between(0,100,X).
X = 0
; X = 1
; ...
; X = 100.
If you start to learn Prolog, better try to use s(X) numbers first which are much easier to understand and reason about. The same example, but only going up to 3:
?- nat_nat_sum(N,_,s(s(s(0)))).
with the definition:
nat_nat_sum(0,I,I).
nat_nat_sum(s(I),J,s(K)) :-
nat_nat_sum(I,J,K).
What a nice quiz. It exemplifies very well how difficult can be to control the recursion with the minimal tools that Prolog defines. We must commit our solutions to values lower than the predefined limit, restricting the otherless unbound search:
is_integer(0).
is_integer(X) :-
is_integer(Y),
( Y >= 100, ! ; X is Y + 1 ).
Here is the trace output limiting the range to 3 (i.e. ... Y >= 3, ! ; ...)
?- is_integer(X).
X = 0 ;
X = 1 ;
X = 2 ;
X = 3 ;
true.

Resources