CLPFD constraint: is a prime number - prolog

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.

Related

Incrementing value on backtrack

how can I do increment on backtracking ... so that goal(S) receives incremented number .. every time it fails on the next run I want to get the next number
S1 is S + 1,goal(S1)
does not work, because :
?- S=0, S1 is S+1.
S = 0,
S1 = 1.
?- S=0,between(1,3,_), S1 is S+1.
S = 0,
S1 = 1 ;
S = 0,
S1 = 1 ;
S = 0,
S1 = 1.
this work
%%counting
baz(..,C) :- .... arg(...), Y is X + 1, nb_setarg(...), goal(Y), ...
foo(..C) :- ....baz(....,C)..., foo(...C).
%%counter
blah :- ....foo(....,counter(0))...
this is not working, i think cause the recursive foo() would force baz() to initialize counter(0)... but i'm good with #sligo solution above
baz(..) :- C = counter(0), .... arg(...), Y is X + 1, nb_setarg(...), goal(Y), ...
foo(..) :- ....baz(....)..., foo(...).
so that goal(S) receives incremented number .. every time it fails on the next run I want to get the next number
That's what between/3 does? Every time on backtracking it makes the next number:
goal(X) :-
write('inside goal, X is '),
write(X),
nl.
test :-
between(0, 3, S),
goal(S).
e.g.
?- test.
inside goal, X is 0
true ;
inside goal, X is 1
true ;
inside goal, X is 2
true ;
inside goal, X is 3
true ;
Edit: From the help for between/3:
between(+Low, +High, ?Value)
Low and High are integers, High >=Low. If Value is an integer,
Low =<Value =<High. When Value is a variable it is successively
bound to all integers between Low and High. If High is inf or
infinite between/3 is true iff Value >=Low, a feature that is
particularly interesting for generating integers from a certain value.
(And see the comments on the help page by LogicalCaptain)
Use non-backtrackable destructive assignment predicate nb_setarg/3:
?- C = counter(0), between(1, 3, _), arg(1, C, X), Y is X + 1, nb_setarg(1, C, Y).
C = counter(1),
X = 0,
Y = 1 ;
C = counter(2),
X = 1,
Y = 2 ;
C = counter(3),
X = 2,
Y = 3.
Alternatives:
foo(C) :-
between(1, inf, C),
goal(C),
!.
baz(C) :-
C = counter(0),
repeat,
arg(1, C, X),
Y is X + 1,
nb_setarg(1, C, Y),
goal(Y),
!.
goal(X) :-
X > 9.
Examples:
?- foo(C).
C = 10.
?- baz(C).
C = counter(10).

Argument is not instantiated, need it to start at zero but also be able to change it

Whenever I run my code, I get an error that the arguments are not instantiated.
ads(X,Z):- mod(X,2) =:= 0, Z is Z+X.
ads(X,Z) :- mod(N,2) =\= 0,Z is Z.
sum_of_nums(0,0,0).
sum_of_nums(X,Y,Z) :- X=<Y, ad(X,Z), sum_of_nums(X+1,Y,Z).
I want to be able to add numbers from X to Y but only the even ones. Don't know why it doesn't work.
First, there are some tiny errors, your compiler should indicate, like the unnecessary singleton variables in the second clause. After repairing this, and replacing ads by ad we have:
ad(X,Z):- mod(X,2) =:= 0, Z is Z+X.
ad(X,Z) :- mod(X,2) =\= 0,Z is Z.
sum_of_nums(0,0,0).
sum_of_nums(X,Y,Z) :- X=<Y, ad(X,Z), sum_of_nums(X+1,Y,Z).
?- sum_of_nums(1,2,S).
error(instantiation_error,(is)/2).
To locate this error, I will insert some goals false such that the
resulting program still produces this instantiation error.
ad(X,Z):- mod(X,2) =:= 0, Z is Z+X, false.
ad(X,Z) :- false, mod(X,2) =\= 0,Z is Z.
sum_of_nums(0,0,0) :- false.
sum_of_nums(X,Y,Z) :- X=<Y, ad(X,Z), false, sum_of_nums(X+1,Y,Z).
?- sum_of_nums(1,2,S).
error(instantiation_error,(is)/2).
Therefore, you have an error in this part already.
It's the Z is Z+X. On the right hand side of (is)/2 you always
need to have variables that are instantiated (known). And Z is not
known.
Variables are a bit different in Prolog. You cannot reassign them.
And also, writing this in Prolog directly doesn't really show what the
language is good at.
sum_of(X, Y, 0) :-
X > Y.
sum_of(X1, Y, Z1) :-
X1 =< Y,
( X1 mod 2 =:= 0 -> S = X1 ; S = 0 ),
X2 is X1+1,
sum_of(X2, Y, Z2),
Z1 is Z2+S.
A more idiomatic way would be:
?- between(1,6,N).
N = 1
; N = 2
; N = 3
; N = 4
; N = 5
; N = 6.
?- between(1,6,N), N mod 2 =:= 0.
N = 2
; N = 4
; N = 6.
?- findall(N, ( between(1,6,N), N mod 2 =:= 0 ), Ns).
Ns = [2,4,6].
?- findall(N, ( between(1,6,N), N mod 2 =:= 0 ), Ns), sum_list(Ns,Sum).
Ns = [2,4,6], Sum = 12.
sum_of(X,Y,Sum) :-
findall(N, ( between(X,Y,N), N mod 2 =:= 0 ), Ns),
sum_list(Ns,Sum).

