How can i change size of sudoku - prolog

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).

Related

Find the minimum in a mixed list in Prolog

I am new to prolog, I am just learning about lists and I came across this question. The answer works perfect for a list of integers.
minimo([X], X) :- !.
minimo([X,Y|Tail], N):-
( X > Y ->
minimo([Y|Tail], N)
;
minimo([X|Tail], N)
).
How can I change this code to get the smallest int from a mixed list?
This
sint([a,b,3,2,1],S)
should give an answer:
S=1
you could just ignore the problem, changing the comparison operator (>)/2 (a binary builtin predicate, actually) to the more general (#>)/2:
minimo([X], X) :- !.
minimo([X,Y|Tail], N):-
( X #> Y ->
minimo([Y|Tail], N)
;
minimo([X|Tail], N)
).
?- minimo([a,b,3,2,1],S).
S = 1.
First of all, I don't think the proposed implementation is very elegant: here they pass the minimum found element thus far by constructing a new list each time. Using an additional parameter (we call an accumulator) is usually the way to go (and is probably more efficient as well).
In order to solve the problem, we first have to find an integer. We can do this like:
sint([H|T],R) :-
integer(H),
!,
sint(T,H,R).
sint([_|T],R) :-
sint(T,R).
So here we check if the head H is an integer/1. If that is the case, we call a predicate sint/3 (not to be confused with sint/2). Otherwise we call recursively sint/2 with the tail T of the list.
Now we still need to define sint/3. In case we have reached the end of the list [], we simply return the minum found thus far:
sint([],R,R).
Otherwise there are two cases:
the head H is an integer and smaller than the element found thus far, in that case we perform recursion with the head as new current minimum:
sint([H|T],M,R):
integer(H),
H < M,
!,
sint(T,H,R).
otherwise, we simply ignore the head, and perform recursion with the tail T.
sint([_|T],M,R) :-
sint(T,M,R).
We can put the recursive clauses in an if-then-else structure. Together with the earlier defined predicate, the full program then is:
sint([H|T],R) :-
integer(H),
!,
sint(T,H,R).
sint([_|T],R) :-
sint(T,R).
sint([],R,R).
sint([H|T],M,R):
(
(integer(H),H < M)
-> sint(T,H,R)
; sint(T,M,R)
).
The advantage of this approach is that filtering and comparing (to obtain the minimum) is done at the same time, so we only iterate once over the list. This will usually result in a performance boost since the "control structures" are only executed once: more is done in an iteration, but we only iterate once.
We can generalize the approach by making the filter generic:
filter_minimum(Filter,[H|T],R) :-
Goal =.. [Filter,H],
call(Goal),
!,
filter_minimum(Filter,T,H,R).
filter_minimum(Filter,[_|T],R) :-
filter_minimum(Filter,T,R).
filter_minimum(_,[],R,R).
filter_minimum(Filter,[H|T],M,R) :-
Goal =.. [Filter,H],
(
(call(Goal),H < M)
-> filter_minimum(Filter,T,H,R)
; filter_minimum(Filter,T,M,R)
).
You can then call it with:
filter_minimum(integer,[a,b,3,2,1],R).
to filter with integer/1 and calculate the minimum.
You could just write a predicate that returns a list with the numbers and the use the above minimo/2 predicate:
only_numbers([],[]).
only_numbers([H|T],[H|T1]):-integer(H),only_numbers(T,T1).
only_numbers([H|T],L):- \+integer(H),only_numbers(T,L).
sint(L,S):-only_numbers(L,L1),minimo(L1,S).

Prolog: Exam schedule generator - How to avoid permutations in solutions

I'm building an exam scheduler in Prolog.
The scheduler is based on this example:
https://metacpan.org/source/DOUGW/AI-Prolog-0.741/examples/schedule.pl
How can I make sure there are no permutations in my solution?
For example solution
-> ((exam1, teacher1, time1, room1), (exam2, teacher2, time2, room2))
Later solution:
-> ((exam2, teacher2, time2, room2),(exam1, teacher1, time1, room1))
How can I avoid this?
Thanks!
1) The closest/easiest from what you've got is to check that the course you've chosen is strictly bigger in order than the previous one.
For example by adding an extra predicate which also includes the previous course in the combination.
%%makeListPrev(PreviousTakenCourse, ResultCombinationOfCourses, NrOfCoursesToAdd)
makeListPrev(_,[], 0).
makeListPrev(course(Tprev,Ttime,Troom),[course(Teacher,Time,Room)|Rest], N) :-
N > 0,
teacher(Teacher),
classtime(Time),
classroom(Room),
course(Tprev,Ttime,Troom) #< course(Teacher,Time,Room), %% enforce unique combinations
is(M,minus(N,1)),
makeListPrev(course(Teacher,Time,Room),Rest,M).
In this way you eliminate all duplicate permutations of the same combination by always taking the lexographically smallest.
E.g if you have 4 courses:
(a,b,c,d)
(a,b,d,c) % d can't be before c
(a,c,b,d) % c can't be before b
...
2) Another way to solve this quite easily is to first create a list of all possible courses. And then take out all possible combinations of N sequentially.
scheduler(L) :-
%% Find all possible courses
findall(course(Teacher,Time,Room),(teacher(Teacher),classtime(Time),classroom(Room)),Courses),
makeList(Courses,4,L),
different(L).
makeList([],0,[]) :- !. %% list completed
makeList([H|T],N,[H|Res]) :- %% list including H
M is N-1,
makeList(T,M,Res).
makeList([_|T], N, Res) :- makeList(T, N, Res). %% list without H

