Prolog arithmetic syntax - prolog

How to define a as a integer/float number ?
I want to find the results of a+b+c+d=10 where a,b,c,d is integer and >=0.

Here is a simple, modern, pure Prolog, non-CLP-library solution:
range(X):-
member(X,[0,1,2,3,4,5,6,7,8,9,10]).
ten(A,B,C,D):-
range(A),
range(B),
range(C),
range(D),
10 =:= A + B + C + D.

with SWI-Prolog you can use CLP(FD) library
1 ?- use_module(library(clpfd)).
% library(error) compiled into error 0.00 sec, 9,764 bytes
% library(clpfd) compiled into clpfd 0.05 sec, 227,496 bytes
true.
2 ?- Vars=[A,B,C,D],Vars ins 0..10,sum(Vars,#=,10),label(Vars).
Vars = [0, 0, 0, 10],
A = 0,
B = 0,
C = 0,
D = 10 ;
Vars = [0, 0, 1, 9],
A = 0,
B = 0,
C = 1,
D = 9 ;
Vars = [0, 0, 2, 8],
A = 0,
B = 0,
C = 2,
D = 8 ;
Vars = [0, 0, 3, 7],
A = 0,
B = 0,
C = 3,
D = 7 ;
...

Here is GNU-Prolog piece of code with constraint solving over finite domains :
$ gprolog
| ?- [user].
compiling user for byte code...
ten(A,B,C,D) :- fd_domain([A,B,C,D],0,9999999), 10 #= A + B + C + D.
Ctrl + D
| ?- ten(A,B,C,D), fd_labeling([A,B,C,D]).
As you can see, it solves problem of big ranges like 0-9999999
A = 0
B = 0
C = 0
D = 10 ? ;
A = 0
B = 0
C = 1
D = 9 ? ;
A = 0
B = 0
C = 2
D = 8 ? ;
...
P.S. Thanks for Przemysław Kobylański for his blog with clear, very nice Prolog examples, where I've found inspiring examples.
P.P.S. When playing with finite domains, you might like to use fd_set_vector_max/1 . In above case it's not needed, but depending on constraint might be usefull - more details when Gnu-Prolog operates on ranges, when on vectors of possible values, can be found at manual "Finite domain solver and built-in predicates - Introduction"

Related

Predicate that, if we input 6 as argument, generates A = 6, B = 0... A = 4, B = 2... A = 2, B = 4... A = 0, B = 6 and ends

This is what I have:
values(Count, A, B) :-
A is Count,
B is 0.
values(Count, A, B) :-
values(Count, Aa, Bb),
A is Aa-2,
B is Bb+2,
\+ A < 0;
B < 0.
So I want by output to be:
A = 6,
B = 0
A = 4,
B = 2
A = 2,
B = 4
A = 0,
B = 6
I'm getting that, but then the interpreter just keeps going and runs out of Stack space, because the recursive values(Count, Aa, Bb) is at the start. I don't know how to rewrite this so that the recursion isn't endless, I want it to end after I get the above output. Would anyone be able to help?
I would do it like this:
val(A,A,0):-
A>=0.
val(C,A,B):-
CC is C-2,
CC >=0,
val(CC,A,BB),
B is BB+2.
The output is
?- val(6, A, B).
A = 6,
B = 0 ;
A = 4,
B = 2 ;
A = 2,
B = 4 ;
A = 0,
B = 6 ;
false.
So what is the difference? I use the Count variable as counter. It has to decrease in every step to force the recursion to end. The downside is I have to make sure the counter is never less than zero.
It might be easier if you use between/3. Do you know that the argument is a positive even number?
p(To0, A, B) :-
To is To0 div 2,
between(0, To, X),
A is (To - X) * 2,
B is X * 2.
?- p(6, A, B).
A = 6,
B = 0 ;
A = 4,
B = 2 ;
A = 2,
B = 4 ;
A = 0,
B = 6.

Double factorial swi-prolog

help please I need to find ((2n-1)!!) \ (2n)!! but I only know how to write factorial not double.
factorial(0,1).
factorial(N,F) :-
N>0,
N1 is N-1,
factorial(N1,F1),
F is N * F1.
If you look up the Wikipedia entry on double factorial you can easily spot the two candidates for base cases: 0!! = 1 and 1!! = 1. Depending on the number n being odd or even you'll arrive at one of those base cases when calculating n!! recursively because, in the recursive rule, n is decreased by 2 instead of 1 (compared to n!). You can express that in Prolog like so:
doublefactorial(0,1).
doublefactorial(1,1).
doublefactorial(N,F) :-
N > 1,
N2 is N-2,
doublefactorial(N2,F1),
F is N * F1.
If you query this predicate you'll get the desired result:
?- doublefactorial(0,F).
F = 1 ;
false.
?- doublefactorial(1,F).
F = 1 ;
false.
?- doublefactorial(2,F).
F = 2 ;
false.
?- doublefactorial(3,F).
F = 3 ;
false.
?- doublefactorial(4,F).
F = 8 ;
false.
?- doublefactorial(5,F).
F = 15 ;
false.
.
.
.
However, due to the use of >/2 and is/2, this predicate can only be used in one direction:
?- doublefactorial(N,10395).
ERROR: >/2: Arguments are not sufficiently instantiated
?- doublefactorial(N,F).
N = 0,
F = 1 ;
N = F, F = 1 ;
ERROR: >/2: Arguments are not sufficiently instantiated
If you'd like to use the predicate in all directions you could opt to use CLP(FD):
:- use_module(library(clpfd)).
doublefactorial2(0,1).
doublefactorial2(1,1).
doublefactorial2(N,F) :-
N #> 1,
N2 #= N-2,
F #= N * F1,
doublefactorial2(N2,F1).
?- doublefactorial2(N,10395).
N = 11 ;
false.
?- doublefactorial2(N,46080).
N = 12 ;
false.
?- doublefactorial2(N,F).
N = 0,
F = 1 ;
N = F, F = 1 ;
N = F, F = 2 ;
N = F, F = 3 ;
N = 4,
F = 8 ;
N = 5,
F = 15 ;
N = 6,
F = 48 ;
N = 7,
F = 105 ;
N = 8,
F = 384 ;
N = 9,
F = 945 ;
.
.
.
Note how the goal F #= N * F1 can now be put in front of the recursive goal, thus making the predicate tail-recursive, because that equation is now propagated as a constraint. For more information see the SWI-Prolog documentation on CLP(FD).
To calculate (2n)!!/(2n-1)!! or (2n-1)!!/(2n)!! for a particular n you can query the the predicate like this:
?- N=5, X #= 2*N, doublefactorial2(X,F1), Y #= 2*N-1, doublefactorial2(Y,F2), RESULT is F1/F2.
N = 5,
X = 10,
F1 = 3840,
Y = 9,
F2 = 945,
RESULT = 4.063492063492063 ;
false.
?- N=5, X #= 2*N, doublefactorial2(X,F1), Y #= 2*N-1, doublefactorial2(Y,F2), RESULT is F2/F1.
N = 5,
X = 10,
F1 = 3840,
Y = 9,
F2 = 945,
RESULT = 0.24609375 ;
false.
Note that the result is actually calculated using is/2. This is because, in general, the result is not an integer but a rational number, hence you can use CLP(Q) to get the result as a fraction:
?- use_module(library(clpq)).
% library(clpq) compiled into clpq 0.08 sec, 1,189 clauses
true.
?- N=5, X #= 2*N, doublefactorial2(X,F1), Y #= 2*N-1, doublefactorial2(Y,F2), {RESULT = F1/F2}.
N = 5,
X = 10,
F1 = 3840,
Y = 9,
F2 = 945,
RESULT = 256 rdiv 63 ;
false.
?- N=5, X #= 2*N, doublefactorial2(X,F1), Y #= 2*N-1, doublefactorial2(Y,F2), {RESULT = F2/F1}.
N = 5,
X = 10,
F1 = 3840,
Y = 9,
F2 = 945,
RESULT = 63 rdiv 256 ;
false.
For more details see the SWI-Prolog documentation on CLP(Q). Due to the use of CLP(FD) you can also query for a range of n, say 1 to 5:
?- N in 1..5, X #= 2*N, doublefactorial2(X,F1), Y #= 2*N-1, doublefactorial2(Y,F2), {RESULT = F1/F2}.
N = Y, Y = F2, F2 = 1,
X = F1, F1 = RESULT, RESULT = 2 ;
N = 2,
X = 4,
F1 = 8,
Y = F2, F2 = 3,
RESULT = 8 rdiv 3 ;
N = 3,
X = 6,
F1 = 48,
Y = 5,
F2 = 15,
RESULT = 16 rdiv 5 ;
N = 4,
X = 8,
F1 = 384,
Y = 7,
F2 = 105,
RESULT = 128 rdiv 35 ;
N = 5,
X = 10,
F1 = 3840,
Y = 9,
F2 = 945,
RESULT = 256 rdiv 63 ;
false.

How to find two numbers where a restriction is applied

Let's say that I want to find two numbers where the sum of these are 8, are from 1-9 and must be different(it is obvious that these numbers are (7,1),(6,2),etc).So I wrote.
dif_list([H|T]):- \+ member(H,T),dif_list(T).
dif_list([]).
check1_9([H|T]):-H>=1,H=<9,check1_9(T).
check1_9([]).
find_number([A,B],N) :- N =:= A+B,dif_list([A,B]),check1_9([A,B]).
Afterwards I will ask prolog
?-find_number([A,B],8).
ERROR: =:=/2: Arguments are not sufficiently instantiated
My goal is that prolog will print for me the results.For example:
?-find_number([A,B],8).
A = 7,
B = 1 ;
A = 6,
B = 2 ;
...
The best way to handle this kind of problem in Prolog is to use the CLP(FD) library:
:- [library(clpfd)].
sum_of(A, B, Sum) :-
A #> 0,
B #> 0,
A + B #= Sum.
?- sum_of(A, B, 8), label([A, B]).
A = 1,
B = 7 ;
A = 2,
B = 6 ;
A = 3,
B = 5 ;
A = B, B = 4 ;
A = 5,
B = 3 ;
A = 6,
B = 2 ;
A = 7,
B = 1.
?-
If you want the addends to be unique, you can further constrain it:
sum_of(A, B, Sum) :-
A #> 0,
B #>= A,
A + B #= Sum.
There's really no need to use a list to manage the variables A and B, but you can if you wish: sum_of([A,B], Sum).
Prolog is not that declarative: there are indeed answer set programming (ASP) or constraint logic programming (clp) languages where you can simply define a set of constraints and a finite domain solver aims to solve it (but these will take considerable time).
I would suggest that you define your program as follows:
find_number(A,B,N) :-
member(A,[1,2,3,4,5,6,7,8,9]),
member(B,[1,2,3,4,5,6,7,8,9]),
N is A+B,
A \= B.
Here member/2 will instantiate A and B to values that are provided by the list, so 1..9, next you use is/2 to calculate the sum and verify that the sum is equal to N. You can only call N is A+B if A and B are given a proper value. Finally we say A \= B (A is not equal to B).
When you run this predicate, it produces:
?- find_number(A,B,8).
A = 1,
B = 7 ;
A = 2,
B = 6 ;
A = 3,
B = 5 ;
A = 5,
B = 3 ;
A = 6,
B = 2 ;
A = 7,
B = 1 ;
false.
You can however also query with A and B already filled in, or one of them filled in, or where the sum is left open. So:
?- find_number(A,2,8).
A = 6 ;
false.
or:
?- find_number(A,2,N).
A = 1,
N = 3 ;
A = 3,
N = 5 ;
A = 4,
N = 6 ;
A = 5,
N = 7 ;
A = 6,
N = 8 ;
A = 7,
N = 9 ;
A = 8,
N = 10 ;
A = 9,
N = 11 ;
false.

Write a Prolog program that solves the following arithmetic puzzle

PYP
CQB
CBCW
-----
WXYPB
where each letter represents a unique digit from 0-9 and the value below the line represents the sum of those about it.
Check out the very related question Faster implementation of verbal arithmetic in Prolog.
Based on my previous answer, let's solve your specific equation using clpfd!
?- Eq = ([P,Y,P] + [C,Q,B] + [C,B,C,W] #= [W,X,Y,P,B]),
crypt_arith_(Eq,Zs),
labeling([],Zs).
Eq = ([9,3,9]+[8,7,5]+[8,5,8,1]#=[1,0,3,9,5]),
Zs = [9,3,8,7,5,1,0],
P = 9,
Y = 3,
C = 8,
Q = 7,
B = 5,
W = 1,
X = 0 ;
false.

Restricting Variable Domain without CLPFD Library

I have a list of variables in my program, say A, B, C, D, ..., J, and I need to restrict the domain of each of the variables to the same set of integers, say 1, 2, ... 10. I know of a few different ways to do this, but all of them use at least one method from CLPFD, such as X #> 0, X ins [domain], or fd_domain(args). I haven't been able to find a way of doing this without any built-in libraries (all of which are banned for this project).
I would think that writing in the rules like this would be sufficient:
A > 0, A < 11, B > 0, B < 11, ..., J > 0, J < 11
But apparently the variables are not sufficiently instantiated. I know it's a trivially simple question, but I've been searching on my own for a while and really have no other resources for help. Thanks very much.
There's the between function in SWI-Prolog:
?- between(1, 9, A).
A = 1 ;
A = 2 ;
A = 3 ;
A = 4 ;
A = 5 ;
A = 6 ;
A = 7 ;
A = 8 ;
A = 9.
If that's banned as well (it's non-standard), then you use member/2:
?- member(A, [1, 2, 3, 4, 5, 6, 7, 8, 9]).
A = 1 ;
A = 2 ;
A = 3 ;
A = 4 ;
A = 5 ;
A = 6 ;
A = 7 ;
A = 8 ;
A = 9.
Without CLP(fd), you'll be trapped in the generate-and-test paradigm, though, and perhaps it's better to find some workaround where you check variable values in an ad hoc way to get decent performance.

Resources