Related
I have a program fib(X,Y). If Y is the Xth Fibonacci number it returns True else it should return False. My program breaks anytime I input statement which is false.
fib(R,V) :- fib(0,1,R,V).
fib(X, Y, 0, V) :- Y == V.
fib(X, Y, R, V) :- Z is X + Y, C is R - 1, fib(Y, Z, C, V).
fib(0,1) -> True
fib(1,1) -> True
fib(2,2) -> True
fib(3,3) -> True
fib(4,5) -> True
fib(3,5) -> Won't finish.
What do I do wrong? I am using https://swish.swi-prolog.org/ to run my program queries.
The problem here is that you write two clauses fib(X, Y, 0, V) :- and fib(X, Y, R, V) :-. Prolog uses backtracking: in case one clause has been tried, it wil - regardless of sucess or failure - also later retry the next clause (there are some meta-predicates like once/1 that can alter this).
So even if R is 0, or lower, Prolog will also try the second clause.
A quick way to fix this is by using a guards for the second clause:
fib(_, Y, 0, V) :-
Y == V.
fib(X, Y, R, V) :-
R > 0,
Z is X + Y,
C is R - 1,
fib(Y, Z, C, V).
Furthermore your code is not very elegant in the sense that you can not use the relation in a reversed way, nor can we query for the X-th element.
For instance you use Y == V, but this blocks unification: if we want to know the X-th fibonacci number, we want a way to propagate the result back. So we can use unification instead:
fib(_, V, 0, V).
fib(X, Y, R, V) :-
R > 0,
Z is X + Y,
C is R - 1,
fib(Y, Z, C, V).
But now we still do not have a bidirectional relation: we can not obtain the X for a given value V. This is more complex. The easiest way is probably using clpfd for this:
:- use_module(library(clpfd)).
fib(_, V, 0, V).
fib(X, Y, R, V) :-
R #> 0,
V #>= Y,
Z is X + Y,
C #= R - 1,
fib(Y, Z, C, V).
Now we can:
enumerate all indices and the corresponding Fibonacci numbers:
?- fib(A,B).
A = 0,
B = 1 ;
A = B, B = 2 ;
A = B, B = 3 ;
A = 4,
B = 5 ;
A = 5,
B = 8 ;
A = 6,
B = 13 ;
A = 7,
B = 21
...
Obtain the i-th Fibonacci number:
?- fib(2,B).
B = 2 ;
false.
?- fib(10,B).
B = 89 ;
false.
obtain the i for which the corresponding Fibonacci number is a certain value:
?- fib(A,1).
A = 0 ;
A = 1 ;
false.
?- fib(A,2).
A = 2 ;
false.
?- fib(A,3).
A = 3 ;
false.
?- fib(A,4).
false.
?- fib(A,5).
A = 4 ;
false.
Check if the i-th Fibonacci number is a given value:
?- fib(4,5).
true ;
false.
?- fib(4,6).
false.
?- fib(4,10).
false.
?- fib(5,8).
true ;
false.
I'm not even sure if this is possible, but I'm trying to write a predicate prime/1 which constrains its argument to be a prime number.
The problem I have is that I haven't found any way of expressing “apply that constraint to all integers less than the variable integer”.
Here is an attempt which doesn't work:
prime(N) :-
N #> 1 #/\ % Has to be strictly greater than 1
(
N #= 2 % Can be 2
#\/ % Or
(
N #> 2 #/\ % A number strictly greater than 2
N mod 2 #= 1 #/\ % which is odd
K #< N #/\
K #> 1 #/\
(#\ (
N mod K #= 0 % A non working attempt at expressing:
“there is no 1 < K < N such that K divides N”
))
)
).
I hoped that #\ would act like \+ and check that it is false for all possible cases but this doesn't seem to be the case, since this implementation does this:
?- X #< 100, prime(X), indomain(X).
X = 2 ; % Correct
X = 3 ; % Correct
X = 5 ; % Correct
X = 7 ; % Correct
X = 9 ; % Incorrect ; multiple of 3
X = 11 ; % Correct
X = 13 ; % Correct
X = 15 % Incorrect ; multiple of 5
…
Basically this unifies with 2\/{Odd integers greater than 2}.
EDIT
Expressing that a number is not prime is very easy:
composite(N) :-
I #>= J,
J #> 1,
N #= I*J.
Basically: “N is composite if it can be written as I*J with I >= J > 1”.
I am still unable to “negate” those constraints. I have tried using things like #==> (implies) but this doesn't seem to be implification at all! N #= I*J #==> J #= 1 will work for composite numbers, even though 12 = I*J doesn't imply that necessarily J = 1!
prime/1
This took me quite a while and I'm sure it's far from being very efficient but this seems to work, so here goes nothing:
We create a custom constraint propagator (following this example) for the constraint prime/1, as such:
:- use_module(library(clpfd)).
:- multifile clpfd:run_propagator/2.
prime(N) :-
clpfd:make_propagator(prime(N), Prop),
clpfd:init_propagator(N, Prop),
clpfd:trigger_once(Prop).
clpfd:run_propagator(prime(N), MState) :-
(
nonvar(N) -> clpfd:kill(MState), prime_decomposition(N, [_])
;
clpfd:fd_get(N, ND, NL, NU, NPs),
clpfd:cis_max(NL, n(2), NNL),
clpfd:update_bounds(N, ND, NPs, NL, NU, NNL, NU)
).
If N is a variable, we constrain its lower bound to be 2, or keep its original lower bound if it is bigger than 2.
If N is ground, then we check that N is prime, using this prime_decomposition/2 predicate:
prime_decomposition(2, [2]).
prime_decomposition(N, Z) :-
N #> 0,
indomain(N),
SN is ceiling(sqrt(N)),
prime_decomposition_1(N, SN, 2, [], Z).
prime_decomposition_1(1, _, _, L, L) :- !.
prime_decomposition_1(N, SN, D, L, LF) :-
(
0 #= N mod D -> !, false
;
D1 #= D+1,
(
D1 #> SN ->
LF = [N |L]
;
prime_decomposition_2(N, SN, D1, L, LF)
)
).
prime_decomposition_2(1, _, _, L, L) :- !.
prime_decomposition_2(N, SN, D, L, LF) :-
(
0 #= N mod D -> !, false
;
D1 #= D+2,
(
D1 #> SN ->
LF = [N |L]
;
prime_decomposition_2(N, SN, D1, L, LF)
)
).
You could obviously replace this predicate with any deterministic prime checking algorithm. This one is a modification of a prime factorization algorithm which has been modified to fail as soon as one factor is found.
Some queries
?- prime(X).
X in 2..sup,
prime(X).
?- X in -100..100, prime(X).
X in 2..100,
prime(X).
?- X in -100..0, prime(X).
false.
?- X in 100..200, prime(X).
X in 100..200,
prime(X).
?- X #< 20, prime(X), indomain(X).
X = 2 ;
X = 3 ;
X = 5 ;
X = 7 ;
X = 11 ;
X = 13 ;
X = 17 ;
X = 19.
?- prime(X), prime(Y), [X, Y] ins 123456789..1234567890, Y-X #= 2, indomain(Y).
X = 123457127,
Y = 123457129 ;
X = 123457289,
Y = 123457291 ;
X = 123457967,
Y = 123457969
…
?- time((X in 123456787654321..1234567876543210, prime(X), indomain(X))).
% 113,041,584 inferences, 5.070 CPU in 5.063 seconds (100% CPU, 22296027 Lips)
X = 123456787654391 .
Some problems
This constraint does not propagate as strongly as it should. For example:
?- prime(X), X in {2,3,8,16}.
X in 2..3\/8\/16,
prime(X).
when we should know that 8 and 16 are not possible since they are even numbers.
I have tried to add other constraints in the propagator but they seem to slow it down more than anything else, so I'm not sure if I was doing something wrong or if it is slower to update constaints than check for primeness when labeling.
There are some instances where recursive predicates can be CLP(FD)-fied with the benefit that the predicate turns bidirectional. What are the limits of this method? For example can the following computation CLP(FD)-fied:
Fn: n-th Fibonacci Number
Ln: n-th Lucas Number (starting with 2)
By this doubling recursion step:
F2n = Fn*Ln
L2n = (5*Fn^2+Ln^2)//2
And this incrementing recursion step:
Fn+1 = (Fn+Ln)//2
Ln+1 = (5*Fn+Ln)//2
The traditional Prolog realization works already from n to Fn. Can this be turned into a CLP(FD) program preserving the fast recursion and at the same time making it bidirectionally, for example figuring out the index n for Fn=377? If yes how? If not why?
Bye
Yes, it can be done by constraining the values. You can also move the recursion to be tail recursion, although it's not required to get the solutions:
fibluc(0, 0, 2).
fibluc(1, 1, 1).
fibluc(N, F, L) :-
N in 2..1000, % Pick a reasonable value here for 1000
[F, L] ins 1..sup,
N rem 2 #= 1,
M #= N-1,
F #= (F1 + L1) // 2,
L #= (5*F1 + L1) // 2,
fibluc(M, F1, L1).
fibluc(N, F, L) :-
N in 2..1000, % Pick a reasonable value here for 1000
[F, L] ins 1..sup,
N rem 2 #= 0,
M #= N // 2,
F #= F1 * L1,
L #= (5*F1*F1 + L1*L1) // 2,
fibluc(M, F1, L1).
Will yield:
?- fibluc(10, X, Y).
X = 55,
Y = 123 ;
false.
?- fibluc(N, 55, Y).
N = 10,
Y = 123 ;
false.
?- fibluc(N, X, 123).
N = 10,
X = 55 ;
false.
?- fibluc(N, 55, 123).
N = 10 ;
false.
?- fibluc(N, 55, 125).
false.
?- fibluc(N, X, Y).
N = X, X = 0,
Y = 2 ;
N = X, X = Y, Y = 1 ;
N = 3,
X = 2,
Y = 4 ;
N = 7,
X = 13,
Y = 29 ;
N = 15,
X = 610,
Y = 1364 ;
N = 31,
X = 1346269,
Y = 3010349 ;
N = 63,
X = 6557470319842,
Y = 14662949395604 ;
...
This could be modified to generate results for increasing values of N when N is uninstantiated.
Here's a timed, compound query example, run in SWI Prolog 7.1.33 under Linux:
?- time((fibluc(100, X, Y), fibluc(N, X, Z))).
% 11,337,988 inferences, 3.092 CPU in 3.100 seconds (100% CPU, 3666357 Lips)
X = 354224848179261915075,
Y = Z, Z = 792070839848372253127,
N = 100 ;
% 1,593,620 inferences, 0.466 CPU in 0.468 seconds (100% CPU, 3417800 Lips)
false.
?-
Using SWI Prolog 7.2.3 with the same code above and the same compound query, the code does go off for a very long time. I waited at least 15 minutes without termination. It's still running right now... I may check on it in the morning. :)
I did, however, re-arrange the above code to move the recursive call back to where the original code had it as follows:
fibluc(0, 0, 2).
fibluc(1, 1, 1).
fibluc(N, F, L) :-
N in 2..1000, % Pick a reasonable value here for 1000
[F, L] ins 1..sup,
N rem 2 #= 1,
M #= N-1,
fibluc(M, F1, L1),
F #= (F1 + L1) // 2,
L #= (5*F1 + L1) // 2.
fibluc(N, F, L) :-
N in 2..1000, % Pick a reasonable value here for 1000
[F, L] ins 1..sup,
N rem 2 #= 0,
M #= N // 2,
fibluc(M, F1, L1),
F #= F1 * L1,
L #= (5*F1*F1 + L1*L1) // 2.
In this case, the favorable results returned:
?- time((fibluc(100, X, Y), fibluc(N, X, Z))).
% 10,070,701 inferences, 3.216 CPU in 3.222 seconds (100% CPU, 3131849 Lips)
X = 354224848179261915075,
Y = Z, Z = 792070839848372253127,
N = 100 ;
% 1,415,320 inferences, 0.493 CPU in 0.496 seconds (100% CPU, 2868423 Lips)
false.
Note that the performance of CLP(FD) can be vastly different between different Prolog interpreters. It's interesting that, with SWI Prolog, the ability to handle the tail recursive case was temporarily there with version 7.1.33.
I'm kinda new to Prolog so I have a few problems with a certain task. The task is to write a tail recursive predicate count_elems(List,N,Count) condition List_Element > N, Count1 is Count+1.
My approach:
count_elems( L, N, Count ) :-
count_elems(L,N,0).
count_elems( [H|T], N, Count ) :-
H > N ,
Count1 is Count+1 ,
count_elems(T,N,Count1).
count_elems( [H|T], N, Count ) :-
count_elems(T,N,Count).
Error-Msg:
ERROR: toplevel: Undefined procedure: count_elems/3 (DWIM could not correct goal)
I'm not quite sure where the problem is. thx for any help :)
If you want to make a tail-recursive version of your code, you need (as CapelliC points out) an extra parameter to act as an accumulator. You can see the issue in your first clause:
count_elems(L, N, Count) :- count_elems(L,N,0).
Here, Count is a singleton variable, not instantiated anywhere. Your recursive call to count_elems starts count at 0, but there's no longer a variable to be instantiated with the total. So, you need:
count_elems(L, N, Count) :-
count_elems(L, N, 0, Count).
Then declare the count_elem/4 clauses:
count_elems([H|T], N, Acc, Count) :-
H > N, % count this element if it's > N
Acc1 is Acc + 1, % increment the accumulator
count_elems(T, N, Acc1, Count). % check the rest of the list
count_elems([H|T], N, Acc, Count) :-
H =< N, % don't count this element if it's <= N
count_elems(T, N, Acc, Count). % check rest of list (w/out incrementing acc)
count_elems([], _, Count, Count). % At the end, instantiate total with accumulator
You can also use an "if-else" structure for count_elems/4:
count_elems([H|T], N, Acc, Count) :-
(H > N
-> Acc1 is Acc + 1
; Acc1 = Acc
),
count_elems(T, N, Acc1, Count).
count_elems([], _, Count, Count).
Also as CapelliC pointed out, your stated error message is probably due to not reading in your prolog source file.
Preserve logical-purity with clpfd!
Here's how:
:- use_module(library(clpfd)).
count_elems([],_,0).
count_elems([X|Xs],Z,Count) :-
X #=< Z,
count_elems(Xs,Z,Count).
count_elems([X|Xs],Z,Count) :-
X #> Z,
Count #= Count0 + 1,
count_elems(Xs,Z,Count0).
Let's have a look at how versatile count_elems/3 is:
?- count_elems([1,2,3,4,5,4,3,2],2,Count).
Count = 5 ; % leaves useless choicepoint behind
false.
?- count_elems([1,2,3,4,5,4,3,2],X,3).
X = 3 ;
false.
?- count_elems([1,2,3,4,5,4,3,2],X,Count).
Count = 0, X in 5..sup ;
Count = 1, X = 4 ;
Count = 3, X = Count ;
Count = 5, X = 2 ;
Count = 7, X = 1 ;
Count = 8, X in inf..0 .
Edit 2015-05-05
We could also use meta-predicate
tcount/3, in combination with a reified version of (#<)/2:
#<(X,Y,Truth) :- integer(X), integer(Y), !, ( X<Y -> Truth=true ; Truth=false ).
#<(X,Y,true) :- X #< Y.
#<(X,Y,false) :- X #>= Y.
Let's run above queries again!
?- tcount(#<(2),[1,2,3,4,5,4,3,2],Count).
Count = 5. % succeeds deterministically
?- tcount(#<(X),[1,2,3,4,5,4,3,2],3).
X = 3 ;
false.
?- tcount(#<(X),[1,2,3,4,5,4,3,2],Count).
Count = 8, X in inf..0 ;
Count = 7, X = 1 ;
Count = 5, X = 2 ;
Count = 3, X = Count ;
Count = 1, X = 4 ;
Count = 0, X in 5..sup .
A note regarding efficiency:
count_elems([1,2,3,4,5,4,3,2],2,Count) left a useless choicepoint behind.
tcount(#<(2),[1,2,3,4,5,4,3,2],Count) succeeded deterministically.
Seems you didn't consult your source file.
When you will fix this (you could save these rules in a file count_elems.pl, then issue a ?- consult(count_elems).), you'll face the actual problem that Count it's a singleton in first rule, indicating that you must pass the counter down to actual tail recursive clauses, and unify it with the accumulator (the Count that gets updated to Count1) when the list' visit is done.
You'll end with 3 count_elems/4 clauses. Don't forget the base case:
count_elems([],_,C,C).
I have this code that uses an upper bound variable N that is supposed to terminate for X and Y of the pythagorean triple. However it only freezes when it reaches the upper bound. Wasn't sure how to use the cut to stop the backtracking. Code is:
is_int(0).
is_int(X) :- is_int(Y), X is Y+1.
minus(S,S,0).
minus(S,D1,D2) :- S>0, S1 is S-1, minus(S1,D1,D3), D2 is D3+1.
pythag(X,Y,Z,N) :- int_triple(X,Y,Z,N), Z*Z =:= X*X + Y*Y.
int_triple(X,Y,Z,N) :- is_int(S), minus(S,X,S1), X>0, X<N,
minus(S1,Y,Z), Y>0, Y<N.
Will be called, for example with,
?- pythag(X,Y,Z,20).
First, let us test your solution:
?- pythag(X,Y,Z,20).
X = 4, Y = 3, Z = 5
; X = 3, Y = 4, Z = 5
; X = 8, Y = 6, Z = 10
; X = 6, Y = 8, Z = 10
; X = 12, Y = 5, Z = 13
; X = 5, Y = 12, Z = 13
; X = 12, Y = 9, Z = 15
; X = 9, Y = 12, Z = 15
; X = 15, Y = 8, Z = 17
; X = 8, Y = 15, Z = 17
; X = 16, Y = 12, Z = 20
; X = 12, Y = 16, Z = 20
; loops.
Looks perfect to me! All answers are correct solutions! ... up to and including this last solution. After that, your program loops.
Before we try to identify the problem, just hold on for a moment: You must be pretty patient to go through 12 (that is: twelve) answers only to find that loop. Do you think that this method will also work for bigger cases? How many answers are you willing to look at before you give up? Isn't there a simpler way to find out about the problem?
There is one interesting observation here: The answers found have (almost) nothing to do with the looping of the program! That is: By looking at the answers, you get (frequently – as in this case) no clue about the actual cause of the loop! So why not turn off all the answers and concentrate on the relevant part! In fact, we can do this as follows:
?- pythag(X,Y,Z,20), false.
loops.
Now, all answers have been removed due to the goal false. What remains is just the final outcome: either termination, or non-termination, or some error. Nothing else. This should facilitate our observations about termination a bit - no more blinding answers scrolling over the screen. Note that this does not solve the problem in general. After all, how long are we willing to wait? 1s ? 1m?
The actual reason of non-termination can be best understood by looking at a relevant failure slice. That is a fragment of the program whose non-termination implies the non-termination of the whole program. See this answer for more details. Here is the relevant failure slice of your program for query pythag(X,Y,Z,20), false:
pythag(X,Y,Z,N) :-
int_triple(X,Y,Z,N), false,
Z*Z =:= X*X + Y*Y.
int_triple(X,Y,Z,N) :-
is_int(S), false,
minus(S,X,S1), X>0, X<N,
minus(S1,Y,Z), Y>0, Y<N.
is_int(0) :- false.
is_int(X) :-
is_int(Y), false,
X is Y+1.
Note that there are not many things left of your program. E.g., the actual equation is gone (that's more or less the logic part...). Still, this fragment is relevant. And as long as you do not change something within that fragment, the problem will persist! That is guaranteed for a pure monotonic program as this one...
Here is my preferred solution: It uses length/2 and between/3, two frequently supported predicates of the Prolog prologue.
pythag2(X,Y,Z,N) :-
length(_, N),
between(1,N,X),
between(1,N,Y),
between(1,N,Z),
Z*Z =:= X*X + Y*Y.
I was recently as well thinking about a Prolog solution to
find Pythagorean triples. I came up with a slightly different
code. Assume we have a function:
isqrt(a) = floor(sqrt(a))
It is then enough to enumerate x and y, and to check whether
x*x+y*y is the square of some z. Namely to check for:
h = x*x+y*y, z = isqrt(h), z*z = h ?
The function isqrt can be implemented via bisection. For
symmetry breaking we can enumerate y after x. Assuming
N = 99 the resulting code is:
% between(+Integer, +Integer, -Integer)
between(Lo, Hi, _) :-
Lo > Hi, !, fail.
between(Lo, _, Lo).
between(Lo, Hi, X) :-
Lo2 is Lo+1, between(Lo2, Hi, X).
% bisect(+Integer, +Integer, +Integer, -Integer)
bisect(Lo, Hi, X, Y) :-
Lo+1 < Hi, !,
M is (Lo+Hi) // 2,
S is M*M,
(S > X -> bisect(Lo, M, X, Y);
S < X -> bisect(M, Hi, X, Y);
M = Y).
bisect(Lo, _, _, Lo).
% pythago(-List)
pythago(X) :-
X = [A,B,C],
between(1, 99, A),
between(A, 99, B),
H is A*A+B*B,
bisect(0, H, H, C),
C =< 99, H =:= C*C.
There should be 50 such Pythagorean tripples, see also Sloan's A046083:
?- findall(-, pythago(_), L), length(L, N).
N = 52.
One might like to cross check with the following
CLP(FD) solution.
:- use_module(library(clpfd)).
% pythago3(-List)
pythago3(X) :-
X = [A,B,C],
X ins 1..99,
A*A+B*B #= C*C,
A #=< B,
label(X).
It gives the same number of solutions:
?- findall(-, pythago3(_), L), length(L, N).
N = 50.