Prolog - sequence in list

We want to build a predicate that gets a list L and a number N and is true if N is the length of the longest sequence of list L.
For example:
?- ls([1,2,2,4,4,4,2,3,2],3).
true.
?- ls([1,2,3,2,3,2,1,7,8],3).
false.
For this I built -
head([X|S],X). % head of the list
ls([H|T],N) :- head(T,X),H=X, NN is N-1 , ls(T,NN) . % if the head equal to his following
ls(_,0) :- !. % get seq in length N
ls([H|T],N) :- head(T,X) , not(H=X) ,ls(T,N). % if the head doesn't equal to his following
The concept is simply - check if the head equal to his following , if so , continue with the tail and decrement the N .
I checked my code and it works well (ignore cases which N = 1) -
ls([1,2,2,4,4,4,2,3,2],3).
true ;
false .
But the true answer isn't finite and there is more answer after that , how could I make it to return finite answer ?
Prolog-wise, you have a few problems. One is that your predicate only works when both arguments are instantiated, which is disappointing to Prolog. Another is your style—head/2 doesn't really add anything over [H|T]. I also think this algorithm is fundamentally flawed. I don't think you can be sure that no sequence of longer length exists in the tail of the list without retaining an unchanged copy of the guessed length. In other words, the second thing #Zakum points out, I don't think there will be a simple solution for it.
This is how I would have approached the problem. First a helper predicate for getting the maximum of two values:
max(X, Y, X) :- X >= Y.
max(X, Y, Y) :- Y > X.
Now most of the work sequence_length/2 does is delegated to a loop, except for the base case of the empty list:
sequence_length([], 0).
sequence_length([X|Xs], Length) :-
once(sequence_length_loop(X, Xs, 1, Length)).
The call to once/1 ensures we only get one answer. This will prevent the predicate from usefully generating lists with sequences while also making the predicate deterministic, which is something you desired. (It has the same effect as a nicely placed cut).
Loop's base case: copy the accumulator to the output parameter:
sequence_length_loop(_, [], Length, Length).
Inductive case #1: we have another copy of the same value. Increment the accumulator and recur.
sequence_length_loop(X, [X|Xs], Acc, Length) :-
succ(Acc, Acc1),
sequence_length_loop(X, Xs, Acc1, Length).
Inductive case #2: we have a different value. Calculate the sequence length of the remainder of the list; if it is larger than our accumulator, use that; otherwise, use the accumulator.
sequence_length_loop(X, [Y|Xs], Acc, Length) :-
X \= Y,
sequence_length([Y|Xs], LengthRemaining),
max(Acc, LengthRemaining, Length).
This is how I would approach this problem. I don't know if it will be useful for you or not, but I hope you can glean something from it.
How about adding a break to the last rule?
head([X|S],X). % head of the list
ls([H|T],N) :- head(T,X),H=X, NN is N-1 , ls(T,NN) . % if the head equal to his following
ls(_,0) :- !. % get seq in length N
ls([H|T],N) :- head(T,X) , not(H=X) ,ls(T,N),!. % if the head doesn't equal to his following
Works for me, though I'm no Prolog expert.
//EDIT: btw. try
14 ?- ls([1,2,2,4,4,4,2,3,2],2).
true ;
false.
Looks false to me, there is no check whether N is the longest sequence. Or did I get the requirements wrong?
Your code is checking if there is in list at least a sequence of elements of specified length. You need more arguments to keep the state of the search while visiting the list:
ls([E|Es], L) :- ls(E, 1, Es, L).
ls(X, N, [Y|Ys], L) :-
( X = Y
-> M is N+1,
ls(X, M, Ys, L)
; ls(Y, 1, Ys, M),
( M > N -> L = M ; L = N )
).
ls(_, N, [], N).

Prolog: DRY way of creating lists declaratively

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

Prolog Question - How to generate sublists of a given length

I want to generate all the sublists of a given list with the given property that they have a certain length mentioned as argument and also they have as a containing element a given element which is passed as a parameter. I have managed to do this but with the help of two predicates, and in terms of optimality is very slow:
sublist([], []).
sublist([A|T], [A|L]):-
sublist(T, L).
sublist(T, [_|L]):-
sublist(T, L).
choose(T, L):-
sublist(T, L),
(dimension(2, T); dimension(1, T)),
belongs(f, T).
In here I would like to return through the T parameter of the choose predicate all the sublists of the L list which have the dimension 2 or 1 and which contains the f element. The predicates dimension and member has the same usage as the predefined predicates length, respectively member.Can you please tell me how to incorporate this two conditions within the sublist predicate so that the program builds only those particular sublists?
The following builds subsequences of length MinLen =< Len =< MaxLen. I've no idea why you renamed length and member, so I'm going to use the originals. sublist/4 calls your sublist/2.
sublist(Sub,List,MinLen,MaxLen) :-
between(MinLen,MaxLen,Len),
length(Sub,Len),
sublist(Sub,List).
Note that length is called on two variables, so you get an iterative deepening search. choose/2 can now be defined as
choose(Sub,List) :-
sublist(Sub,List,1,2),
member(f,Sub).
This is the clean solution. If it's is not fast enough, then roll all the conditions into one predicate:
choose(Sub,List),
(Sub = [f] ; Sub = [f,_] ; Sub = [_,f]),
sublist(Sub,List).

Resources