Prolog: DRY way of creating lists declaratively - prolog

I'm doing some experiments with Prolog and having difficulties with the following rule:
row(Row, Matrix, [R1,R2,R3,R4]) :-
cell(1, Row, Matrix, R1),
cell(2, Row, Matrix, R2),
cell(3, Row, Matrix, R3),
cell(4, Row, Matrix, R4).
This rule extracts one row from a matrix, given its row number. For example,
row(2, [1,2,3,4,5,6,7,8], X)
X = [5,6,7,8]
What nags me is that there is lots of repetition in that code. After finishing with 4x4 matrices, I will have to deal with 9x9 ones. And the code can get very non DRY.
Is there a way to extract that repetition out?
Thanks.
Edit: The complete code giving me trouble is here: https://github.com/kikito/7-languages-in-7-weeks/blob/master/3-prolog/day-3/sudoku-refactor.pl

After writing my first answer, I realized that you can also simplify your program using findall
row(Row, Matrix, L) :- findall(X,cell(_,Row,Matrix,X),L).

I would think about changing the representation to a list of lists rather than a flat list, then selecting a row becomes very easy. You can just use the built-in nth1/3:
:- use_module(library(lists)). % I use Sicstus Prolog
row(N,M,X) :- nth1(N,M,X).
cell(R,C,M,X) :- nth1(R,M,Y), nth1(C,Y,X).
column(N,M,X) :- findall(Y,(nth1(_,M,Z), nth1(N,Z,Y)),X).
m([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]]).
example(Row,Cell,Column) :- m(M), row(2,M,Row), cell(2,3,M,Cell), column(2,M,Column).
%| ?- example(A,B,C).
%A = [5,6,7,8],
%B = 7,
%C = [2,6,10,14] ? ;
%no

Related

Prolog - Using Bagof

I've been stuck on a past paper question while studying for my exams.
The question is:
https://gyazo.com/ee2fcd88d67068e8cf7d478a98f486a0
I figured I've got to use findall/bagof/setof because I need to collect a set of solutions. Furthermore, setof seems appropriate because the list needs to be presented in descending order.
My solution so far is:
teams(List) :-
setof((Team, A),
(Team^team(Team, _, Wins, Draws, _), A is Wins*3 + Draws*1),
List).
However the problem is I don't quite get the answers all in one list. I'm very likely using Team^ incorrectly. I'd really appreciate pointers on how I can get a list of ordered tuples in terms of points. The output it gives me is:
X = [(queenspark,43)] ? ;
X = [(stirling,26)] ? ;
X = [(clyde,25)] ? ;
X = [(peterhead,35)] ? ;
X = [(rangers,63)] ? ;
Also, it's not really apparent what kind of order, if any it's in, so I'm also lost as to how setof is ordering.
Whats the best way to approach this question using setof?
Thanks.
Firstly, I would suggest to change (Team,A) to a pair representation A-Team with the A being in front since this is the total score of the team and thus the key you want to use for sorting. Then you would like to prefix the variables that should not be in the list with a ^ in front of the query you want to aggregate. See the following example:
?- setof(A-Team, P^Wins^Draws^L^(team(Team, P, Wins, Draws, L), A is Wins*3 + Draws*1), List).
List = [25-clyde,26-stirling,35-peterhead,43-queenspark,63-rangers]
Since you asked, consider the following query with the pair ordering flipped to Team-A for comparison reasons:
?- setof(Team-A,P^Wins^Draws^L^(team(Team,P,Wins,Draws,L), A is Wins*3 + Draws*1),List).
List = [clyde-25,peterhead-35,queenspark-43,rangers-63,stirling-26]
Now the resulting list is sorted with respect to the teamnames. So A-Team is the opportune choice. You could then use the predicate lists:reverse/2 to reverse the order to a descending list and then define an auxilary predicate pair_second/2 that you can use with apply:maplist/3 to get rid of the leading scores in the pairs:
:- use_module(library(lists)).
:- use_module(library(apply)).
% team(+Name, +Played, +Won, +Drawn, +Lost)
team(clyde,26,7,4,15).
team(peterhead,26,9,8,9).
team(queenspark,24,12,7,5).
team(rangers,26,19,6,1).
team(stirling,25,7,5,13).
pair_second(A-B,B). % 2nd argument is 2nd element of pair
teams(Results) :-
setof(A-Team,
P^Wins^Draws^L^(team(Team, P, Wins, Draws, L), A is Wins*3 + Draws*1),
List),
reverse(List,RList),
maplist(pair_second,RList,Results). % apply pair_second/2 to RList
If you query the predicate now you get the desired results:
?- teams(T).
T = [rangers,queenspark,peterhead,stirling,clyde]
Concerning your question in the comments: Yes, of course that is possible. You can write a predicate that describes a relation between a list of pairs and a list than only consists of the second element of the pairs. Let's call it pairlist_namelist/2:
pairlist_namelist([],[]).
pairlist_namelist([S-N|SNs],[N|Ns]) :-
pairlist_namelist(SNs,Ns).
Then you can define teams/1 like so:
teams(Results) :-
setof(A-Team,
P^Wins^Draws^L^(team(Team, P, Wins, Draws, L), A is Wins*3 + Draws*1),
List),
reverse(List,RList),
pairlist_namelist(RList,Results).
In this case, besides maplist/3, you don't need pair_second/2 either. Also you don't need to include :- use_module(library(apply)). The example query above yields the same result with this version.

