Restricting Variable Domain without CLPFD Library - prolog

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.

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.

Prolog - System of equations solver

I trying to create compact code in prolog that sovles systems of equations.
For example, in this case, the assumptions must be
A+B-C-D=4, A+B+C+D=14, A-B+C-D=2.
I'm trying to have it where it solves all combinations possible for A, B, C, and D but satisfies all 3 equations. They can only be #'s 0-9 though but somehow show all possible solutions/combinations.
So after running the query, it would output something like
Crypto(A,B,C,D)
A = 8, B = 1, C = 0, D = 5.
^That would be one solution. But I need to show all possible.
I'm kind of lost as to how to satisfy all 3 in Prolog. Thank you.
You can solve it by taking out one element from the domain of the variables and assign it to them such that every variable has a different number assigned to it. It's a brute force method.
takeout(X, [X|R], R).
takeout(X, [Y|Xs], [Y|Ys]):- takeout(X, Xs, Ys).
aas(X,L,L1):- takeout(X,L,L1).
crypto(A,B,C,D):-
L=[0,1,2,3,4,5,6,7,8,9],
aas(A,L,L1),aas(B,L1,L2),aas(C,L2,L3),aas(D,L3,_),
A+B-C-D=:=4,
A+B+C+D=:=14,
A-B+C-D=:=2,
nl.
aas(X,L,L1). used for assigning values to the variables.
takeout function is used for taking out one element and return a list excluding the element taken out.
OUTPUT
?- crypto(A,B,C,D).
A = 3,
B = 6,
C = 5,
D = 0
A = 5,
B = 4,
C = 3,
D = 2
A = 7,
B = 2,
C = 1,
D = 4
A = 8,
B = 1,
C = 0,
D = 5
This program prints all the possible solutions to that equation A+B-C-D=4, A+B+C+D=14, A-B+C-D=2. Hope this answers your question.

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.

clpfd - generate the list of all integers between 5 and 10

I'm working with SWI-Prolog to get clpfd generate the list of all distinct integers between 5 and 10:
q1(Answer) :-
length(Xs, Answer),
Xs ins 0..20,
chain(Xs, #<),
maplist(q1constraints, Xs).
q1constraints(X) :-
X #>= 5,
X #=< 10.
Kind of works, but generates a solution for each of the lengths 0, 1, ... 6 and then hangs seeking a solution of length 7:
?- q1(Answer).
Answer = 0 ;
Answer = 1 ;
Answer = 2 ;
Answer = 3 ;
Answer = 4 ;
Answer = 5 ;
Answer = 6 ;
<hangs>
Is there a good way to generate the list of all integers that satisfy the desired constraints?
Your question is not that clear to me. But I will try:
?- length(Xs,6), Xs ins 5..10, chain(Xs,#<), Xs = [5|_], last(Xs, 10).
Xs = [5,6,7,8,9,10].
Note that with these elements, it is necessary to fix the length of the list first. Otherwise:
?- length(Xs,N), Xs ins 5..10, chain(Xs,#<), Xs = [5|_], last(Xs, 10).
Xs = [5,10], N = 2
; Xs = [5,_A,10], N = 3, _A in 6..9
; Xs = [5,_A,_B,10], N = 4, _A#=<_B+ -1, _A in 6..8, _B in 7..9
; Xs = [5,_C,_A,_B,10], N = 5, _A#=<_B+ -1, _C#=<_A+ -1, _A in 7..8, _C in 6..7, _B in 8..9
; Xs = [5,6,7,8,9,10], N = 6
; loops.
In fact, even the (ins)/2 is not needed:
?- length(Xs,6), chain(Xs,#<), Xs = [5|_], last(Xs, 10).
Xs = [5,6,7,8,9,10].
(In newer versions of clpfd called clpz the argument order of chain/2` is reversed adhering to the common argument ordering.)
Here is what your program does:
Generate a list of increasing lengths, starting with an empty list
For each element X in the list, pose a constraint that X is in [0, 20]
For the whole list, pose a constraint that values are strictly increasing in magnitude
For each element in the list, pose an additional constraint that X is in [5, 10].
You then ask for the length of the generated list.
There are 6 values that are in [0, 20] and in [5,10]: 5, 6, 7, 8, 9, 10. For the empty list you generate first, there are no constrained variables; for the list with 1 variable, there would be 6 possible values of the variable, but you don't ask for these values, only for the length of the list; for the list with 2 variables, you will have 5 possible combinations: {5,6}, {6,7}, ..., {9,10}, but again, you don't ask for them, just for the length of the list.
Eventually, you get to list with 7 values. Since there are only 6 values that each element could have, there are no solutions.
So what is your goal here? Maybe you should try and explain better. To get all values between 5 and 10 by backtracking, you could say: between(5, 10, X), or, with CLPFD, X in 5..10, label([X]). If it is neither of these, you need to re-write your question.
If you want the total number of even integers in 5..10 (SPOILER: there are 3 of them!):
?- aggregate(count, X^(X in 5..10, X mod 2 #= 0, indomain(X)), Answer).
Answer = 3.
Breaking it down:
X in 5..10, X mod 2 #= 0 just constrains X to be an even integer between 5 and 10:
?- X in 5..10, X mod 2 #= 0.
X in 6..10,
X mod 2#=0.
indomain(X) does the actual search, succeeding once for each feasible value of X:
?- X in 5..10, X mod 2 #= 0, indomain(X).
X = 6 ;
X = 8 ;
X = 10.
X^(...) existentially quantifies X within the parentheses, limiting its scope. If we instead leave it as a free variable, aggregation will respect it:
?- aggregate(count, (X in 5..10, X mod 2 #= 0, indomain(X)), Answer).
X = 6,
Answer = 1 ;
X = 8,
Answer = 1 ;
X = 10,
Answer = 1.

Prolog arithmetic syntax

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"

Resources