Random Latin squares: Difference between revisions

From Rosetta Code
Content added Content deleted
(Add wp ref.)
m (Fixed two mis-spelled words.)
Line 2: Line 2:


A Latin square of size <code>n</code> is an arrangement of <code>n</code> symbols in an <code>n-by-n</code> square in such a way that each row and column has each symbol appearing exactly once.<br>
A Latin square of size <code>n</code> is an arrangement of <code>n</code> symbols in an <code>n-by-n</code> square in such a way that each row and column has each symbol appearing exactly once.<br>
A randomised Latin square generates random configuartions of the symbols for such a Latin square
A randomised Latin square generates random configurations of the symbols for such a Latin square


;Example n=4 randomised Latin square:
;Example n=4 randomised Latin square:
Line 11: Line 11:


;Task:
;Task:
# Generate a function/routine/proceedure/method/... that given <code>n</code> generates a randomised Latin square of size <code>n</code>.
# Generate a function/routine/procedure/method/... that given <code>n</code> generates a randomised Latin square of size <code>n</code>.
# Use the function to generate ''and show here'', two randomly generated squares of size 5.
# Use the function to generate ''and show here'', two randomly generated squares of size 5.



Revision as of 13:32, 9 June 2019

Random Latin squares is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

A Latin square of size n is an arrangement of n symbols in an n-by-n square in such a way that each row and column has each symbol appearing exactly once.
A randomised Latin square generates random configurations of the symbols for such a Latin square

Example n=4 randomised Latin square
0 2 3 1
2 1 0 3
3 0 1 2
1 3 2 0
Task
  1. Generate a function/routine/procedure/method/... that given n generates a randomised Latin square of size n.
  2. Use the function to generate and show here, two randomly generated squares of size 5.
Reference

Julia

Using the Python algorithm as described in the discussion section. <lang julia>using Random

shufflerows(mat) = mat[shuffle(1:end), :] shufflecols(mat) = mat[:, shuffle(1:end)]

function addatdiagonal(mat)

   n = size(mat)[1] + 1
   newmat = similar(mat, size(mat) .+ 1)
   for j in 1:n, i in 1:n
       newmat[i, j] = (i == n && j < n) ? mat[1, j] : (i == j) ? n - 1 :
           (i < j) ? mat[i, j - 1] : mat[i, j]
   end
   newmat

end

function makelatinsquare(N)

   mat = [0 1; 1 0]
   for i in 3:N
       mat = addatdiagonal(mat)
   end
   shufflecols(shufflerows(mat))

end

function printlatinsquare(N)

   mat = makelatinsquare(N)
   for i in 1:N, j in 1:N
       print(rpad(mat[i, j], 3), j == N ? "\n" : "")
   end

end

printlatinsquare(5), println("\n"), printlatinsquare(5)

</lang>

Output:
1  3  0  4  2
3  0  4  2  1
0  4  2  1  3
2  1  3  0  4
4  2  1  3  0


2  0  1  3  4
4  3  2  1  0
3  2  0  4  1
1  4  3  0  2
0  1  4  2  3


Perl 6

Works with: Rakudo version 2019.03
Translation of: Python

<lang perl6>sub latin-square { [[0,1], [1,0]] };

sub random ( @ls, :$size = 5 ) {

   # Build
   for 2 ..^ $size -> $i {
       @ls[$i] = @ls[0].clone;
       @ls[$_].splice($_, 0, $i) for 0 .. $i;
   }
   # Shuffle
   @ls = @ls[^$size .pick(*)];
   my @cols = ^$size .pick(*);
   @ls[$_] = @ls[$_][@cols] for ^@ls;
   # Some random Latin glyphs
   my @symbols = ('Ŋ' .. 'ž').pick($size);
   @ls.deepmap: { $_ = @symbols[$_] };

}

sub display ( @array ) { $_.fmt("%2s ").put for |@array, }


  1. The Task
  1. Default size 5

display random latin-square;

  1. Specified size

display random :size($_), latin-square for 3, 3;

  1. Or, if you'd prefer:

display random latin-square, :size($_) for 9, 14;</lang>

