I'm still new to Prolog, and I've encountered an error I have no idea how to fix.
I've written a simple exponentiation program that looks like this:
exp(b, 0, R) :- R is 1. % non-recursive case: exponent is 0
exp(0, e, R) :- R is 0. % non-recursive case: base is 0
exp(Base, Exponent, Result) :- % recurse if base and exponent are non-negative
Base >= 0,
Exponent >= 0,
E1 is Exponent-1,
exp(Base, E1, R1),
Result is Base*R1.
This compiles fine, but when I run it and give it a query like, say, exp(2, 4, X). I'm met with the following output:
?- exp(2, 4, X).
false.
Is there something I've done wrong? Or is it a matter of formatting the result in some way I'm unaware of?
You are confusing variables with atoms. It works as expected if you simple change the two nonrecusive clauses to:
exp(_, 0, 1).
exp(0, _, 0).
In fact, I recommend to change the whole program to use CLP(FD) constraints throughout:
exp(_, 0, 1).
exp(0, _, 0).
exp(Base, Exponent, Result):-
Base #>= 0,
Exponent #>= 0,
E1 #= Exponent-1,
exp(Base, E1, R1),
Result #= Base*R1.
Now for example the following at least yields a solution:
?- exp(2, X, 16).
X = 4
whereas we previously had:
?- exp(2, X, 16).
>=/2: Arguments are not sufficiently instantiated
Note also the most general query:
?- exp(X, Y, Z).
Y = 0,
Z = 1 ;
X = Z, Z = 0 ;
X = Z,
Y = 1,
Z in 0..sup ;
X = Z, Z = 0,
Y in 0..sup,
_G801+1#=Y,
_G801 in -1..sup .
Related
I would like to make a predicat reverse(N,Result) in Prolog.
For example:
reverse(12345,Result).
Result = 54321.
I have to use tail-recursion. I can use *, +, - and divmod/4 and that's all.I can't use list.
I can reverse a number < 100 but I don't find how to finish my code, I can't complete my code to reverse integers bigger than 100 correctly.
reverse(N,N):-
N <10,
N>0.
reverse(N,Result):-
N > 9,
iter(N,0,Result).
iter(N,Ac,Result):-
N < 100, !,
divmod(N,10,Q,R),
R1 is R*10,
Result is Q + R1.
Can I have some help please ?
Thanks you in advance.
I suggest the use of CLP(FD), since it offers declarative reasoning over integer arithmetic and a lot of Prolog systems provide it. Concerning the digit-reversal, I recommend you take a look at entry A004086 in The On-Line Encyclopedia of Integer Sequences. In the paragraph headed FORMULA, you'll find, among others, the following formulae:
a(n) = d(n,0) with d(n,r) = if n=0 then r else d(floor(n/10),r*10+(n mod 10))
These can be translated into a predicates by adding an additional argument for the reversed number. First let's give it a nice declarative name, say digits_reversed/2. Then the relation can be expressed using #>/2, #=/2, (/)/2, +/2, mod/2 and tail-recursion:
:- use_module(library(clpfd)).
digits_reversed(N,X) :-
digits_reversed_(N,X,0).
digits_reversed_(0,R,R).
digits_reversed_(N,X,R) :-
N #> 0,
N0 #= N/10,
R1 #= R*10 + (N mod 10),
digits_reversed_(N0,X,R1).
Note that digits_reversed/2 correspond to a(n) and digits_reversed_/3 corresponds to d(n,r) in the above formulae. Now let's query the predicate with the example from your post:
?- digits_reversed(12345,R).
R = 54321 ;
false.
The predicate can also be used in the other direction, that is ask What number has been reversed to obtain 54321? However, since leading zeros of numbers are omitted one reversed number has infinitely many original numbers:
?- digits_reversed(N,54321).
N = 12345 ;
N = 123450 ;
N = 1234500 ;
N = 12345000 ;
N = 123450000 ;
N = 1234500000 ;
N = 12345000000 ;
N = 123450000000 ;
.
.
.
Even the most general query yields solutions but you'll get residual goals as an answer for numbers with more than one digit:
?- digits_reversed(N,R).
N = R, R = 0 ; % <- zero
N = R,
R in 1..9 ; % <- other one-digit numbers
N in 10..99, % <- numbers with two digits
N mod 10#=_G3123,
N/10#=_G3135,
_G3123 in 0..9,
_G3123*10#=_G3159,
_G3159 in 0..90,
_G3159+_G3135#=R,
_G3135 in 1..9,
R in 1..99 ;
N in 100..999, % <- numbers with three digits
N mod 10#=_G4782,
N/10#=_G4794,
_G4782 in 0..9,
_G4782*10#=_G4818,
_G4818 in 0..90,
_G4818+_G4845#=_G4842,
_G4845 in 0..9,
_G4794 mod 10#=_G4845,
_G4794 in 10..99,
_G4794/10#=_G4890,
_G4890 in 1..9,
_G4916+_G4890#=R,
_G4916 in 0..990,
_G4842*10#=_G4916,
_G4842 in 0..99,
R in 1..999 ;
.
.
.
To get actual numbers with the query above, you have to restrict the range of N and label it after the predicate has posted the arithmetic constraints:
?- N in 10..20, digits_reversed(N,R), label([N]).
N = 10,
R = 1 ;
N = R, R = 11 ;
N = 12,
R = 21 ;
N = 13,
R = 31 ;
N = 14,
R = 41 ;
N = 15,
R = 51 ;
N = 16,
R = 61 ;
N = 17,
R = 71 ;
N = 18,
R = 81 ;
N = 19,
R = 91 ;
N = 20,
R = 2 ;
false.
If for some reason you don't want a constraints based solution, or if you using a Prolog system not supporting constraints, an alternative solution is:
reverse_digits(N, M) :-
( integer(N) ->
reverse_digits(N, 0, M)
; integer(M),
reverse_digits(M, 0, N)
).
reverse_digits(0, M, M) :- !.
reverse_digits(N, M0, M) :-
N > 0,
R is N div 10,
M1 is M0 * 10 + N mod 10,
reverse_digits(R, M1, M).
This solution can be used with either argument bound to an integer and leaves no spurious choice-points:
?- reverse_digits(12345, M).
M = 54321.
?- reverse_digits(N, 12345).
N = 54321.
?- reverse_digits(12345, 54321).
true.
But note that this solution, unlike the constraints based solution, cannot be used as a generator of pairs of integers that satisfy the relation:
?- reverse_digits(N, M).
false.
reverseNumber(N,R):-reverse_acc(N,0,R).
reverse_acc(0,Acc,Acc).
reverse_acc(N,Acc,R):- C is N mod 10, N1 is N div 10,
Acc1 is Acc * 10 + C,
reverse_acc(N1, Acc1,R).
I have the following Prolog from the book mastering Prolog, and I'm trying to learn some simple recursion.
mins_to_hours(In, H, M):-
In<60,
H = 0,
M is In.
mins_to_hours(In, H, M):-
In>=60,
In1 is In-60,
H1 is H+1,
mins_to_hours(In1, H1, M).
I'm not entirely sure why it doesn't work and I've been fiddling with it for hours. Any help even to point me in the right direction is much appreciated. Thanks in advance.
A major difficulty you are facing in this example is the so-called modedness of low-level arithmetic predicates. For example, let us try the most general query with the code you posted:
?- mins_to_hours(In, H, M).
ERROR: Arguments are not sufficiently instantiated
To get rid of this shortcoming, I first replace the low-level predicates with CLP(FD) constraints, which are available in all major Prolog systems and simplify reasoning over your code.
For this, I simply replace (<)/2 by (#<)/2, (is)/2 by (#=)/2 etc. (depending on your Prolog system, you may also still have to import a library for this):
mins_to_hours(In, H, M):-
In #< 60,
H = 0,
M #= In.
mins_to_hours(In, H, M):-
In #>= 60,
In1 #= In-60,
H1 #= H+1,
mins_to_hours(In1, H1, M).
Now, let us again try the most general query, where all arguments are fresh variables:
?- mins_to_hours(In, H, M).
In = M,
H = 0,
M in inf..59 ;
H = -1,
In in 60..119,
M+60#=In,
M in 0..59 ;
H = -2,
In in 120..179,
_5238+60#=In,
_5238 in 60..119,
M+60#=_5238,
M in 0..59 .
Here, it seems very odd that H can assume negative values!
Let us try a few concrete cases:
?- mins_to_hours(30, H, M).
H = 0,
M = 30 ;
false.
This still seems quite OK!
?- mins_to_hours(60, H, M).
H = -1,
M = 0 ;
false.
This already seems much less OK!
With a bit of practice, it is easy to see the reason: In the second clause, you are inadvertently confusing the roles of H and H1! Suppose we write the second clause like this:
mins_to_hours(In, H, M):-
In #>= 60,
In1 #= In-60,
H #= H1+1,
mins_to_hours(In1, H1, M).
Then we get:
?- mins_to_hours(60, H, M).
H = 1,
M = 0 ;
false.
And for two more cases:
?- mins_to_hours(500, H, M).
H = 8,
M = 20 ;
false.
?- mins_to_hours(1000, H, M).
H = 16,
M = 40 ;
false.
Seems pretty nice!
Note that if you stick to lower-level arithmetic, you cannot that easily correct the mistake: Using predicates like (<)/2 and (is)/2 requires that you also take into account the actual execution order of Prolog, and this is much too hard for almost all beginners. I highly recommend you use CLP(FD) constraints instead, since they let you readily try the effect of different goal orders, while keeping the relation correct and general.
I'm a beginner to Prolog and have two requirements:
f(1) = 1
f(x) = 5x + x^2 + f(x - 1)
rules:
f(1,1).
f(X,Y) :-
Y is 5 * X + X * X + f(X-1,Y).
query:
f(4,X).
Output:
ERROR: is/2: Arguments are not sufficiently instantiated
How can I add value of f(X-1)?
This can be easily solved by using auxiliary variables.
For example, consider:
f(1, 1).
f(X, Y) :-
Y #= 5*X + X^2 + T1,
T2 #= X - 1,
f(T2, T1).
This is a straight-forward translation of the rules you give, using auxiliary variables T1 and T2 which stand for the partial expressions f(X-1) and X-1, respectively. As #BallpointBen correctly notes, it is not sufficient to use the terms themselves, because these terms are different from their arithmetic evaluation. In particular, -(2,1) is not the integer 1, but 2 - 1 #= 1 does hold!
Depending on your Prolog system, you may ned to currently still import a library to use the predicate (#=)/2, which expresses equality of integer expressesions.
Your example query now already yields a solution:
?- f(4, X).
X = 75 .
Note that the predicate does not terminate universally in this case:
?- f(4, X), false.
nontermination
We can easily make it so with an additional constraint:
f(1, 1).
f(X, Y) :-
X #> 1,
Y #= 5*X + X^2 + T1,
T2 #= X - 1,
f(T2, T1).
Now we have:
?- f(4, X).
X = 75 ;
false.
Note that we can use this as a true relation, also in the most general case:
?- f(X, Y).
X = Y, Y = 1 ;
X = 2,
Y = 15 ;
X = 3,
Y = 39 ;
X = 4,
Y = 75 ;
etc.
Versions based on lower-level arithmetic typically only cover a very limited subset of instances of such queries. I therefore recommend that you use (#=)/2 instead of (is)/2. Especially for beginners, using (is)/2 is too hard to understand. Take the many related questions filed under instantiation-error as evidence, and see clpfd for declarative solutions.
The issue is that you are trying to evaluate f(X-1,Y) as if it were a number, but of course it is a predicate that may be true or false. After some tinkering, I found this solution:
f(1,1).
f(X,Y) :- X > 0, Z is X-1, f(Z,N), Y is 5*X + X*X + N.
The trick is to let it find its way down to f(1,N) first, without evaluating anything; then let the results bubble back up by satisfying Y is 5*X + X*X + N. In Prolog, order matters for its search. It needs to satisfy f(Z,N) in order to have a value of N for the statement Y is 5*X + X*X + N.
Also, note the condition X > 0 to avoid infinite recursion.
I'm trying to implement a program that takes a variable with multiple values and evaluates all the values. For instance:
foo(X,R) :-
X > 2,
Z is R + 1,
R = Z.
This program might not be valid, but it will help me ask the question regardless.
My question: If X has multiple values, how would I increment the counter for each value X > 2?
In order to instantiate X to increasingly larger integers you can use the following:
?- between(0, inf, X).
X = 0 ;
X = 1 ;
X = 2 ;
X = 3 ;
X = 4 ;
<ETC.>
PS1: Notice that you have to instantiate R as well since it is used in the arithmetic expression Z is R + 1.
PS2: Notice that your program fails for all instantiations of X and R since R =\= R + 1 for finite R. The for instance means that the following query will not terminate:
?- between(0, inf, X), foo(X, 1).
Alternatively, the program can be rewritten in library CLP(FD) (created by Markus Triska):
:- use_module(library(clpfd)).
foo(X,R):-
X #> 2,
Z #= R + 1,
R #= Z.
Define a Prolog predicate makelist/3 such that makelist(Start, End, List) is true if
List is a list of all integers from the integer Start to the integer End. For example:
makelist(3, 7, [3, 4, 5, 6, 7]) should be true.
Can't understand why my code doesn't work
makelist(H, L, _) :-
L is H+1.
makelist(H, L, List) :-
append([], [H], List), H1 is H+1.
makelist(H1, L, List) :-
append(List, [H1], List1), last(List1, R),
R \= L+1, makelist(N, L, List1), N is H1+1.
You can simplify your code, let's take your predicate and examine what is what you really need to do:
% makelist(X,Y,L)
Since your recursive call is increasing by 1 the first parameter, let's call it X, then your base case would be when X is the same than Y:
makelist(X,X,[X]) .
and your recursive call: it will be when X is smaller than Y, you need to increase X and add the value to the list:
makelist(X,Y,[X|L]) :- X < Y ,
X1 is X + 1 ,
makelist(X1, Y, L).