How to find the biggest digit in a number in Prolog?

I have an easy task, but somehow I haven't solved it in over an hour. This recursion I am doing isn't working, I'm stuck in an infinte loop. It should compare the last digit of a number with every other and remember the biggest one. Would really like to know why is my logic faulty and how to solve this problem.
This is my try on it:
maxDigit(X,X):-
X<10.
maxDigit(X,N):-
X1 is X//10,
X2 is X mod 10,
maxDigit(X1,N1),
X2=<N1,
N is N1.
maxDigit(X,N):-
X1 is X//10,
X2 is X mod 10,
maxDigit(X1,N1),
X2>N1,
N is X2.
Using SICStus Prolog 4.3.3 we simply combine n_base_digits/3 and maximum/2 like so:
?- n_base_digits(12390238464, 10, _Digits), maximum(Max, _Digits).
Max = 9.
A comment suggested stopping as soon as the maximum digit is encountered. This is how we do:
:- use_module(library(clpfd)).
:- use_module(library(reif)).
#=(X, Y, T) :- X #= Y #<==> B, bool10_t(B, T).
bool10_t(1, true).
bool10_t(0,false).
Based on if_/3, (;)/3 and (#=)/3 we then define:
n_base_maxdigit(N, Base, D) :-
N #> 0, % positive integers only
Base #> 1, % smallest base = 2
D #>= 0,
D #< Base,
n_base_maxdigit0_maxdigit(N, Base, 0, D).
n_base_maxdigit0_maxdigit(N, Base, D0, D) :-
D1 #= N mod Base,
N0 #= N // Base,
D2 #= max(D0,D1),
if_(( D2 + 1 #= Base ; N0 #= 0 ),
D = D2,
n_base_maxdigit0_maxdigit(N0, Base, D2, D)).
Sample query using SWI-Prolog 7.3.22 with Prolog lambda:
?- use_module(library(lambda)).
true.
?- Max+\ ( N is 7^7^7 * 10+9, time(n_base_maxdigit(N,10,Max)) ).
% 663 inferences, 0.001 CPU in 0.001 seconds (100% CPU, 1022162 Lips)
Max = 9.
You have just to use if/then/else :
maxDigit(X,X):-
X<10,
!. % added after false's remark
maxDigit(X,N):-
X1 is X//10,
X2 is X mod 10,
maxDigit(X1,N1),
( X2<N1
-> N = N1
; N = X2).
in SWI-Prolog could be:
maxDigit(N,M) :- number_codes(N,L), max_list(L,T), M is T-0'0.

CLP(FD)-ying Simultaneous Recursion for Fibonacci Lukas Numbers Possible?

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.

Inverse factorial in Prolog

Can someone helping me to find a way to get the inverse factorial in Prolog...
For example inverse_factorial(6,X) ===> X = 3.
I have been working on it a lot of time.
I currently have the factorial, but i have to make it reversible. Please help me.
Prolog's predicates are relations, so once you have defined factorial, you have implicitly defined the inverse too. However, regular arithmetics is moded in Prolog, that is, the entire expression in (is)/2 or (>)/2 has to be known at runtime, and if it is not, an error occurs. Constraints overcome this shortcoming:
:- use_module(library(clpfd)).
n_factorial(0, 1).
n_factorial(N, F) :-
N #> 0, N1 #= N - 1, F #= N * F1,
n_factorial(N1, F1).
This definition now works in both directions.
?- n_factorial(N,6).
N = 3
; false.
?- n_factorial(3,F).
F = 6
; false.
Since SICStus 4.3.4 and SWI 7.1.25 also the following terminates:
?- n_factorial(N,N).
N = 1
; N = 2
; false.
See the manual for more.
For reference, here is the best implementation of a declarative factorial predicate I could come up with.
Two main points are different from #false's answer:
It uses an accumulator argument, and recursive calls increment the factor we multiply the factorial with, instead of a standard recursive implementation where the base case is 0. This makes the predicate much faster when the factorial is known and the initial number is not.
It uses if_/3 and (=)/3 extensively, from module reif, to get rid of unnecessary choice points when possible. It also uses (#>)/3 and the reified (===)/6 which is a variation of (=)/3 for cases where we have two couples that can be used for the if -> then part of if_.
factorial/2
factorial(N, F) :-
factorial(N, 0, 1, F).
factorial(N, I, N0, F) :-
F #> 0,
N #>= 0,
I #>= 0,
I #=< N,
N0 #> 0,
N0 #=< F,
if_(I #> 2,
( F #> N,
if_(===(N, I, N0, F, T1),
if_(T1 = true,
N0 = F,
N = I
),
( J #= I + 1,
N1 #= N0*J,
factorial(N, J, N1, F)
)
)
),
if_(N = I,
N0 = F,
( J #= I + 1,
N1 #= N0*J,
factorial(N, J, N1, F)
)
)
).
(#>)/3
#>(X, Y, T) :-
zcompare(C, X, Y),
greater_true(C, T).
greater_true(>, true).
greater_true(<, false).
greater_true(=, false).
(===)/6
===(X1, Y1, X2, Y2, T1, T) :-
( T1 == true -> =(X1, Y1, T)
; T1 == false -> =(X2, Y2, T)
; X1 == Y1 -> T1 = true, T = true
; X1 \= Y1 -> T1 = true, T = false
; X2 == Y2 -> T1 = false, T = true
; X2 \= Y2 -> T1 = false, T = false
; T1 = true, T = true, X1 = Y1
; T1 = true, T = false, dif(X1, Y1)
).
Some queries
?- factorial(N, N).
N = 1 ;
N = 2 ;
false. % One could probably get rid of the choice point at the cost of readability
?- factorial(N, 1).
N = 0 ;
N = 1 ;
false. % Same
?- factorial(10, N).
N = 3628800. % No choice point
?- time(factorial(N, 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000)).
% 79,283 inferences, 0.031 CPU in 0.027 seconds (116% CPU, 2541106 Lips)
N = 100. % No choice point
?- time(factorial(N, 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518284253697920827223758251185210916864000000000000000000000000)).
% 78,907 inferences, 0.031 CPU in 0.025 seconds (125% CPU, 2529054 Lips)
false.
?- F #> 10^100, factorial(N, F).
F = 11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000,
N = 70 ;
F = 850478588567862317521167644239926010288584608120796235886430763388588680378079017697280000000000000000,
N = 71 ;
F = 61234458376886086861524070385274672740778091784697328983823014963978384987221689274204160000000000000000,
N = 72 ;
...
a simple 'low tech' way: enumerate integers until
you find the sought factorial, then 'get back' the number
the factorial being built is greater than the target. Then you can fail...
Practically, you can just add 2 arguments to your existing factorial implementation, the target and the found inverse.
Just implement factorial(X, XFact) and then swap arguments
factorial(X, XFact) :- f(X, 1, 1, XFact).
f(N, N, F, F) :- !.
f(N, N0, F0, F) :- succ(N0, N1), F1 is F0 * N1, f(N, N1, F1, F).

Resources