Write a Prolog program that solves the following arithmetic puzzle - prolog

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.

Related

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+clpfd: simple binary number parser with value

I'm currently trying to understand DCGs in prolog.
Consider this example.
digit(0) --> "0".
digit(1) --> "1".
binaryNumber(Val) --> digit(Val).
binaryNumber(Next*2 + Cur) -->
%CurVal #= Cur + Next*2,
binaryNumber(Next),
digit(Cur).
That produces:
207 ?- binaryNumber(X, Y, []).
X = 0,
Y = [48] ;
X = 1,
Y = [49] ;
X = 0*2+0,
Y = [48, 48] ;
X = 0*2+1,
Y = [48, 49] ;
X = 1*2+0,
Y = [49, 48] ;
X = 1*2+1,
Y = [49, 49] ;
X = (0*2+0)*2+0,
Which is nice.
However, if I want to "convert" string to value:
:- use_module(library(clpfd)).
digit(0) --> "0".
digit(1) --> "1".
binaryNumber(Val) --> digit(Val).
binaryNumber(CurVal) -->
CurVal #= Cur + Next*2,
binaryNumber(Next),
digit(Cur).
I get:
209 ?- binaryNumber(X, Y, []).
X = 0,
Y = [48] ;
X = 1,
Y = [49] ;
ERROR: binaryNumber/3: Undefined procedure: (#=)/4
ERROR: However, there are definitions for:
ERROR: (#=)/2
Exception: (7) #=(_G4807345, _G4807428+_G4807431*2, _G4807346, _G4807475) ?
...
Two questions:
Why does binaryNumber want #= to have "arity" of 4?
How do I fix this?
You're very close!
Commonly, a dcg foo//n isn't implemented "directly", but by translating a grammar foo//n to a corresponding Prolog predicate foo//(n+2). This translation is done by term_expansion/2, a mechanism analogous to macros in other languages. Usually, you don't have to mind it at all.
For more on dcg read: (1) this DCG primer, and (2) the question
"Is there a way or an algorithm to convert DCG into normal definite clauses in Prolog?" and the answers to that question.
Coming back to the subject, I see two issues in your dcg use:
If used within grammar rules, "ordinary" Prolog goals must be encapsulated with curly braces {}/1,
so they are skipped in aforementioned "grammar to predicate" translation step. In your code, you don't want to use (#=)//2 (a.k.a. (#=)/4), you want (#=)/2!
It is good practise, not to use foo/(n+2) goals directly.
Use phrase/2 or phrase/3 for that!
So let's edit the corresponding code snippet:
binaryNumber(Next*10 + Cur) -->
{ CurVal #= Cur + Next*2 },
binaryNumber(Next),
digit(Cur).
Now let's query!
?- phrase(binaryNumber(X),Ts).
X = 0, Ts = [48] ;
X = 1, Ts = [49] ;
X = 0, Ts = [48,48] ;
X = 1, Ts = [48,49] ;
X = 2, Ts = [49,48] ;
X = 3, Ts = [49,49] ...

Prolog - descending order list

I am trying to write a function - decListRange(X,List) which give a list in range [X-1:1] by descending order. For example -
decListRange(9,List).
Will give -
List = [8,7,6,5,4,3,2,1].
I tried the following but it goes into infinite loop -
decListRange(1,[]) :- !.
decListRange(X,[H|Rest]) :-
H = X-1, NextX = X - 1 ,decListRange(NextX,Rest).
You have two problems. The first real one is that you need to use is instead of =:
H is X-1
This is needed to trigger arithmetic evaluation. Your second problem isn't a real problem but speaks to a bigger misunderstanding, which is that H and NextX are equivalent. Because Prolog only has bindings and not "assignables" as it were, you should never really need to create two "variables" with the same binding. There's no state being kept around for you to modify later.
Cleaning up both you get this:
decListRange(1, []) :- !.
decListRange(X, [H|Rest]) :-
X > 1,
H is X-1,
decListRange(H, Rest).
Edit 2: a clpfd implementation
:- use_module(library(clpfd)).
declist(N, L) :- N == 1, !, L = []. % green cut
declist(1, []).
declist(N, [N1|Ns]) :-
N #> 1,
N1 #= N - 1,
declist(N1, Ns).
This one has the properties #false mentions below in the comments:
?- declist(3, L).
L = [2, 1] ;
false.
?- declist(3, [2,1]).
true ;
false.
?- declist(N, [3,2,1]).
N = 4.
?- declist(N, X).
N = 1,
X = [] ;
N = 2,
X = [1] ;
N = 3,
X = [2, 1] ;
N = 4,
X = [3, 2, 1] ;
N = 5,
X = [4, 3, 2, 1] .
Edit: a short interlude on the difference between = and is.
In procedural languages = is almost always syntax for assigning a particular value to a variable. In Prolog, variables are bindings, and once established they cannot be directly modified by reassigning the variable a different value. Instead they work more like variables in math and logic, where the variable "stands in" for interesting values, but those values are themselves basically immutable. In Prolog, = essentially asks the unification engine to establish bindings. So if you were to do something like this:
?- name(X, Y) = name(bob, tony).
Prolog responds with variable bindings:
X = bob,
Y = tony.
Once those bindings exist, contradictory bindings will fail and affirmative bindings will succeed:
?- name(X, Y) = name(bob, tony), X = bob.
X = bob,
Y = tony.
?- name(X, Y) = name(bob, tony), X = william.
false.
The unification algorithm itself doesn't know anything about arithmetic. This has the pleasant side-effect that you can use any expression raw. For instance:
?- Expr = X + 3, Z + Q = Expr.
Expr = Z+3,
X = Z,
Q = 3.
This is probably really surprising looking. You may expect that somehow Prolog was smart enough to keep the expression around because it noticed X was a variable or something, but that isn't true either:
?- X = 4, Expr = X + 3, Z + Q = Expr.
X = 4,
Expr = 4+3,
Z = 4,
Q = 3.
Another way of looking at this is that Prolog is considering + to be just another operator, so X+3 is a fact just like add(X, 3) that doesn't necessarily have any special meaning. Whichever way you look at it, the is/2 operator exists to apply arithmetic reasoning and produce a value:
?- X = 4, Expr is X + 3.
X = 4,
Expr = 7.
Notice that Expr has the computed value but none of the original structure:
?- X = 4, Expr is X + 3, Z + Q = Expr.
false.
In practice, if you need to do a lot of reasoning with arithmetic, you will want to use a library like clpfd or clpqr depending on whether you're interested in integers or reals. This library enables you to do more interesting things more easily, like specify that an equation holds for values in a certain range and get those values out.

Resources