X
4291

Building Latin Squares with IDL

This Help Article provides the code to construct latin squares with IDL.

Discussion 
A latin square of order n is an nxn array, each element of which contains exactly one of the symbols {1,2,3,...,n}, such that each row and each column of the array contains each of the symbols in {1,2,3,...,n} exactly once. A latin square is said to be idempotent if cell (i,i) contains the symbol i for all 1 <= i <= n.. A latin square L of order 2n is said to be half-idempotent if for 1 <= i <= n elements (i,i) and (n+i,n+i) of L contain the symbol i.

Here is an example of a latin square of order 8:

IDL> print, latin_square(8)
2 3 4 5 6 7 8 1
3 4 5 6 7 8 1 2
4 5 6 7 8 1 2 3
5 6 7 8 1 2 3 4
6 7 8 1 2 3 4 5
7 8 1 2 3 4 5 6
8 1 2 3 4 5 6 7
1 2 3 4 5 6 7 8



Here is an example of an idempotent latin square of order 8:

IDL> print, latin_square(8, idempotent = 1)
1 8 2 6 3 7 4 5
5 2 8 3 7 4 1 6
2 6 3 8 4 1 5 7
6 3 7 4 8 5 2 1
3 7 4 1 5 8 6 2
7 4 1 5 2 6 8 3
8 1 5 2 6 3 7 4
4 5 6 7 1 2 3 8



Here is an example of a half-idempotent latin square of order 8:

IDL> print, latin_square(8, idempotent = 2)
1 6 2 5 3 7 4 8
6 2 5 3 7 4 8 1
2 5 3 7 4 8 1 6
5 3 7 4 8 1 6 2
3 7 4 8 1 6 2 5
7 4 8 1 6 2 5 3
4 8 1 6 2 5 3 7
8 1 6 2 5 3 7 4

Solution:

function add_group, sz
; This routine will return a Group table for the addititive
; group Z/nZ where n = sz.
row = lindgen(sz,sz)+1
col = lindgen(sz,sz)/sz + 1
return, (row+col) mod sz
end
;
;
function lat_sq, sz
; This routine will return a latin square of order SZ.
ls = add_group(sz)
ls[where(ls eq 0)] = sz
return, ls
end
;
;
function half_idempotent_latin_square, sz
; This routine will return a half idempotent latin square
; of order SZ.
if sz mod 2 eq 0 then begin ; Valid size.
ls = add_group(sz)
for i = 2, sz, 2 do begin
temp1 = where(ls eq i/2)
temp2 = where(ls eq i mod sz)
ls[temp1] = i
ls[temp2] = i/2
endfor
return, ls
endif else begin ; Invalid size.
void = dialog_message('Half idempotent Latin squares must have '+ $
'even dimensions. Returning "0"', /info)
return, 0
endelse
end
;
;
function idempotent_latin_square, in_sz
; This routine will return an idempotent latin square of order SZ.
if ((in_sz mod 2) eq 1) then sz = in_sz $
else sz = in_sz-1
; Constructing an idempotent Latin Square of odd order.
; Either in_sz or in_sz-1... Whichever is odd.
ls = add_group(sz)
for i = 0, (size(ls))[1]-1 do begin
val = ls[i,i]
temp2 = where(ls eq (i+1) mod sz)
ls[where(ls eq val)] = (i+1) mod sz
ls[temp2] = val
endfor
; Add the extra row/column to even ordered LS.
if ((in_sz mod 2) eq 0) then begin
even_ls = lonarr(in_sz,in_sz)
ls[where(ls eq 0)] = in_sz-1
even_ls[0:sz-1,0:sz-1] = ls[*,*]
for i = 0, in_sz-3 do begin
even_ls[in_sz-1,i] = even_ls[i+1,i]
even_ls[i+1,in_sz-1] = even_ls[i+1,i]
even_ls[i+1,i] = 0
end
even_ls[in_sz-1,in_sz-2] = even_ls[0,in_sz-2]
even_ls[0,in_sz-1] = even_ls[0,in_sz-2]
even_ls[0,in_sz-2] = 0
ls = even_ls
endif
ls[where(ls eq 0)] = in_sz
return, ls
end
;
;
function latin_square, sz, $ ; Wrapper routine.
idempotent = idem ; 1 : Idempotent
; 2 : Half Idempotent
case n_elements(sz) of
0: begin
void = dialog_message('You must enter a size.', /info)
return, 0
end
1: begin
if not keyword_set(idem) then idem = 0
case idem of
1: return, idempotent_latin_square(sz)
2: return, half_idempotent_latin_square(sz)
else: return, lat_sq(sz)
endcase
end
else: begin
void = dialog_message('SZ must be a scalar.', /info)
return, 0
end
endcase
end