Search code examples
prologclpfdlatin-square

Prolog - Latin Square solution


I am trying to write a program in Prolog to find a Latin Square of size N.

I have this right now:

delete(X, [X|T], T).
delete(X, [H|T], [H|S]) :-
   delete(X, T, S).

permutation([], []).
permutation([H|T], R) :-
   permutation(T, X),
   delete(H, R, X).

latinSqaure([_]).
latinSquare([A,B|T], N) :-
   permutation(A,B),
   isSafe(A,B),
   latinSquare([B|T]).

isSafe([], []).
isSafe([H1|T1], [H2|T2]) :- 
   H1 =\= H2, 
   isSafe(T1, T2).

Solution

  • using SWI-Prolog library:

    :- module(latin_square, [latin_square/2]).
    :- use_module(library(clpfd), [transpose/2]).
    
    latin_square(N, S) :-
        numlist(1, N, Row),
        length(Rows, N),
        maplist(copy_term(Row), Rows),
        maplist(permutation, Rows, S),
        transpose(S, T),
        maplist(valid, T).
    
    valid([X|T]) :-
        memberchk(X, T), !, fail.
    valid([_|T]) :- valid(T).
    valid([_]).
    

    test:

    ?- aggregate(count,S^latin_square(4,S),C).
    C = 576.
    

    edit your code, once corrected removing typos, it's a verifier, not a generator, but (as noted by ssBarBee in a deleted comment), it's flawed by missing test on not adjacent rows. Here the corrected code

    delete(X, [X|T], T).
    delete(X, [H|T], [H|S]) :-
        delete(X, T, S).
    
    permutation([], []).
    permutation([H|T], R):-
        permutation(T, X),
        delete(H, R, X).
    
    latinSquare([_]).
    latinSquare([A,B|T]) :-
        permutation(A,B),
        isSafe(A,B),
        latinSquare([B|T]).
    
    isSafe([], []).
    isSafe([H1|T1], [H2|T2]) :-
        H1 =\= H2,
        isSafe(T1, T2).
    

    and some test

    ?- latinSquare([[1,2,3],[2,3,1],[3,2,1]]).
    false.
    
    ?- latinSquare([[1,2,3],[2,3,1],[3,1,2]]).
    true .
    
    ?- latinSquare([[1,2,3],[2,3,1],[1,2,3]]).
    true .
    

    note the last test it's wrong, should give false instead.