Prolog Using findall/3 on a Matrix

I have the following matrix in my SWI prolog;
matrix(1,[ [*,*,*,*,*,*,*,*,*,*,*,*],
[*,*,*,spots(2,4),spots(2,5),*,*,*,*,spots(2,10),spots(2,11),*],
[*,*,*,spots(3,4),spots(3,5),spots(3,6),spots(3,7),*,*,spots(3,10),spots(3,11),*],
[*,*,spots(4,3),spots(4,4),*,spots(4,6),spots(4,7),spots(4,8),spots(4,9),*,spots(4,11),spots(4,12)],
[*,spots(5,2),spots(5,3),spots(5,4),spots(5,5),*,*,spots(5,8),spots(5,9),*,spots(5,11),spots(5,12)],
[*,spots(6,2),spots(6,3),*,spots(6,5),spots(6,6),spots(6,7),spots(6,8),*,spots(6,10),spots(6,11),spots(6,12)],
[*,*,spots(7,3),spots(7,4),*,spots(7,6),spots(7,7),spots(7,8),*,spots(7,10),spots(7,11),*],
[*,spots(8,2),spots(8,3),spots(8,4),*,spots(8,6),spots(8,7),spots(8,8),spots(8,9),*,spots(8,11),spots(8,12)],
[*,spots(9,2),spots(9,3),*,spots(9,5),spots(9,6),*,*,spots(9,9),spots(9,10),spots(9,11),spots(9,12)],
[*,spots(10,2),spots(10,3),*,spots(10,5),spots(10,6),spots(10,7),spots(10,8),*,spots(10,10),spots(10,11),*]
[*,*,spots(11,3),spots(11,4),*,*,spots(11,7),spots(11,8),spots(11,9),spots(11,10),*,*],
[*,*,spots(12,3),spots(12,4),*,*,*,*,spots(12,9),spots(12,10),*,*]]).
I want to use a findall/3 predicate so that I can get a list of all the spot(X,Y) facts like >>>
findall(spots(X,Y),matrix(1,Map),X).
Which should return something like the following;
X = (spots(2,4), spots(2,5), spots(2,10), spots(2,11), spots(3,4) etc .... spots(12,10)).
However, I'm very confused in how to implement this, due to the matrix being composed of a list within a list. Would appreciate if someone could show me a configured predicate in order to achieve a list like stated.
Thanks for any help!!! - really appreciate it!
Edit - may be able to use this code found below and unable to see how I could implement this into a second findall/3 statement. Really stuck so appreciate any help on this.
at(Mat, Row, Col, Val) :- nth1(Row, Mat, ARow), nth1(Col, ARow, Val).
Just think what your predicate should describe: You want to find all terms of the form spots(_,_) in a list of lists that otherwise consists of atoms *.
:- use_module(library(lists)).
matrix_spots([],[]). % no spots in the empty matrix
matrix_spots([R|Rs],S) :-
row_spots(R,RSs), % RSs ... spots in row R
matrix_spots(Rs,S1), % S1 ... spots in the remaining rows
append(RSs,S1,S). % S ... RSs followed by S1
row_spots([],[]). % no spots in an empty row
row_spots([E|Es],[E|RSs]) :- % E is in the list of spots
E=spots(_,_), % if it is a spot
row_spots(Es,RSs). % RSs ... spots in rest of row
row_spots([*|Es],RSs) :- % * is not in the list of spots
row_spots(Es,RSs). % Rss ... spots in rest of row
Now you can query your matrix for all its spots:
?- matrix(1,M), matrix_spots(M,S).
M = [[*,*,*,*,*,*,*,*,*,*,*,*],[*,*,*,spots(2,4),spots(2,5),*,*,*,*,spots(2,10),spots(2,11),*],[*,*,*,spots(3,4),spots(3,5),spots(3,6),spots(3,7),*,*,spots(3,10),spots(3,11),*],[*,*,spots(4,3),spots(4,4),*,spots(4,6),spots(4,7),spots(4,8),spots(4,9),*,spots(4,11),spots(4,12)],[*,spots(5,2),spots(5,3),spots(5,4),spots(5,5),*,*,spots(5,8),spots(5,9),*,spots(5,11),spots(5,12)],[*,spots(6,2),spots(6,3),*,spots(6,5),spots(6,6),spots(6,7),spots(6,8),*,spots(6,10),spots(6,11),spots(6,12)],[*,*,spots(7,3),spots(7,4),*,spots(7,6),spots(7,7),spots(7,8),*,spots(7,10),spots(7,11),*],[*,spots(8,2),spots(8,3),spots(8,4),*,spots(8,6),spots(8,7),spots(8,8),spots(8,9),*,spots(8,11),spots(8,12)],[*,spots(9,2),spots(9,3),*,spots(9,5),spots(9,6),*,*,spots(9,9),spots(9,10),spots(9,11),spots(9,12)],[*,spots(10,2),spots(10,3),*,spots(10,5),spots(10,6),spots(10,7),spots(10,8),*,spots(10,10),spots(10,11),*],[*,*,spots(11,3),spots(11,4),*,*,spots(11,7),spots(11,8),spots(11,9),spots(11,10),*,*],[*,*,spots(12,3),spots(12,4),*,*,*,*,spots(12,9),spots(12,10),*,*]],
S = [spots(2,4),spots(2,5),spots(2,10),spots(2,11),spots(3,4),spots(3,5),spots(3,6),spots(3,7),spots(3,10),spots(3,11),spots(4,3),spots(4,4),spots(4,6),spots(4,7),spots(4,8),spots(4,9),spots(4,11),spots(4,12),spots(5,2),spots(5,3),spots(5,4),spots(5,5),spots(5,8),spots(5,9),spots(5,11),spots(5,12),spots(6,2),spots(6,3),spots(6,5),spots(6,6),spots(6,7),spots(6,8),spots(6,10),spots(6,11),spots(6,12),spots(7,3),spots(7,4),spots(7,6),spots(7,7),spots(7,8),spots(7,10),spots(7,11),spots(8,2),spots(8,3),spots(8,4),spots(8,6),spots(8,7),spots(8,8),spots(8,9),spots(8,11),spots(8,12),spots(9,2),spots(9,3),spots(9,5),spots(9,6),spots(9,9),spots(9,10),spots(9,11),spots(9,12),spots(10,2),spots(10,3),spots(10,5),spots(10,6),spots(10,7),spots(10,8),spots(10,10),spots(10,11),spots(11,3),spots(11,4),spots(11,7),spots(11,8),spots(11,9),spots(1ts(12,4),spots(12,9),spots(12,10)] ? ;
no
Note that you have a typo in your example matrix: at the end of the 10th list the comma is missing: ...spots(10,11),*],
Edit:
Here is a dcg version as suggested by #mat in the comments. It is indeed much easier readable:
matrix_spots(M,S) :-
phrase(rows(M),S).
rows([]) --> % no spots in the empty matrix
[].
rows([R|Rs]) -->
row(R), % all spots in row R
rows(Rs). % all spots in the remaining rows
row([]) --> % no spots in an empty row
[].
row([*|Xs]) --> % no spot at this position in the row
row(Xs). % but there might be in the remainder
row([spots(A,B)|Xs]) --> % spot at this position
[spots(A,B)], % is in the list
row(Xs). % and the spots in the rest of the row
The query above can be used one-to-one with this dcg-version.
Concerning your (#User15388472) findall/3 question in the comments: Imagine you had a predicate matrix_spot/2 that is matching one term of the form spots(A,B) as second argument instead of a list of all spots. That predicate could look something like that:
matrix_spot([R|Rs],S) :-
row_spot(R,S). % S is in row R
matrix_spot([R|Rs],S) :- % S is not in R but
matrix_spot(Rs,S). % in one of the other rows Rs
row_spot([spots(A,B)|Xs],spots(A,B)). % head of the list is the spot
row_spot([X|Xs],S) :-
row_spot(Xs,S). % S is in the tail of the list
If you query this predicate you get one spots(A,B) at a time as an answer:
?- matrix(1,M), matrix_spot(M,S).
M = [[*,*,*,*,*,*,*,*,*,*,*,*],[*,*,*,spots(2,4),spots(2,5),*,*,*,*,spots(2,10),spots(2,11),*],[*,*,*,spots(3,4),spots(3,5),spots(3,6),spots(3,7),*,*,spots(3,10),spots(3,11),*],[*,*,spots(4,3),spots(4,4),*,spots(4,6),spots(4,7),spots(4,8),spots(4,9),*,spots(4,11),spots(4,12)],[*,spots(5,2),spots(5,3),spots(5,4),spots(5,5),*,*,spots(5,8),spots(5,9),*,spots(5,11),spots(5,12)],[*,spots(6,2),spots(6,3),*,spots(6,5),spots(6,6),spots(6,7),spots(6,8),*,spots(6,10),spots(6,11),spots(6,12)],[*,*,spots(7,3),spots(7,4),*,spots(7,6),spots(7,7),spots(7,8),*,spots(7,10),spots(7,11),*],[*,spots(8,2),spots(8,3),spots(8,4),*,spots(8,6),spots(8,7),spots(8,8),spots(8,9),*,spots(8,11),spots(8,12)],[*,spots(9,2),spots(9,3),*,spots(9,5),spots(9,6),*,*,spots(9,9),spots(9,10),spots(9,11),spots(9,12)],[*,spots(10,2),spots(10,3),*,spots(10,5),spots(10,6),spots(10,7),spots(10,8),*,spots(10,10),spots(10,11),*],[*,*,spots(11,3),spots(11,4),*,*,spots(11,7),spots(11,8),spots(11,9),spots(11,10),*,*],[*,*,spots(12,3),spots(12,4),*,*,*,*,spots(12,9),spots(12,10),*,*]],
S = spots(2,4) ? ;
M = [[*,*,*,*,*,*,*,*,*,*,*,*],[*,*,*,spots(2,4),spots(2,5),*,*,*,*,spots(2,10),spots(2,11),*],[*,*,*,spots(3,4),spots(3,5),spots(3,6),spots(3,7),*,*,spots(3,10),spots(3,11),*],[*,*,spots(4,3),spots(4,4),*,spots(4,6),spots(4,7),spots(4,8),spots(4,9),*,spots(4,11),spots(4,12)],[*,spots(5,2),spots(5,3),spots(5,4),spots(5,5),*,*,spots(5,8),spots(5,9),*,spots(5,11),spots(5,12)],[*,spots(6,2),spots(6,3),*,spots(6,5),spots(6,6),spots(6,7),spots(6,8),*,spots(6,10),spots(6,11),spots(6,12)],[*,*,spots(7,3),spots(7,4),*,spots(7,6),spots(7,7),spots(7,8),*,spots(7,10),spots(7,11),*],[*,spots(8,2),spots(8,3),spots(8,4),*,spots(8,6),spots(8,7),spots(8,8),spots(8,9),*,spots(8,11),spots(8,12)],[*,spots(9,2),spots(9,3),*,spots(9,5),spots(9,6),*,*,spots(9,9),spots(9,10),spots(9,11),spots(9,12)],[*,spots(10,2),spots(10,3),*,spots(10,5),spots(10,6),spots(10,7),spots(10,8),*,spots(10,10),spots(10,11),*],[*,*,spots(11,3),spots(11,4),*,*,spots(11,7),spots(11,8),spots(11,9),spots(11,10),*,*],[*,*,spots(12,3),spots(12,4),*,*,*,*,spots(12,9),spots(12,10),*,*]],
S = spots(2,5) ? ;
...
In a scenario like this you can use findall/3 to find all terms spots(A,B) in the matrix:
?- matrix(1,M), findall(S,matrix_spot(M,S),Spots).
M = [[*,*,*,*,*,*,*,*,*,*,*,*],[*,*,*,spots(2,4),spots(2,5),*,*,*,*,spots(2,10),spots(2,11),*],[*,*,*,spots(3,4),spots(3,5),spots(3,6),spots(3,7),*,*,spots(3,10),spots(3,11),*],[*,*,spots(4,3),spots(4,4),*,spots(4,6),spots(4,7),spots(4,8),spots(4,9),*,spots(4,11),spots(4,12)],[*,spots(5,2),spots(5,3),spots(5,4),spots(5,5),*,*,spots(5,8),spots(5,9),*,spots(5,11),spots(5,12)],[*,spots(6,2),spots(6,3),*,spots(6,5),spots(6,6),spots(6,7),spots(6,8),*,spots(6,10),spots(6,11),spots(6,12)],[*,*,spots(7,3),spots(7,4),*,spots(7,6),spots(7,7),spots(7,8),*,spots(7,10),spots(7,11),*],[*,spots(8,2),spots(8,3),spots(8,4),*,spots(8,6),spots(8,7),spots(8,8),spots(8,9),*,spots(8,11),spots(8,12)],[*,spots(9,2),spots(9,3),*,spots(9,5),spots(9,6),*,*,spots(9,9),spots(9,10),spots(9,11),spots(9,12)],[*,spots(10,2),spots(10,3),*,spots(10,5),spots(10,6),spots(10,7),spots(10,8),*,spots(10,10),spots(10,11),*],[*,*,spots(11,3),spots(11,4),*,*,spots(11,7),spots(11,8),spots(11,9),spots(11,10),*,*],[*,*,spots(12,3),spots(12,4),*,*,*,*,spots(12,9),spots(12,10),*,*]],
Spots = [spots(2,4),spots(2,5),spots(2,10),spots(2,11),spots(3,4),spots(3,5),spots(3,6),spots(3,7),spots(3,10),spots(3,11),spots(4,3),spots(4,4),spots(4,6),spots(4,7),spots(4,8),spots(4,9),spots(4,11),spots(4,12),spots(5,2),spots(5,3),spots(5,4),spots(5,5),spots(5,8),spots(5,9),spots(5,11),spots(5,12),spots(6,2),spots(6,3),spots(6,5),spots(6,6),spots(6,7),spots(6,8),spots(6,10),spots(6,11),spots(6,12),spots(7,3),spots(7,4),spots(7,6),spots(7,7),spots(7,8),spots(7,10),spots(7,11),spots(8,2),spots(8,3),spots(8,4),spots(8,6),spots(8,7),spots(8,8),spots(8,9),spots(8,11),spots(8,12),spots(9,2),spots(9,3),spots(9,5),spots(9,6),spots(9,9),spots(9,10),spots(9,11),spots(9,12),spots(10,2),spots(10,3),spots(10,5),spots(10,6),spots(10,7),spots(10,8),spots(10,10),spots(10,11),spots(11,3),spots(11,4),spots(11,7),spots(11,8),spots(11,9),spots(11,10),spots(12,3),spots(12,4),spots(12,9),spots(12,10)]

How can i change size of sudoku

I have a script to solve a Sudoku with size= 9*9
i have 81 variables and i define the rules for them,
How can change this code to solve a sudoku with any size?
for example for a sudoku 16*16, the rules will be for subsquares 4*4.
go(L) :-
L=[A1,A2,A3,A4,A5,A6,A7,A8,A9,
B1,B2,B3,B4,B5,B6,B7,B8,B9,
C1,C2,C3,C4,C5,C6,C7,C8,C9,
D1,D2,D3,D4,D5,D6,D7,D8,D9,
E1,E2,E3,E4,E5,E6,E7,E8,E9,
F1,F2,F3,F4,F5,F6,F7,F8,F9,
G1,G2,G3,G4,G5,G6,G7,G8,G9,
H1,H2,H3,H4,H5,H6,H7,H8,H9,
I1,I2,I3,I4,I5,I6,I7,I8,I9],
fd_domain(L,1,9),
fd_alldifferent([A1,A2,A3,A4,A5,A6,A7,A8,A9]),
fd_alldifferent([B1,B2,B3,B4,B5,B6,B7,B8,B9]),
fd_alldifferent([C1,C2,C3,C4,C5,C6,C7,C8,C9]),
fd_alldifferent([D1,D2,D3,D4,D5,D6,D7,D8,D9]),
fd_alldifferent([E1,E2,E3,E4,E5,E6,E7,E8,E9]),
fd_alldifferent([F1,F2,F3,F4,F5,F6,F7,F8,F9]),
fd_alldifferent([G1,G2,G3,G4,G5,G6,G7,G8,G9]),
fd_alldifferent([H1,H2,H3,H4,H5,H6,H7,H8,H9]),
fd_alldifferent([I1,I2,I3,I4,I5,I6,I7,I8,I9]),
fd_alldifferent([A1,B1,C1,D1,E1,F1,G1,H1,I1]),
fd_alldifferent([A2,B2,C2,D2,E2,F2,G2,H2,I2]),
fd_alldifferent([A3,B3,C3,D3,E3,F3,G3,H3,I3]),
fd_alldifferent([A4,B4,C4,D4,E4,F4,G4,H4,I4]),
fd_alldifferent([A5,B5,C5,D5,E5,F5,G5,H5,I5]),
fd_alldifferent([A6,B6,C6,D6,E6,F6,G6,H6,I6]),
fd_alldifferent([A7,B7,C7,D7,E7,F7,G7,H7,I7]),
fd_alldifferent([A8,B8,C8,D8,E8,F8,G8,H8,I8]),
fd_alldifferent([A9,B9,C9,D9,E9,F9,G9,H9,I9]),
fd_alldifferent([A1,A2,A3,B1,B2,B3,C1,C2,C3]),
fd_alldifferent([A4,A5,A6,B4,B5,B6,C4,C5,C6]),
fd_alldifferent([A7,A8,A9,B7,B8,B9,C7,C8,C9]),
fd_alldifferent([D1,D2,D3,E1,E2,E3,F1,F2,F3]),
fd_alldifferent([D4,D5,D6,E4,E5,E6,D4,D5,D6]),
fd_alldifferent([D7,D8,D9,E7,E8,E9,D7,D8,D9]),
fd_alldifferent([G1,G2,G3,H1,H2,H3,I1,I2,I3]),
fd_alldifferent([G4,G5,G6,H4,H5,H6,I4,I5,I6]),
fd_alldifferent([G7,G8,G9,H7,H8,H9,I7,I8,I9]),
fd_labeling([A1,A2,A3,A4,A5,A6,A7,A8,A9,
B1,B2,B3,B4,B5,B6,B7,B8,B9,
C1,C2,C3,C4,C5,C6,C7,C8,C9,
D1,D2,D3,D4,D5,D6,D7,D8,D9,
E1,E2,E3,E4,E5,E6,E7,E8,E9,
F1,F2,F3,F4,F5,F6,F7,F8,F9,
G1,G2,G3,G4,G5,G6,G7,G8,G9,
H1,H2,H3,H4,H5,H6,H7,H8,H9,
I1,I2,I3,I4,I5,I6,I7,I8,I9]).
should i write another script or just i can change this one?
Thanks,
The code will need a rewrite to work for a general case. It is currently completely hard-coded for all the dimensions, so it can't be just tweaked to generalize it.
Here is an example to show you how you can use maplist as a tool for a problem like this. It is not a complete solution to your problem, but should get you started.
% Auxiliary predicates that will be maplist-friendly (the list is the last argument)
%
length_(N, L) :- length(L, N).
fd_domain_(Min, Max, L) :- fd_domain(L, Min, Max).
constrained_matrix(N, Matrix) :-
length(Matrix, N), % Matrix has N elements
maplist(length_(N), Matrix), % Each element of Matrix has N elements
maplist(fd_domain_(1, N), Matrix), % The domain of each sublist is 1 to N
maplist(fd_all_different, Matrix), % Each sublist must have elements all different
maplist(fd_labeling, Matrix).
And run a query like this:
| ?- constrained_matrix(3, L).
L = [[1,2,3],[1,2,3],[1,2,3]] ? ;
L = [[1,2,3],[1,2,3],[1,3,2]] ? ;
L = [[1,2,3],[1,2,3],[2,1,3]] ? ;
L = [[1,2,3],[1,2,3],[2,3,1]] ? ;
...
As you can see, the solution set is all 3x3 matrices which have rows with unique elements, but columns can be anything. You can add more constraints by writing/using Prolog predicates that can transpose a matrix (interchange rows versus columns in Matrix) and use maplist again to constrain the columns. You can add even more constraints for subsquares as needed (write a predicate to extract a submatrix, for example, and make good use of maplist).

transpose a matrix in prolog

I'm fairly new to Prologue and one of my first assignments in the class is to transpose a matrix in Prolog, meaning: If I have a matrix
A=[[1,2,3],[4,5,6],[7,8,9]]
I should get another matrix
S=[[1,4,7],[2,5,8],[3,6,9]].
I've written the code for it, however in the result I'm getting something like:
S=[[1,4,7],[2,5,8],[3,6,9], []].
(There is an empty list at the end of it).
How do I correct something like that? Is my code completely wrong? I'm not supposed to use any non-standard tools (such as SWI-Prolog)
trans([],[]).
trans([S|R], [L|L1]) :-
trans(S, R, L, M),
trans(M, L1).
trans([], _,[],[]).
trans([S1|S2], [], [S1|L1], [S2|M]):-
trans([], [], L1, M).
trans([S1|S2], [R1|R2], [S1|L1], [S2|M]):-
trans(R1, R2, L1, M).
I've also seen and used the code provided here: How to transpose a matrix in prolog , however I wanted to try and write it myself.
One simple solution is to add another rule for predicate trans/2 to match that specific situation that in your case adds the empty list at the end.
trans([],[]).
trans([[]|_], []):-!.
trans([S|R], [L|L1]) :-
trans(S, R, L, M),
trans(M, L1).

Prolog issue with max list function: nondeterm vs procedure

I am trying to do a small project in prolog where a user can input a list and then it calculates the average, max in the list etc. etc.
So far so good, but I ran into a problem when writing the max function (finds max number in the list). The code is:
maxN([X],X):-!.
maxN([X|L],X) :- maxN(L,M), X > M.
maxN([X|L],M) :- maxN(L,M), M >= X.
The function itself works separately, but I get this error message:
The predicate 'forma::maxN/2 (i,o)', which is declared as 'procedure', is actually 'nondeterm' forma.pro
This is my predicate in the *.cl definition:
maxN: (integer* Z, integer U) procedure (i,o).
I cannot declare it as nondeterm because it causes issues with my whole form. Can you help me/give a hint how to make it a procedure? I am thinking I have to make a cut somewhere but my attempts have failed so far.
P.S. I am using Visual Prolog 7.4.
Edit: After trying the alternatives proposed to make the two rules into one or with an accumulator, I now get that the predicate is 'determ' instead of a procedure. According to my Prolog guide that means that the predicate doesn't have multiple solutions now, but instead has a chance to fail. Basically all code variations I've done up to now lead me to a 'determ'.
The problem is that Prolog sees a choice point between your second and third rules. In other words, you, the human, know that both X > M and M >= X cannot both be true, but Prolog is not able to infer that.
IMO the best thing to do would be to rephrase those two rules with one rule:
maxN([X], X) :- !.
maxN([X|L], Max) :-
maxN(L, M),
X > M -> Max = X
; Max = M.
This way there isn't ever an extra choice point that would need to be pruned with a cut.
Following #CapelliC's advice, you could also reformulate this with an accumulator:
maxN([X|Xs], Max) :- maxN_loop(Xs, X, Max).
maxN_loop([], Max, Max).
maxN_loop([X|Xs], Y, Max) :-
X > Y -> maxN_loop(Xs, X, Max)
; maxN_loop(Xs, Y, Max).
sorry, I don't know the Prolog dialect you're using, my advice is to try to add a cut after the second clause:
maxN([X|L],X) :- maxN(L,M), X > M, !.
Generally, I think a recursive procedure can be made deterministic transforming it to tail recursive. Unfortunately, this requires to add an accumulator:
maxN([],A,A).
maxN([X|L],A,M) :- X > A, !, maxN(L,X,M).
maxN([X|L],A,M) :- maxN(L,A,M).
Of course, top level call should become
maxN([F|L],M) :- maxN(L,F,M).

Resources