Sample output:
 Ř   ŝ   ŷ   ű   ŭ 
 ŷ   ű   ŭ   Ř   ŝ 
 ŭ   Ř   ŝ   ŷ   ű 
 ű   ŭ   Ř   ŝ   ŷ 
 ŝ   ŷ   ű   ŭ   Ř 
   
 ŋ   ŗ   ŭ 
 ŗ   ŭ   ŋ 
 ŭ   ŋ   ŗ 
   
 Ř   ő   Ū 
 Ū   Ř   ő 
 ő   Ū   Ř 
   
 Ŵ   Ÿ   Ţ   ů   ş   Ū   ţ   ŧ   ű 
 ŧ   Ţ   ů   Ÿ   Ŵ   ű   Ū   ş   ţ 
 Ū   ş   Ŵ   ŧ   ţ   ů   Ţ   ű   Ÿ 
 ů   ţ   Ū   ű   Ţ   ŧ   Ŵ   Ÿ   ş 
 ş   ů   Ÿ   Ţ   ŧ   ţ   ű   Ŵ   Ū 
 ţ   ŧ   ş   Ŵ   ű   Ţ   Ÿ   Ū   ů 
 Ţ   ű   ţ   Ū   Ÿ   Ŵ   ş   ů   ŧ 
 Ÿ   Ū   ű   ţ   ů   ş   ŧ   Ţ   Ŵ 
 ű   Ŵ   ŧ   ş   Ū   Ÿ   ů   ţ   Ţ 
   
 ō   Ş   ū   ŝ   Ŝ   ś   Ž   ř   Ś   š   Ů   ž   Ō   Ŗ 
 Ŗ   ś   Ō   ū   ř   Ů   Ś   ž   Ŝ   ō   š   ŝ   Ş   Ž 
 ś   ŝ   ř   Ŝ   Ŗ   ū   š   Ž   ō   Ş   Ō   Ś   ž   Ů 
 Ş   ž   Ŝ   Ś   ō   ŝ   Ů   Ŗ   š   Ō   ū   Ž   ř   ś 
 Ŝ   ō   Ů   ś   ū   Ŗ   ž   Ō   ŝ   Ś   Ž   Ş   š   ř 
 Ś   š   ś   Ş   ŝ   ō   ř   ū   ž   Ž   Ŗ   Ō   Ů   Ŝ 
 Ž   Ů   Ş   Ō   ž   š   Ŝ   ŝ   ř   Ŗ   ō   ū   ś   Ś 
 š   Ō   ŝ   ž   Ś   Ş   Ŗ   Ŝ   Ž   Ů   ś   ř   ū   ō 
 ū   Ŝ   Ž   Ŗ   Ů   ř   Ş   š   ś   ŝ   ž   ō   Ś   Ō 
 ŝ   Ś   Ŗ   ō   ś   Ŝ   Ō   Ů   Ş   ž   ř   š   Ž   ū 
 ž   Ž   ō   š   Ş   Ś   ū   ś   Ō   ř   Ŝ   Ů   Ŗ   ŝ 
 ř   Ŗ   š   Ů   Ō   Ž   ŝ   Ş   ū   Ŝ   Ś   ś   ō   ž 
 Ů   ū   ž   ř   Ž   Ō   ō   Ś   Ŗ   ś   Ş   Ŝ   ŝ   š 
 Ō   ř   Ś   Ž   š   ž   ś   ō   Ů   ū   ŝ   Ŗ   Ŝ   Ş

Python

<lang python>from random import choice, shuffle from copy import deepcopy

def rls(n):

   if n <= 0:
       return []
   else:
       symbols = list(range(n))
       square = _rls(symbols)
       return _shuffle_transpose_shuffle(square)


def _shuffle_transpose_shuffle(matrix):

   square = deepcopy(matrix)
   shuffle(square)
   trans = list(zip(*square))
   shuffle(trans)
   return trans


def _rls(symbols):

   n = len(symbols)
   if n == 1:
       return [symbols]
   else:
       sym = choice(symbols)
       symbols.remove(sym)
       square = _rls(symbols)
       square.append(square[0].copy())
       for i in range(n):
           square[i].insert(i, sym)
       return square

def _to_text(square):

   if square:
       width = max(len(str(sym)) for row in square for sym in row)
       txt = '\n'.join(' '.join(f"{sym:>{width}}" for sym in row)
                       for row in square)
   else:
       txt = 
   return txt

def _check(square):

   transpose = list(zip(*square))
   assert _check_rows(square) and _check_rows(transpose), \
       "Not a Latin square"

def _check_rows(square):

   if not square:
       return True
   set_row0 = set(square[0])
   return all(len(row) == len(set(row)) and set(row) == set_row0
              for row in square)


if __name__ == '__main__':

   for i in [3, 3,  5, 5, 12]:
       square = rls(i)
       print(_to_text(square))
       _check(square)
       print()</lang>
Output:
2 1 0
0 2 1
1 0 2

1 0 2
0 2 1
2 1 0

1 0 3 2 4
3 4 2 0 1
4 2 1 3 0
2 1 0 4 3
0 3 4 1 2

2 1 0 4 3
0 4 3 2 1
3 2 1 0 4
4 3 2 1 0
1 0 4 3 2

 6  2  4  8 11  9  3  1  7  0  5 10
 1 11  5  2  8  6  0  9  4 10  7  3
 2  7 10  5  4  8  9 11  0  6  3  1
 8  5  0  4  7 11  1  2  3  9 10  6
11  4  3  7  5  2  6  8 10  1  0  9
10  1  8  6  9  0  7  3 11  4  2  5
 7  0  1  3 10  5  8  4  6  2  9 11
 9  8  7 11  2  1 10  6  5  3  4  0
 3  9  2  1  6 10  4  0  8  5 11  7
 5  3  6 10  0  4 11  7  9  8  1  2
 4 10  9  0  3  7  2  5  1 11  6  8
 0  6 11  9  1  3  5 10  2  7  8  4