I'm new to Prolog and I want to do something like this, but don't know where to start. Already made the matrix and how to verify the numbers are under 9 with Bounds library, but that's about it, have been struggling with this for days.
It should look like this:
2+7-4=5
+ - *
9-5*2=8
- + -
4*3-8=4
= = =
7 5 0
The main idea is to give Prolog a semi-filled matrix so he can complete it. Thanks for any info or ideas you can give me in advance.
A code for resolving equations by placing operators with given numbers:
:- use_module(library(bounds)).
lista([X]) --> [X].
lista([H|T]) --> [H], op, lista(T).
op --> [+].
op --> [-].
op --> [*].
op --> [/].
op --> [''].
puzzle(Num, Res) :-
permutation(Num, Numbperm),
lista(Numbperm, Lista, []),
concat_atom([Res, =:=|Lista], At),
term_to_atom(Ev, At),
call(Ev),
write(Ev), nl.
To utilize clpfd, let's use library(clpfd)), not library(bounds)!
:- use_module(library(clpfd)).
We can state the constraints that must hold like this:
m3x3_zs(Mss,Zs) :-
Mss = [[M11,M12,M13], [M21,M22,M23], [M31,M32,M33]],
Zs = [ M11,M12,M13 , M21,M22,M23 , M31,M32,M33 ],
Zs ins 0..9,
5 #= M11+M12-M13, % row constraints
8 #= (M21-M22)*M23, % (see text below for details)
4 #= M31*M32-M33,
7 #= M11+M21-M31, % column constraints
5 #= M12-M22+M23,
0 #= M13*M23-M33.
Note the highlighted goal 8 #= <b>(M21-M22)*M23</b> above! If we had used the common precedence rules for A-B*C we would have had 8 #= M21-(M22*M23), but that would have excluded the sample solution [[2,7,4],[9,5,2],[4,3,8]] you gave in the OP.
Now let's search all solutions by using the enumeration predicate
labeling/2!
?- m3x3_zs(Mss,Zs), labeling([],Zs).
Mss = [[0,5,0],[9,1,1],[2,2,0]], Zs = [0,5,0,9,1,1,2,2,0]
; Mss = [[0,5,0],[9,8,8],[2,2,0]], Zs = [0,5,0,9,8,8,2,2,0]
; Mss = [[0,7,2],[8,4,2],[1,8,4]], Zs = [0,7,2,8,4,2,1,8,4]
; Mss = [[0,8,3],[9,5,2],[2,5,6]], Zs = [0,8,3,9,5,2,2,5,6]
; Mss = [[1,4,0],[8,0,1],[2,2,0]], Zs = [1,4,0,8,0,1,2,2,0]
; Mss = [[1,4,0],[8,7,8],[2,2,0]], Zs = [1,4,0,8,7,8,2,2,0]
; Mss = [[1,5,1],[9,8,8],[3,4,8]], Zs = [1,5,1,9,8,8,3,4,8]
; Mss = [[1,6,2],[7,3,2],[1,8,4]], Zs = [1,6,2,7,3,2,1,8,4]
; Mss = [[1,7,3],[8,4,2],[2,5,6]], Zs = [1,7,3,8,4,2,2,5,6]
; Mss = [[1,8,4],[9,5,2],[3,4,8]], Zs = [1,8,4,9,5,2,3,4,8]
; Mss = [[2,3,0],[7,6,8],[2,2,0]], Zs = [2,3,0,7,6,8,2,2,0]
; Mss = [[2,4,1],[8,7,8],[3,4,8]], Zs = [2,4,1,8,7,8,3,4,8]
; Mss = [[2,5,2],[6,2,2],[1,8,4]], Zs = [2,5,2,6,2,2,1,8,4]
; Mss = [[2,6,3],[7,3,2],[2,5,6]], Zs = [2,6,3,7,3,2,2,5,6]
; Mss = [[2,7,4],[8,4,2],[3,4,8]], Zs = [2,7,4,8,4,2,3,4,8]
; Mss = [[3,2,0],[6,5,8],[2,2,0]], Zs = [3,2,0,6,5,8,2,2,0]
; Mss = [[3,3,1],[7,6,8],[3,4,8]], Zs = [3,3,1,7,6,8,3,4,8]
; Mss = [[3,4,2],[5,1,2],[1,8,4]], Zs = [3,4,2,5,1,2,1,8,4]
; Mss = [[3,5,3],[6,2,2],[2,5,6]], Zs = [3,5,3,6,2,2,2,5,6]
; Mss = [[3,6,4],[7,3,2],[3,4,8]], Zs = [3,6,4,7,3,2,3,4,8]
; Mss = [[4,1,0],[5,4,8],[2,2,0]], Zs = [4,1,0,5,4,8,2,2,0]
; Mss = [[4,2,1],[6,5,8],[3,4,8]], Zs = [4,2,1,6,5,8,3,4,8]
; Mss = [[4,3,2],[4,0,2],[1,8,4]], Zs = [4,3,2,4,0,2,1,8,4]
; Mss = [[4,4,3],[5,1,2],[2,5,6]], Zs = [4,4,3,5,1,2,2,5,6]
; Mss = [[4,5,4],[6,2,2],[3,4,8]], Zs = [4,5,4,6,2,2,3,4,8]
; Mss = [[5,0,0],[4,3,8],[2,2,0]], Zs = [5,0,0,4,3,8,2,2,0]
; Mss = [[5,1,1],[5,4,8],[3,4,8]], Zs = [5,1,1,5,4,8,3,4,8]
; Mss = [[5,3,3],[4,0,2],[2,5,6]], Zs = [5,3,3,4,0,2,2,5,6]
; Mss = [[5,4,4],[5,1,2],[3,4,8]], Zs = [5,4,4,5,1,2,3,4,8]
; Mss = [[6,0,1],[4,3,8],[3,4,8]], Zs = [6,0,1,4,3,8,3,4,8]
; Mss = [[6,3,4],[4,0,2],[3,4,8]], Zs = [6,3,4,4,0,2,3,4,8]
; false.
How about a little more specific? Which solutions have 4 in the middle?
?- m3x3_zs(Mss,Zs), Mss=[_,[_,4,_],_], labeling([],Zs).
Mss = [[0,7,2],[8,4,2],[1,8,4]], Zs = [0,7,2,8,4,2,1,8,4]
; Mss = [[1,7,3],[8,4,2],[2,5,6]], Zs = [1,7,3,8,4,2,2,5,6]
; Mss = [[2,7,4],[8,4,2],[3,4,8]], Zs = [2,7,4,8,4,2,3,4,8]
; Mss = [[4,1,0],[5,4,8],[2,2,0]], Zs = [4,1,0,5,4,8,2,2,0]
; Mss = [[5,1,1],[5,4,8],[3,4,8]], Zs = [5,1,1,5,4,8,3,4,8].
How can I generate all the possible sets of the elements of a list with current length?
?- get_set(X, [1,2,3]).
X = [1,1,1] ;
X = [1,1,2] ;
X = [1,1,3] ;
X = [1,2,1] ;
X = [1,2,2] ;
X = [1,2,3] ;
X = [1,3,1] ;
X = [1,3,2] ;
X = [1,3,3] ;
.....
X = [3,3,2] ;
X = [3,3,3].
UPD: there is good answer given by Sharky.
But maybe it's not the best. Here is another:
get_set(X,L) :- get_set(X,L,L).
get_set([],[],_).
get_set([X|Xs],[_|T],L) :- member(X,L), get_set(Xs,T,L).
Consider:
get_set(L0, L) :-
length(L, Len),
length(L0, Len),
apply_elem(L0, L).
apply_elem([], _).
apply_elem([X|Xs], L) :-
member(X, L),
apply_elem(Xs, L).
Explanation:
Determining the length of the input list L as Len allows us to generate a list of unique variables, L0, via length/2. Then, we simply apply elements of L to all members of L0 via member/2, which leaves choicepoints for options, should they exist (i.e., if the list L is of length > 1). Prolog will backtrack to generate all possible combinations of elements of L into the list L0, as required.
Based on library predicate same_length/2, we can make it work safely in "both" directions!
Simply define get_set/2 like this, using meta-predicate maplist/2:
get_set(Xs,Ys) :-
same_length(Xs,Ys),
maplist(list_member(Ys),Xs).
list_member(Xs,X) :-
member(X,Xs).
First, the sample query suggested by the OP:
?- get_set(Xs,[1,2,3]).
Xs = [1,1,1] ;
Xs = [1,1,2] ;
Xs = [1,1,3] ;
Xs = [1,2,1] ;
Xs = [1,2,2] ;
Xs = [1,2,3] ;
Xs = [1,3,1] ;
Xs = [1,3,2] ;
Xs = [1,3,3] ;
Xs = [2,1,1] ;
Xs = [2,1,2] ;
Xs = [2,1,3] ;
Xs = [2,2,1] ;
Xs = [2,2,2] ;
Xs = [2,2,3] ;
Xs = [2,3,1] ;
Xs = [2,3,2] ;
Xs = [2,3,3] ;
Xs = [3,1,1] ;
Xs = [3,1,2] ;
Xs = [3,1,3] ;
Xs = [3,2,1] ;
Xs = [3,2,2] ;
Xs = [3,2,3] ;
Xs = [3,3,1] ;
Xs = [3,3,2] ;
Xs = [3,3,3] ;
false. % terminates universally
Let's try the other way round!
?- get_set([1,2,3],Ys).
Ys = [1,2,3] ;
Ys = [1,3,2] ;
Ys = [2,1,3] ;
Ys = [3,1,2] ;
Ys = [2,3,1] ;
Ys = [3,2,1] ;
false. % terminates universally
How can I generate all the possible combinations of the elements of a list?
For example, given the list [1,2,3], I want to design a predicate with the form comb([1,2,3], L). which should return the following answer for L:
[1]
[2]
[3]
[1,2]
[2,1]
[1,3]
[3,1]
[2,3]
[3,2]
[1,2,3]
[1,3,2]
[2,1,3]
[2,3,1]
[3,1,2]
[3,2,1]
What you are asking for involves both combinations (selecting a subset) and permutations (rearranging the order) of a list.
Your example output implies that the empty list is not considered a valid solution, so we will exclude it in the implementation that follows. Reconsider if this was an oversight. Also this implementation produces the solutions in a different order than your example output.
comb(InList,Out) :-
splitSet(InList,_,SubList),
SubList = [_|_], /* disallow empty list */
permute(SubList,Out).
splitSet([ ],[ ],[ ]).
splitSet([H|T],[H|L],R) :-
splitSet(T,L,R).
splitSet([H|T],L,[H|R]) :-
splitSet(T,L,R).
permute([ ],[ ]) :- !.
permute(L,[X|R]) :-
omit(X,L,M),
permute(M,R).
omit(H,[H|T],T).
omit(X,[H|L],[H|R]) :-
omit(X,L,R).
Tested with Amzi! Prolog:
?- comb([1,2,3],L).
L = [3] ;
L = [2] ;
L = [2, 3] ;
L = [3, 2] ;
L = [1] ;
L = [1, 3] ;
L = [3, 1] ;
L = [1, 2] ;
L = [2, 1] ;
L = [1, 2, 3] ;
L = [1, 3, 2] ;
L = [2, 1, 3] ;
L = [2, 3, 1] ;
L = [3, 1, 2] ;
L = [3, 2, 1] ;
no
Stay pure by defining comb/2 based on same_length/2, prefix/2, foldl/4 and
select/3:
comb(As,Bs) :-
same_length(As,Full),
Bs = [_|_],
prefix(Bs,Full),
foldl(select,Bs,As,_).
Here's the sample query given by the OP:
?- comb([1,2,3],Xs).
Xs = [1]
; Xs = [2]
; Xs = [3]
; Xs = [1,2]
; Xs = [1,3]
; Xs = [2,1]
; Xs = [2,3]
; Xs = [3,1]
; Xs = [3,2]
; Xs = [1,2,3]
; Xs = [1,3,2]
; Xs = [2,1,3]
; Xs = [2,3,1]
; Xs = [3,1,2]
; Xs = [3,2,1]
; false.
Ok! But what if the list given as the first argument contains duplicates?
?- comb([1,1,2],Xs).
Xs = [1]
; Xs = [1] % (redundant)
; Xs = [2]
; Xs = [1,1]
; Xs = [1,2]
; Xs = [1,1] % (redundant)
; Xs = [1,2] % (redundant)
; Xs = [2,1]
; Xs = [2,1] % (redundant)
; Xs = [1,1,2]
; Xs = [1,2,1]
; Xs = [1,1,2] % (redundant)
; Xs = [1,2,1] % (redundant)
; Xs = [2,1,1]
; Xs = [2,1,1] % (redundant)
; false.
Not quite! Can we get rid of above redundant answers? Yes, simply use selectd/3!
comb(As,Bs) :-
same_length(As,Full),
Bs = [_|_],
prefix(Bs,Full),
foldl(selectd,Bs,As,_).
So let's re-run above query again with the improved implementation of comb/2!
?- comb([1,1,2],Xs).
Xs = [1]
; Xs = [2]
; Xs = [1,1]
; Xs = [1,2]
; Xs = [2,1]
; Xs = [1,1,2]
; Xs = [1,2,1]
; Xs = [2,1,1]
; false.
there is a predefined predicate called permutation ...
1 ?- permutation([1,2,3],L).
L = [1, 2, 3] ;
L = [2, 1, 3] ;
L = [2, 3, 1] ;
L = [1, 3, 2] ;
L = [3, 1, 2] ;
L = [3, 2, 1] .
2 ?- listing(permutation).
lists:permutation([], [], []).
lists:permutation([C|A], D, [_|B]) :-
permutation(A, E, B),
select(C, D, E).
lists:permutation(A, B) :-
permutation(A, B, B).
true.
hope this helps ..
Hint: This is easy to do if you have written a predicate inselt(X,Y,Z), which holds if any insertion of Y into X gives Z:
inselt([E|X], Y, [E|Z]) :- inselt(X,Y,Z).
inselt(X, Y, [Y|X]).
Then comb/3 can be coded recursively using inselt/3.