Data commit

This commit is contained in:
Ingy döt Net 2023-07-01 11:58:00 -04:00
parent 7387c8f97b
commit cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions

View file

@ -0,0 +1,2 @@
---
from: http://rosettacode.org/wiki/Random_Latin_squares

View file

@ -0,0 +1,25 @@
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>
For the purposes of this task, a random Latin square of size <code>n</code> is a Latin square constructed or generated by a probabilistic procedure such that the probability of any particular Latin square of size <code>n</code> being produced is non-zero.
;Example n=4 randomised Latin square:
<pre>0 2 3 1
2 1 0 3
3 0 1 2
1 3 2 0</pre>
;Task:
# Create 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.
;Note:
Strict ''uniformity'' in the random generation is a hard problem and '''not''' a requirement of the task.
;Related tasks:
* [[Latin Squares in reduced form/Randomizing using Jacobson and Matthews Technique]]
* [[Latin Squares in reduced form]]
;Reference:
* [[wp:Latin_square|Wikipedia: Latin square]]
* [[oeis:A002860|OEIS: A002860]]
<br>

View file

@ -0,0 +1,46 @@
F _transpose(matrix)
assert(matrix.len == matrix[0].len)
V r = [[0] * matrix.len] * matrix.len
L(i) 0 .< matrix.len
L(j) 0 .< matrix.len
r[i][j] = matrix[j][i]
R r
F _shuffle_transpose_shuffle(matrix)
V square = copy(matrix)
random:shuffle(&square)
V trans = _transpose(square)
random:shuffle(&trans)
R trans
F _rls(&symbols)
V n = symbols.len
I n == 1
R [symbols]
E
V sym = random:choice(symbols)
symbols.remove(sym)
V square = _rls(&symbols)
square.append(copy(square[0]))
L(i) 0 .< n
square[i].insert(i, sym)
R square
F rls(n)
V symbols = Array(0 .< n)
V square = _rls(&symbols)
R _shuffle_transpose_shuffle(square)
F _check_rows(square)
V set_row0 = Set(square[0])
R all(square.map(row -> row.len == Set(row).len & Set(row) == @set_row0))
F _check(square)
V transpose = _transpose(square)
assert(_check_rows(square) & _check_rows(transpose), Not a Latin square)
L(i) [3, 3, 5, 5]
V square = rls(i)
print(square.map(row -> row.join( )).join("\n"))
_check(square)
print()

View file

@ -0,0 +1,81 @@
BEGIN # generate random latin squares #
# Knuth Shuffle routine from the Knuth Shuffle Task #
# modified to shufflw a row of a [,]CHAR array #
PROC knuth shuffle = (REF[,]CHAR a, INT row)VOID:
(
PROC between = (INT a, b)INT :
(
ENTIER (random * ABS (b-a+1) + (a<b|a|b))
);
FOR i FROM LWB a TO UPB a DO
INT j = between(LWB a, UPB a);
CHAR t = a[row, i];
a[row, i] := a[row, j];
a[row, j] := t
OD
);
# generates a random latin square #
PROC latin square = ( INT n )[,]CHAR:
BEGIN
[ 1 : n ]CHAR letters;
[ 1 : n, 1 : n ]CHAR result;
FOR col TO n DO
letters[ col ] := REPR ( ABS "A" + ( col - 1 ) )
OD;
FOR row TO n DO
result[ row, : ] := letters
OD;
knuth shuffle( result, 1 );
FOR row FROM 2 TO n - 1 DO
BOOL ok := FALSE;
WHILE
knuth shuffle( result, row );
BOOL all different := TRUE;
FOR prev TO row - 1 WHILE all different DO
FOR col TO n
WHILE all different :=
result[ row, col ] /= result[ prev, col ]
DO SKIP OD
OD;
NOT all different
DO SKIP OD
OD;
# the final row, there is only one possibility for each column #
FOR col TO n DO
[ 1 : n ]CHAR free := letters;
FOR row TO n - 1 DO
free[ ( ABS result[ row, col ] - ABS "A" ) + 1 ] := REPR 0
OD;
BOOL found := FALSE;
FOR row FROM 1 LWB result TO 1 UPB result WHILE NOT found DO
IF free[ row ] /= REPR 0 THEN
found := TRUE;
result[ n, col ] := free[ row ]
FI
OD
OD;
result
END # latin suare # ;
# prints a latin square #
PROC print square = ( [,]CHAR square )VOID:
FOR row FROM 1 LWB square TO 1 UPB square DO
IF 2 LWB square <= 2 UPB square THEN
print( ( square[ row, 2 LWB square ] ) );
FOR col FROM 2 LWB square + 1 TO 2 UPB square DO
print( ( " ", square[ row, col ] ) )
OD;
print( ( newline ) )
FI
OD # print square # ;
next random;
print square( latin square( 5 ) );
print( ( newline ) );
print square( latin square( 5 ) );
print( ( newline ) );
print square( latin square( 10 ) )
END

View file

@ -0,0 +1,124 @@
DEFINE PTR="CARD"
DEFINE DIMENSION="5"
TYPE Matrix=[
PTR data ;BYTE ARRAY
BYTE dim]
PTR FUNC GetPtr(Matrix POINTER mat BYTE x,y)
RETURN (mat.data+x+y*mat.dim)
PROC PrintMatrix(Matrix POINTER mat)
BYTE x,y
BYTE POINTER d
d=GetPtr(mat,0,0)
FOR y=0 TO mat.dim-1
DO
FOR x=0 TO mat.dim-1
DO
PrintB(d^) Put(32)
d==+1
OD
PutE()
OD
RETURN
PROC KnuthShuffle(BYTE ARRAY tab BYTE size)
BYTE i,j,tmp
i=size-1
WHILE i>0
DO
j=Rand(i+1)
tmp=tab(i)
tab(i)=tab(j)
tab(j)=tmp
i==-1
OD
RETURN
PROC LatinSquare(Matrix POINTER mat)
BYTE x,y,yy,shuffled
BYTE POINTER ptr1,ptr2
BYTE ARRAY used(DIMENSION)
ptr1=GetPtr(mat,0,0)
FOR y=0 TO mat.dim-1
DO
FOR x=0 TO mat.dim-1
DO
ptr1^=x
ptr1==+1
OD
OD
;first row
ptr1=GetPtr(mat,0,0)
KnuthShuffle(ptr1,mat.dim)
;middle rows
FOR y=1 TO mat.dim-2
DO
shuffled=0
WHILE shuffled=0
DO
ptr1=GetPtr(mat,0,y)
KnuthShuffle(ptr1,mat.dim)
shuffled=1
yy=0
WHILE shuffled=1 AND yy<y
DO
x=0
WHILE shuffled=1 AND x<mat.dim
DO
ptr1=GetPtr(mat,x,yy)
ptr2=GetPtr(mat,x,y)
IF ptr1^=ptr2^ THEN
shuffled=0
FI
x==+1
OD
yy==+1
OD
OD
OD
;last row
FOR x=0 TO mat.dim-1
DO
Zero(used,mat.dim)
FOR y=0 TO mat.dim-2
DO
ptr1=GetPtr(mat,x,y)
yy=ptr1^ used(yy)=1
OD
FOR y=0 TO mat.dim-1
DO
IF used(y)=0 THEN
ptr1=GetPtr(mat,x,mat.dim-1)
ptr1^=y
EXIT
FI
OD
OD
RETURN
PROC Main()
BYTE ARRAY d(25)
BYTE i
Matrix mat
mat.data=d
mat.dim=DIMENSION
FOR i=1 TO 2
DO
LatinSquare(mat)
PrintMatrix(mat)
PutE()
OD
RETURN

View file

@ -0,0 +1,24 @@
latinSquare: function [n][
square: new []
variants: shuffle permutate 0..n-1
while -> n > size square [
row: sample variants
'square ++ @[row]
filter 'variants 'variant [
reject: false
loop.with:'i variant 'col [
if col = row\[i] ->
reject: true
]
reject
]
]
return square
]
loop 2 'x [
ls: latinSquare 5
loop ls 'row ->
print row
print "---------"
]

View file

@ -0,0 +1,94 @@
#include <algorithm>
#include <chrono>
#include <iostream>
#include <random>
#include <vector>
template <typename T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &v) {
auto it = v.cbegin();
auto end = v.cend();
os << '[';
if (it != end) {
os << *it;
it = std::next(it);
}
while (it != end) {
os << ", ";
os << *it;
it = std::next(it);
}
return os << ']';
}
void printSquare(const std::vector<std::vector<int>> &latin) {
for (auto &row : latin) {
std::cout << row << '\n';
}
std::cout << '\n';
}
void latinSquare(int n) {
if (n <= 0) {
std::cout << "[]\n";
return;
}
// obtain a time-based seed:
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
auto g = std::default_random_engine(seed);
std::vector<std::vector<int>> latin;
for (int i = 0; i < n; ++i) {
std::vector<int> inner;
for (int j = 0; j < n; ++j) {
inner.push_back(j);
}
latin.push_back(inner);
}
// first row
std::shuffle(latin[0].begin(), latin[0].end(), g);
// middle row(s)
for (int i = 1; i < n - 1; ++i) {
bool shuffled = false;
while (!shuffled) {
std::shuffle(latin[i].begin(), latin[i].end(), g);
for (int k = 0; k < i; ++k) {
for (int j = 0; j < n; ++j) {
if (latin[k][j] == latin[i][j]) {
goto shuffling;
}
}
}
shuffled = true;
shuffling: {}
}
}
// last row
for (int j = 0; j < n; ++j) {
std::vector<bool> used(n, false);
for (int i = 0; i < n - 1; ++i) {
used[latin[i][j]] = true;
}
for (int k = 0; k < n; ++k) {
if (!used[k]) {
latin[n - 1][j] = k;
break;
}
}
}
printSquare(latin);
}
int main() {
latinSquare(5);
latinSquare(5);
latinSquare(10);
return 0;
}

View file

@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
namespace RandomLatinSquares {
using Matrix = List<List<int>>;
// Taken from https://stackoverflow.com/a/1262619
static class Helper {
private static readonly Random rng = new Random();
public static void Shuffle<T>(this IList<T> list) {
int n = list.Count;
while (n > 1) {
n--;
int k = rng.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
}
class Program {
static void PrintSquare(Matrix latin) {
foreach (var row in latin) {
Console.Write('[');
var it = row.GetEnumerator();
if (it.MoveNext()) {
Console.Write(it.Current);
}
while (it.MoveNext()) {
Console.Write(", ");
Console.Write(it.Current);
}
Console.WriteLine(']');
}
Console.WriteLine();
}
static void LatinSquare(int n) {
if (n <= 0) {
Console.WriteLine("[]");
return;
}
var latin = new Matrix();
for (int i = 0; i < n; i++) {
List<int> temp = new List<int>();
for (int j = 0; j < n; j++) {
temp.Add(j);
}
latin.Add(temp);
}
// first row
latin[0].Shuffle();
// middle row(s)
for (int i = 1; i < n - 1; i++) {
bool shuffled = false;
while (!shuffled) {
latin[i].Shuffle();
for (int k = 0; k < i; k++) {
for (int j = 0; j < n; j++) {
if (latin[k][j] == latin[i][j]) {
goto shuffling;
}
}
}
shuffled = true;
shuffling: { }
}
}
// last row
for (int j = 0; j < n; j++) {
List<bool> used = new List<bool>();
for (int i = 0; i < n; i++) {
used.Add(false);
}
for (int i = 0; i < n-1; i++) {
used[latin[i][j]] = true;
}
for (int k = 0; k < n; k++) {
if (!used[k]) {
latin[n - 1][j] = k;
break;
}
}
}
PrintSquare(latin);
}
static void Main() {
LatinSquare(5);
LatinSquare(5);
LatinSquare(10); // for good measure
}
}
}

View file

@ -0,0 +1,118 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
// low <= num < high
int randInt(int low, int high) {
return (rand() % (high - low)) + low;
}
// shuffle an array of n elements
void shuffle(int *const array, const int n) {
if (n > 1) {
int i;
for (i = 0; i < n - 1; i++) {
int j = randInt(i, n);
int t = array[i];
array[i] = array[j];
array[j] = t;
}
}
}
// print an n * n array
void printSquare(const int *const latin, const int n) {
int i, j;
for (i = 0; i < n; i++) {
printf("[");
for (j = 0; j < n; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", latin[i * n + j]);
}
printf("]\n");
}
printf("\n");
}
void latinSquare(const int n) {
int *latin, *used;
int i, j, k;
if (n <= 0) {
printf("[]\n");
return;
}
// allocate
latin = (int *)malloc(n * n * sizeof(int));
if (!latin) {
printf("Failed to allocate memory.");
return;
}
// initialize
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
latin[i * n + j] = j;
}
}
// first row
shuffle(latin, n);
// middle row(s)
for (i = 1; i < n - 1; i++) {
bool shuffled = false;
while (!shuffled) {
shuffle(&latin[i * n], n);
for (k = 0; k < i; k++) {
for (j = 0; j < n; j++) {
if (latin[k * n + j] == latin[i * n + j]) {
goto shuffling;
}
}
}
shuffled = true;
shuffling: {}
}
}
//last row
used = (int *)malloc(n * sizeof(int));
for (j = 0; j < n; j++) {
memset(used, 0, n * sizeof(int));
for (i = 0; i < n - 1; i++) {
used[latin[i * n + j]] = 1;
}
for (k = 0; k < n; k++) {
if (used[k] == 0) {
latin[(n - 1) * n + j] = k;
break;
}
}
}
free(used);
// print the result
printSquare(latin, n);
free(latin);
}
int main() {
// initialze the random number generator
srand((unsigned int)time((time_t)0));
latinSquare(5);
latinSquare(5);
latinSquare(10);
return 0;
}

View file

@ -0,0 +1,73 @@
import std.array;
import std.random;
import std.stdio;
alias Matrix = int[][];
void latinSquare(int n) {
if (n <= 0) {
writeln("[]");
return;
}
Matrix latin = uninitializedArray!Matrix(n, n);
foreach (row; latin) {
for (int i = 0; i < n; i++) {
row[i] = i;
}
}
// first row
latin[0].randomShuffle;
// middle row(s)
for (int i = 1; i < n - 1; i++) {
bool shuffled = false;
shuffling:
while (!shuffled) {
latin[i].randomShuffle;
for (int k = 0; k < i; k++) {
for (int j = 0; j < n; j++) {
if (latin[k][j] == latin[i][j]) {
continue shuffling;
}
}
}
shuffled = true;
}
}
// last row
for (int j = 0; j < n; j++) {
bool[] used = uninitializedArray!(bool[])(n);
used[] = false;
for (int i = 0; i < n - 1; i++) {
used[latin[i][j]] = true;
}
for (int k = 0; k < n; k++) {
if (!used[k]) {
latin[n - 1][j] = k;
break;
}
}
}
printSquare(latin);
}
void printSquare(Matrix latin) {
foreach (row; latin) {
writeln(row);
}
}
void main() {
latinSquare(5);
writeln;
latinSquare(5);
writeln;
latinSquare(10);
}

View file

@ -0,0 +1,4 @@
// Generate 2 Random Latin Squares of order 5. Nigel Galloway: July 136th., 2019
let N=let N=System.Random() in (fun n->N.Next(n))
let rc()=let β=lN2p [|0;N 4;N 3;N 2|] [|0..4|] in Seq.item (N 56) (normLS 5) |> List.map(lN2p [|N 5;N 4;N 3;N 2|]) |> List.permute(fun n->β.[n]) |> List.iter(printfn "%A")
rc(); printfn ""; rc()

View file

@ -0,0 +1,11 @@
USING: arrays combinators.extras fry io kernel math.matrices
prettyprint random sequences sets ;
IN: rosetta-code.random-latin-squares
: rand-permutation ( n -- seq ) <iota> >array randomize ;
: ls? ( n -- ? ) [ all-unique? ] column-map t [ and ] reduce ;
: (ls) ( n -- m ) dup '[ _ rand-permutation ] replicate ;
: ls ( n -- m ) dup (ls) dup ls? [ nip ] [ drop ls ] if ;
: random-latin-squares ( -- ) [ 5 ls simple-table. nl ] twice ;
MAIN: random-latin-squares

View file

@ -0,0 +1,80 @@
package main
import (
"fmt"
"math/rand"
"time"
)
type matrix [][]int
func shuffle(row []int, n int) {
rand.Shuffle(n, func(i, j int) {
row[i], row[j] = row[j], row[i]
})
}
func latinSquare(n int) {
if n <= 0 {
fmt.Println("[]\n")
return
}
latin := make(matrix, n)
for i := 0; i < n; i++ {
latin[i] = make([]int, n)
if i == n-1 {
break
}
for j := 0; j < n; j++ {
latin[i][j] = j
}
}
// first row
shuffle(latin[0], n)
// middle row(s)
for i := 1; i < n-1; i++ {
shuffled := false
shuffling:
for !shuffled {
shuffle(latin[i], n)
for k := 0; k < i; k++ {
for j := 0; j < n; j++ {
if latin[k][j] == latin[i][j] {
continue shuffling
}
}
}
shuffled = true
}
}
// last row
for j := 0; j < n; j++ {
used := make([]bool, n)
for i := 0; i < n-1; i++ {
used[latin[i][j]] = true
}
for k := 0; k < n; k++ {
if !used[k] {
latin[n-1][j] = k
break
}
}
}
printSquare(latin, n)
}
func printSquare(latin matrix, n int) {
for i := 0; i < n; i++ {
fmt.Println(latin[i])
}
fmt.Println()
}
func main() {
rand.Seed(time.Now().UnixNano())
latinSquare(5)
latinSquare(5)
latinSquare(10) // for good measure
}

View file

@ -0,0 +1,253 @@
package main
import (
"fmt"
"math/rand"
"sort"
"time"
)
type matrix [][]int
// generate derangements of first n numbers, with 'start' in first place.
func dList(n, start int) (r matrix) {
start-- // use 0 basing
a := make([]int, n)
for i := range a {
a[i] = i
}
a[0], a[start] = start, a[0]
sort.Ints(a[1:])
first := a[1]
// recursive closure permutes a[1:]
var recurse func(last int)
recurse = func(last int) {
if last == first {
// bottom of recursion. you get here once for each permutation.
// test if permutation is deranged.
for j, v := range a[1:] { // j starts from 0, not 1
if j+1 == v {
return // no, ignore it
}
}
// yes, save a copy
b := make([]int, n)
copy(b, a)
for i := range b {
b[i]++ // change back to 1 basing
}
r = append(r, b)
return
}
for i := last; i >= 1; i-- {
a[i], a[last] = a[last], a[i]
recurse(last - 1)
a[i], a[last] = a[last], a[i]
}
}
recurse(n - 1)
return
}
func reducedLatinSquares(n int) []matrix {
var rls []matrix
if n < 0 {
n = 0
}
rlatin := make(matrix, n)
for i := 0; i < n; i++ {
rlatin[i] = make([]int, n)
}
if n <= 1 {
return append(rls, rlatin)
}
// first row
for j := 0; j < n; j++ {
rlatin[0][j] = j + 1
}
// recursive closure to compute reduced latin squares
var recurse func(i int)
recurse = func(i int) {
rows := dList(n, i) // get derangements of first n numbers, with 'i' first.
outer:
for r := 0; r < len(rows); r++ {
copy(rlatin[i-1], rows[r])
for k := 0; k < i-1; k++ {
for j := 1; j < n; j++ {
if rlatin[k][j] == rlatin[i-1][j] {
if r < len(rows)-1 {
continue outer
} else if i > 2 {
return
}
}
}
}
if i < n {
recurse(i + 1)
} else {
rl := copyMatrix(rlatin)
rls = append(rls, rl)
}
}
return
}
// remaining rows
recurse(2)
return rls
}
func copyMatrix(m matrix) matrix {
le := len(m)
cpy := make(matrix, le)
for i := 0; i < le; i++ {
cpy[i] = make([]int, le)
copy(cpy[i], m[i])
}
return cpy
}
func printSquare(latin matrix, n int) {
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
fmt.Printf("%d ", latin[i][j]-1)
}
fmt.Println()
}
fmt.Println()
}
func factorial(n uint64) uint64 {
if n == 0 {
return 1
}
prod := uint64(1)
for i := uint64(2); i <= n; i++ {
prod *= i
}
return prod
}
// generate permutations of first n numbers, starting from 0.
func pList(n int) matrix {
fact := factorial(uint64(n))
perms := make(matrix, fact)
a := make([]int, n)
for i := 0; i < n; i++ {
a[i] = i
}
t := make([]int, n)
copy(t, a)
perms[0] = t
n--
var i, j int
for c := uint64(1); c < fact; c++ {
i = n - 1
j = n
for a[i] > a[i+1] {
i--
}
for a[j] < a[i] {
j--
}
a[i], a[j] = a[j], a[i]
j = n
i++
for i < j {
a[i], a[j] = a[j], a[i]
i++
j--
}
t := make([]int, n+1)
copy(t, a)
perms[c] = t
}
return perms
}
func generateLatinSquares(n, tests, echo int) {
rls := reducedLatinSquares(n)
perms := pList(n)
perms2 := pList(n - 1)
for test := 0; test < tests; test++ {
rn := rand.Intn(len(rls))
rl := rls[rn] // select reduced random square at random
rn = rand.Intn(len(perms))
rp := perms[rn] // select a random permuation of 'rl's columns
// permute columns
t := make(matrix, n)
for i := 0; i < n; i++ {
t[i] = make([]int, n)
}
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
t[i][j] = rl[i][rp[j]]
}
}
rn = rand.Intn(len(perms2))
rp = perms2[rn] // select a random permutation of 't's rows 2 to n
// permute rows 2 to n
u := make(matrix, n)
for i := 0; i < n; i++ {
u[i] = make([]int, n)
}
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
if i == 0 {
u[i][j] = t[i][j]
} else {
u[i][j] = t[rp[i-1]+1][j]
}
}
}
if test < echo {
printSquare(u, n)
}
if n == 4 {
for i := 0; i < 4; i++ {
for j := 0; j < 4; j++ {
u[i][j]--
}
}
for i := 0; i < 4; i++ {
copy(a[4*i:], u[i])
}
for i := 0; i < 4; i++ {
if testSquares[i] == a {
counts[i]++
break
}
}
}
}
}
var testSquares = [4][16]int{
{0, 1, 2, 3, 1, 0, 3, 2, 2, 3, 0, 1, 3, 2, 1, 0},
{0, 1, 2, 3, 1, 0, 3, 2, 2, 3, 1, 0, 3, 2, 0, 1},
{0, 1, 2, 3, 1, 2, 3, 0, 2, 3, 0, 1, 3, 0, 1, 2},
{0, 1, 2, 3, 1, 3, 0, 2, 2, 0, 3, 1, 3, 2, 1, 0},
}
var (
counts [4]int
a [16]int
)
func main() {
rand.Seed(time.Now().UnixNano())
fmt.Println("Two randomly generated latin squares of order 5 are:\n")
generateLatinSquares(5, 2, 2)
fmt.Println("Out of 1,000,000 randomly generated latin squares of order 4, ")
fmt.Println("of which there are 576 instances ( => expected 1736 per instance),")
fmt.Println("the following squares occurred the number of times shown:\n")
generateLatinSquares(4, 1e6, 0)
for i := 0; i < 4; i++ {
fmt.Println(testSquares[i][:], ":", counts[i])
}
fmt.Println("\nA randomly generated latin square of order 6 is:\n")
generateLatinSquares(6, 1, 1)
}

View file

@ -0,0 +1,28 @@
import Data.List (permutations, (\\))
latinSquare :: Eq a => [a] -> [a] -> [[a]]
latinSquare [] [] = []
latinSquare c r
| head r /= head c = []
| otherwise = reverse <$> foldl addRow firstRow perms
where
-- permutations grouped by the first element
perms =
tail $
fmap
(fmap . (:) <*> (permutations . (r \\) . return))
c
firstRow = pure <$> r
addRow tbl rows =
head
[ zipWith (:) row tbl
| row <- rows,
and $ different (tail row) (tail tbl)
]
different = zipWith $ (not .) . elem
printTable :: Show a => [[a]] -> IO ()
printTable tbl =
putStrLn $
unlines $
unwords . map show <$> tbl

View file

@ -0,0 +1,5 @@
randomLatinSquare :: Eq a => [a] -> Random [[a]]
randomLatinSquare set = do
r <- randomPermutation set
c <- randomPermutation (tail r)
return $ latinSquare r (head r:c)

View file

@ -0,0 +1,21 @@
import Control.Monad.State
type Random a = State Int a
random :: Integral a => a -> Random a
random k = rescale <$> modify iter
where
iter x = (x * a + c) `mod` m
(a, c, m) = (1103515245, 12345, 2^31-1)
rescale x = fromIntegral x `mod` k
randomPermutation :: Eq a => [a] -> Random [a]
randomPermutation = go
where
go [] = pure []
go lst = do
x <- randomSample lst
(x :) <$> go (lst \\ [x])
randomSample :: [a] -> Random a
randomSample lst = (lst !!) <$> random (length lst)

View file

@ -0,0 +1,11 @@
rls=: 3 : 0
s=. ?~ y NB. "deal" y unique integers from 0 to y
for_ijk. i.<:y do.
NB. deal a new row. subtract it from all previous rows
NB. if you get a 0, some column has a matching integer, deal again
whilst. 0 = */ */ s -"1 r do.
r=. ?~ y
end.
s=. s ,,: r NB. "laminate" successful row to the square
end.
)

View file

@ -0,0 +1,86 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
public class RandomLatinSquares {
private static void printSquare(List<List<Integer>> latin) {
for (List<Integer> row : latin) {
Iterator<Integer> it = row.iterator();
System.out.print("[");
if (it.hasNext()) {
Integer col = it.next();
System.out.print(col);
}
while (it.hasNext()) {
Integer col = it.next();
System.out.print(", ");
System.out.print(col);
}
System.out.println("]");
}
System.out.println();
}
private static void latinSquare(int n) {
if (n <= 0) {
System.out.println("[]");
return;
}
List<List<Integer>> latin = new ArrayList<>(n);
for (int i = 0; i < n; ++i) {
List<Integer> inner = new ArrayList<>(n);
for (int j = 0; j < n; ++j) {
inner.add(j);
}
latin.add(inner);
}
// first row
Collections.shuffle(latin.get(0));
// middle row(s)
for (int i = 1; i < n - 1; ++i) {
boolean shuffled = false;
shuffling:
while (!shuffled) {
Collections.shuffle(latin.get(i));
for (int k = 0; k < i; ++k) {
for (int j = 0; j < n; ++j) {
if (Objects.equals(latin.get(k).get(j), latin.get(i).get(j))) {
continue shuffling;
}
}
}
shuffled = true;
}
}
// last row
for (int j = 0; j < n; ++j) {
List<Boolean> used = new ArrayList<>(n);
for (int i = 0; i < n; ++i) {
used.add(false);
}
for (int i = 0; i < n - 1; ++i) {
used.set(latin.get(i).get(j), true);
}
for (int k = 0; k < n; ++k) {
if (!used.get(k)) {
latin.get(n - 1).set(j, k);
break;
}
}
}
printSquare(latin);
}
public static void main(String[] args) {
latinSquare(5);
latinSquare(5);
latinSquare(10);
}
}

View file

@ -0,0 +1,52 @@
class Latin {
constructor(size = 3) {
this.size = size;
this.mst = [...Array(this.size)].map((v, i) => i + 1);
this.square = Array(this.size).fill(0).map(() => Array(this.size).fill(0));
if (this.create(0, 0)) {
console.table(this.square);
}
}
create(c, r) {
const d = [...this.mst];
let s;
while (true) {
do {
s = d.splice(Math.floor(Math.random() * d.length), 1)[0];
if (!s) return false;
} while (this.check(s, c, r));
this.square[c][r] = s;
if (++c >= this.size) {
c = 0;
if (++r >= this.size) {
return true;
}
}
if (this.create(c, r)) return true;
if (--c < 0) {
c = this.size - 1;
if (--r < 0) {
return false;
}
}
}
}
check(d, c, r) {
for (let a = 0; a < this.size; a++) {
if (c - a > -1) {
if (this.square[c - a][r] === d)
return true;
}
if (r - a > -1) {
if (this.square[c][r - a] === d)
return true;
}
}
return false;
}
}
new Latin(5);

View file

@ -0,0 +1,2 @@
#!/bin/bash
< /dev/random tr -cd '0-9' | fold -w 1 | jq -Mcnr -f random-latin-squares.jq

View file

@ -0,0 +1,42 @@
'''Generic Utility Functions'''
# For inclusion using jq's `include` directive:
# Output: a PRN in range(0;$n) where $n is .
def prn:
if . == 1 then 0
else . as $n
| (($n-1)|tostring|length) as $w
| [limit($w; inputs)] | join("") | tonumber
| if . < $n then . else ($n | prn) end
end;
def knuthShuffle:
length as $n
| if $n <= 1 then .
else {i: $n, a: .}
| until(.i == 0;
.i += -1
| (.i + 1 | prn) as $j
| .a[.i] as $t
| .a[.i] = .a[$j]
| .a[$j] = $t)
| .a
end;
def lpad($len): tostring | ($len - length) as $l | (" " * $l)[:$l] + .;
# If the input array is not rectangular, let nulls fall where they may
def column($j):
[.[] | .[$j]];
# Emit a stream of [value, frequency] pairs
def histogram(stream):
reduce stream as $s ({};
($s|type) as $t
| (if $t == "string" then $s else ($s|tojson) end) as $y
| .[$t][$y][0] = $s
| .[$t][$y][1] += 1 )
| .[][] ;
def ss(s): reduce s as $x (0; . + ($x * $x));
def chiSquared($expected): ss( .[] - $expected ) / $expected;

View file

@ -0,0 +1,85 @@
# Include the utilities e.g. by
# include "random-latin-squares.utilities" {search: "."};
# Determine orthogonality of two arrays, confining attention
# to the first $n elements in each:
def orthogonal($a; $b; $n):
first( (range(0; $n) | if $a[.] == $b[.] then 0 else empty end) // 1) | . == 1;
# Are the two arrays orthogonal up to the length of the shorter?
def orthogonal($a; $b):
([$a, $b | length] | min) as $min
| orthogonal($a; $b; $min);
# Is row $i orthogonal to all the previous rows?
def orthogonal($i):
. as $in
| .[$i] as $row
| all(range(0;$i); orthogonal($row; $in[.]));
# verify columnwise orthogonality
def columnwise:
length as $n
| transpose as $t
| all( range(1;$n); . as $i | $t | orthogonal($i)) ;
def addLast:
(.[0] | length) as $n
| [range(0; $n)] as $range
| [range(0; $n) as $i
| ($range - column($i))[0] ] as $last
| . + [$last] ;
# input: an array being a permutation of [range(0;$n)] for some $n
# output: a Latin Square selected at random from all the candidates
def extend:
(.[0] | length) as $n
| if length >= $n then .
elif length == $n - 1 then addLast
else ([range(0; $n)] | knuthShuffle) as $row
| (. + [$row] )
| if orthogonal(length - 1) and columnwise then extend else empty end
end ;
# Generate a Latin Square.
# The input should be an integer specifying its size.
def latinSquare:
. as $n
| if $n <= 0 then []
else
[ [range(0; $n)] | knuthShuffle]
| first(repeat(extend))
# | (if columnwise then . else debug end) # internal check
end ;
# If the input is a positive integer, $n, generate and print an $n x $n Latin Square.
# If it is not number, echo it.
def printLatinSquare:
if type == "number"
then latinSquare
| .[] | map(lpad(3)) | join(" ")
else .
end;
# $order should be in 1 .. 5 inclusive
# If $n is null, then use 10 * $counts[$order]
def stats($order; $n):
# table of counts:
[0,1,2,12,576,161280] as $counts
| $counts[$order] as $possibilities
| (if $n then $n else 10 * $possibilities end) as $n
| reduce range(0;$n) as $i ({};
($order|latinSquare|flatten|join("")) as $row
| .[$row] += 1)
| # ([histogram(.[])] | sort[] | join(" ")),
"Number of LS(\($order)): \($n)",
(if length == $possibilities
then "All \($possibilities) possibilities have been generated."
else "Of \($possibilities) possibilities, only \(length) were generated."
end),
"Chi-squared statistic (df=\($possibilities-1)): \( [.[]] | chiSquared( $n / $possibilities))";
stats(3;null), "",
stats(4;5760), ""
stats(4;5760)

View file

@ -0,0 +1,62 @@
# Include the utilities e.g. by
# include "random-latin-squares.utilities" {search: "."};
# Select an element at random from [range(0;$n)] - column($j)
def candidate($j):
(.[0] | length) as $n
| [range(0;$n)] - column($j)
| .[length|prn];
# Input: the first row or rows of a Latin Square
def extend:
# The input to ext should be several rows of a Latin Square
# optionally followed by a candidate for an additional row.
def ext:
.[0] as $first
| length as $length
| ($first|length) as $n
| .[-1] as $last
| if ($last|length) < $n # then extend the last row
then ( ([range(0;$n)] - column($last|length)) - $last) as $candidates
| .[:$length-1] as $good
| ($candidates|length) as $cl
# if we can complete the row, then there is no need for another backtrack point!
| if $cl == 1 and ($last|length) == $n - 1
then ($good + [ $last + $candidates]) | ext # n.b. or use `extend` to speed things up at the cost of more bias
else
if $cl == 1 then ($good + [ $last + $candidates]) | ext
elif $cl == 0
then empty
else ($candidates[$cl | prn] as $add
| ($good + [$last + [$add]]) | ext)
end
end
elif length < $n then ((. + [[candidate(0)]]) | ext)
else .
end;
# If at first you do not succeed ...
first( repeat( ext ));
# Generate a Latin Square.
# The input should be an integer specifying its size.
def latinSquare:
. as $n
| if $n <= 0 then []
else
[ [range(0; $n)] | knuthShuffle]
| extend
end ;
# If the input is a positive integer, $n, generate and print an $n x $n Latin Square.
# Otherwise, simply echo it.
def printLatinSquare:
if type == "number"
then latinSquare
| .[] | map(lpad(3)) | join(" ")
else .
end;
"Five", 5, "\nFive", 5, "\nTen", 10, "\nForty", 40
| printLatinSquare
'

View file

@ -0,0 +1,31 @@
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)

View file

@ -0,0 +1,58 @@
typealias matrix = MutableList<MutableList<Int>>
fun printSquare(latin: matrix) {
for (row in latin) {
println(row)
}
println()
}
fun latinSquare(n: Int) {
if (n <= 0) {
println("[]")
return
}
val latin = MutableList(n) { MutableList(n) { it } }
// first row
latin[0].shuffle()
// middle row(s)
for (i in 1 until n - 1) {
var shuffled = false
shuffling@
while (!shuffled) {
latin[i].shuffle()
for (k in 0 until i) {
for (j in 0 until n) {
if (latin[k][j] == latin[i][j]) {
continue@shuffling
}
}
}
shuffled = true
}
}
// last row
for (j in 0 until n) {
val used = MutableList(n) { false }
for (i in 0 until n - 1) {
used[latin[i][j]] = true
}
for (k in 0 until n) {
if (!used[k]) {
latin[n - 1][j] = k
break
}
}
}
printSquare(latin)
}
fun main() {
latinSquare(5)
latinSquare(5)
latinSquare(10) // for good measure
}

View file

@ -0,0 +1,51 @@
Module FastLatinSquare {
n=5
For k=1 To 2
latin()
Next
n=40
latin()
Sub latin()
Local i,a, a(1 To n), b, k
Profiler
flush
Print "latin square ";n;" by ";n
For i=1 To n
Push i
Next i
For i=1 To n div 2
Shiftback random(2, n)
Next i
a=[]
Push ! stack(a)
a=array(a) ' change a from stack to array
For i=1 To n*10
Shiftback random(2, n)
Next i
For i=0 To n-1
Data number ' rotate by one the stack items
b=[] ' move stack To b, leave empty stack
a(a#val(i))=b
Push ! stack(b) ' Push from a copy of b all items To stack
Next i
flush
For k=1 To n div 2
z=random(2, n)
For i=1 To n
a=a(i)
stack a {
shift z
}
Next
Next
For i=1 To n
a=a(i)
a(i)=array(a) ' change To array from stack
Next i
For i=1 To n
Print a(i)
Next i
Print TimeCount
End Sub
}
FastLatinSquare

View file

@ -0,0 +1,73 @@
Module LatinSquare (n, z=1, f$="latin.dat", NewFile As Boolean=False) {
If Not Exist(f$) Or NewFile Then
Open f$ For Wide Output As f
Else
Open f$ For Wide Append As f
End If
ArrayToString=Lambda -> {
Shift 2 ' swap two top values in stack
Push Letter$+Str$(Number)
}
Dim line(1 to n)
flush ' erase current stack of value
z=if(z<1->1, z)
newColumn()
For j=1 To z
Profiler
ResetColumns()
For i=1 To n
placeColumn()
Next
Print "A latin square of ";n;" by ";n
For i=1 To n
Print line(i)
Print #f, line(i)#Fold$(ArrayToString)
Next
Print TimeCount
Refresh
Next
close #f
Flush ' empty stack again
End
Sub ResetColumns()
Local i
For i=1 To n:line(i)=(,):Next
End Sub
Sub newColumn()
Local i
For i=1 To n : Push i: Next
End Sub
Sub shuffle()
Local i
For i=1 To n div 2: Shift Random(2, n): Next
End Sub
Sub shuffleLocal(x)
If Stack.size<=x Then Exit Sub
Shift Random(x+1, Stack.size)
Shiftback x
End Sub
Sub PlaceColumn()
Local i, a, b, k
shuffle()
Do
data number ' rotate one position
k=0
For i=1 To n
a=line(i) ' get the pointer
Do
If a#Pos(Stackitem(i))=-1 Then k=0 :Exit Do
shuffleLocal(i)
k++
Until k>Stack.size-i
If k>0 Then Exit For
Next
Until k=0
For i=1 To n
a=line(i)
Append a, (Stackitem(i),)
Next
End Sub
}
Form 100,50
LatinSquare 5, 2, True
LatinSquare 16

View file

@ -0,0 +1,9 @@
Clear[RandomLatinSquare]
RandomLatinSquare[n_] := Module[{out, ord},
out = Table[RotateLeft[Range[n], i], {i, n}];
out = RandomSample[out];
ord = RandomSample[Range[n]];
out = out[[All, ord]];
out
]
RandomLatinSquare[5] // Grid

View file

@ -0,0 +1,44 @@
import random, sequtils, strutils
type LatinSquare = seq[seq[char]]
proc get[T](s: set[T]): T =
## Return the first element of a set.
for n in s:
return n
proc letterAt(n: Natural): char {.inline.} = chr(ord('A') - 1 + n)
proc latinSquare(n: Positive): LatinSquare =
result = newSeqWith(n, toSeq(letterAt(1)..letterAt(n)))
result[0].shuffle()
for row in 1..(n - 2):
var ok = false
while not ok:
block shuffling:
result[row].shuffle()
for prev in 0..<row:
for col in 0..<n:
if result[row][col] == result[prev][col]:
break shuffling
ok = true
for col in 0..<n:
var s = {letterAt(1)..letterAt(n)}
for row in 0..(n - 2):
s.excl result[row][col]
result[^1][col] = s.get()
proc `$`(s: LatinSquare): string =
let n = s.len
for row in 0..<n:
result.add s[row].join(" ") & '\n'
randomize()
echo latinSquare(5)
echo latinSquare(5)
echo latinSquare(10)

View file

@ -0,0 +1,138 @@
{$APPTYPE CONSOLE}
const
Alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
Type
IncidenceCube = Array of Array Of Array of Integer;
Var
Cube : IncidenceCube;
DIM : Integer;
Procedure InitIncidenceCube(Var c:IncidenceCube; const Size:Integer);
var i, j, k : integer;
begin
DIM := Size;
SetLength(c,DIM,DIM,DIM);
for i := 0 to DIM-1 do
for j := 0 to DIM-1 do
for k := 0 to DIM-1 do c[i,j,k] := 0 ;
for i := 0 to DIM-1 do
for j := 0 to DIM-1 do c[i,j,(i+j) mod DIM] := 1;
end;
Procedure FreeIncidenceCube(Var c:IncidenceCube);
begin
Finalize(c);
end;
procedure PrintIncidenceCube(var c:IncidenceCube);
var i, j, k : integer;
begin
for i := 0 to DIM-1 do begin
for j := 0 to DIM-1 do begin
for k := 0 to DIM-1 do begin
if (c[i,j,k]=1) then begin
write(Alpha[k+1],' ');
break;
end;
end;
end;
Writeln;
end;
Writeln;
WriteLn;
end;
procedure ShuffleIncidenceCube(var c:IncidenceCube);
var i, j, rx, ry, rz, ox, oy, oz : integer;
begin
for i := 0 to (DIM*DIM*DIM)-1 do begin
repeat
rx := Random(DIM);
ry := Random(DIM);
rz := Random(DIM);
until (c[rx,ry,rz]=0);
for j := 0 to DIM-1 do begin
if (c[j,ry,rz]=1) then ox := j;
if (c[rx,j,rz]=1) then oy := j;
if (c[rx,ry,j]=1) then oz := j;
end;
Inc(c[rx,ry,rz]);
Inc(c[rx,oy,oz]);
Inc(c[ox,ry,oz]);
Inc(c[ox,oy,rz]);
Dec(c[rx,ry,oz]);
Dec(c[rx,oy,rz]);
Dec(c[ox,ry,rz]);
Dec(c[ox,oy,oz]);
while (c[ox,oy,oz] < 0) do begin
rx := ox ;
ry := oy ;
rz := oz ;
if (random(2)=0) then begin
for j := 0 to DIM-1 do begin
if (c[j,ry,rz]=1) then ox := j;
end;
end else begin
for j := DIM-1 downto 0 do begin
if (c[j,ry,rz]=1) then ox := j;
end;
end;
if (random(2)=0) then begin
for j := 0 to DIM-1 do begin
if (c[rx,j,rz]=1) then oy := j;
end;
end else begin
for j := DIM-1 downto 0 do begin
if (c[rx,j,rz]=1) then oy := j;
end;
end;
if (random(2)=0) then begin
for j := 0 to DIM-1 do begin
if (c[rx,ry,j]=1) then oz := j;
end;
end else begin
for j := DIM-1 downto 0 do begin
if (c[rx,ry,j]=1) then oz := j;
end;
end;
Inc(c[rx,ry,rz]);
Inc(c[rx,oy,oz]);
Inc(c[ox,ry,oz]);
Inc(c[ox,oy,rz]);
Dec(c[rx,ry,oz]);
Dec(c[rx,oy,rz]);
Dec(c[ox,ry,rz]);
Dec(c[ox,oy,oz]);
end;
end;
end;
begin
Randomize;
InitIncidenceCube(cube, 5); ShuffleIncidenceCube(cube); PrintIncidenceCube(cube); FreeIncidenceCube(Cube);
InitIncidenceCube(cube, 5); ShuffleIncidenceCube(cube); PrintIncidenceCube(cube); FreeIncidenceCube(Cube);
InitIncidenceCube(cube,10); ShuffleIncidenceCube(cube); PrintIncidenceCube(cube); FreeIncidenceCube(Cube);
InitIncidenceCube(cube,26); ShuffleIncidenceCube(cube); PrintIncidenceCube(cube); FreeIncidenceCube(Cube);
end.

View file

@ -0,0 +1,33 @@
use strict;
use warnings;
use feature 'say';
use List::Util 'shuffle';
sub random_ls {
my($n) = @_;
my(@cols,@symbols,@ls_sym);
# build n-sized latin square
my @ls = [0,];
for my $i (1..$n-1) {
@{$ls[$i]} = @{$ls[0]};
splice(@{$ls[$_]}, $_, 0, $i) for 0..$i;
}
# shuffle rows and columns
@cols = shuffle 0..$n-1;
@ls = map [ @{$_}[@cols] ], @ls[shuffle 0..$n-1];
# replace numbers with symbols
@symbols = shuffle( ('A'..'Z')[0..$n-1] );
push @ls_sym, [@symbols[@$_]] for @ls;
@ls_sym
}
sub display {
my $str;
$str .= join(' ', @$_) . "\n" for @_;
$str
}
say display random_ls($_) for 2..5, 5;

View file

@ -0,0 +1,67 @@
(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">aleph</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">ls</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">></span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">aleph</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> <span style="color: #000080;font-style:italic;">-- too big...</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">t1</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()+</span><span style="color: #000000;">1</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">tn</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">tagset</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">),</span> <span style="color: #000080;font-style:italic;">-- {1..n}</span>
<span style="color: #000000;">vcs</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tn</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">),</span> <span style="color: #000080;font-style:italic;">-- valid for cols</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">clashes</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">while</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">)<</span><span style="color: #000000;">n</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">rn</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{},</span> <span style="color: #000080;font-style:italic;">-- next row</span>
<span style="color: #000000;">vr</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">tagset</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">),</span> <span style="color: #000080;font-style:italic;">-- valid for row (ie all)</span>
<span style="color: #000000;">vc</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">vcs</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- copy (in case of clash)</span>
<span style="color: #004080;">bool</span> <span style="color: #000000;">clash</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">n</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">v</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">n</span> <span style="color: #008080;">do</span>
<span style="color: #000080;font-style:italic;">-- collect all still valid options</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">vr</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">and</span> <span style="color: #000000;">vc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">c</span><span style="color: #0000FF;">][</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span> <span style="color: #000000;">v</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">k</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">={}</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">clash</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span>
<span style="color: #008080;">exit</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">z</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">))]</span>
<span style="color: #000000;">rn</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">z</span>
<span style="color: #000000;">vr</span><span style="color: #0000FF;">[</span><span style="color: #000000;">z</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span> <span style="color: #000080;font-style:italic;">-- no longer valid</span>
<span style="color: #000000;">vc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">c</span><span style="color: #0000FF;">][</span><span style="color: #000000;">z</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span> <span style="color: #000080;font-style:italic;">-- ""</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #000000;">clash</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">rn</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">vcs</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">vc</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">clashes</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()></span><span style="color: #000000;">t1</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"rows completed:%d/%d, clashes:%d\n"</span><span style="color: #0000FF;">,</span>
<span style="color: #0000FF;">{</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">),</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span><span style="color: #000000;">clashes</span><span style="color: #0000FF;">})</span>
<span style="color: #000000;">t1</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()+</span><span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">n</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">line</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">n</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">line</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">aleph</span><span style="color: #0000FF;">[</span><span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">line</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">latin_square</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">t0</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ls</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">),</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">e</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">elapsed</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">time</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">t0</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Latin square of order %d (%s):\n%s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span><span style="color: #000000;">e</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #000000;">latin_square</span><span style="color: #0000FF;">(</span><span style="color: #000000;">3</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">latin_square</span><span style="color: #0000FF;">(</span><span style="color: #000000;">5</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">latin_square</span><span style="color: #0000FF;">(</span><span style="color: #000000;">5</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">latin_square</span><span style="color: #0000FF;">(</span><span style="color: #000000;">10</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()!=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">latin_square</span><span style="color: #0000FF;">(</span><span style="color: #000000;">42</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<!--

View file

@ -0,0 +1,36 @@
main =>
_ = random2(), % random seed
N = 5,
foreach(_ in 1..2)
latin_square(N, X),
pretty_print(X)
end,
% A larger random instance
latin_square(62,X),
pretty_print(X).
% Latin square
latin_square(N, X) =>
X = new_array(N,N),
X :: 1..N,
foreach(I in 1..N)
all_different([X[I,J] : J in 1..N]),
all_different([X[J,I] : J in 1..N])
end,
% rand_val for randomness
solve($[ff,rand_val],X).
pretty_print(X) =>
N = X.len,
Alpha = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
foreach(I in 1..N)
foreach(J in 1..N)
if N > 20 then
printf("%w",Alpha[X[I,J]])
else
printf("%2w ",X[I,J])
end
end,
nl
end,
nl.

View file

@ -0,0 +1,5 @@
main =>
foreach(N in 1..6)
Count = count_all(latin_square(N,_)),
println(N=Count)
end.

View file

@ -0,0 +1,61 @@
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()

View file

@ -0,0 +1,20 @@
[ [] []
rot times
[ i join ]
dup size times
[ tuck
nested join
swap
behead join ]
drop
shuffle
transpose
shuffle ] is rls ( n --> [ )
2 times
[ 5 rls
witheach
[ witheach
[ echo sp ]
cr ]
cr ]

View file

@ -0,0 +1,16 @@
/*REXX program generates and displays a randomized Latin square. */
parse arg N seed . /*obtain the optional argument from CL.*/
if N=='' | N=="," then N= 5 /*Not specified? Then use the default.*/
if datatype(seed, 'W') then call random ,,seed /*Seed numeric? Then use it for seed.*/
w= length(N - 1) /*get the length of the largest number.*/
$= /*initialize $ string to null. */
do i=0 for N; $= $ right(i, w, '_') /*build a string of numbers (from zero)*/
end /*i*/ /* [↑] $ string is (so far) in order.*/
z= /*Z: will be the 1st row of the square*/
do N; ?= random(1,words($)) /*gen a random number from the $ string*/
z= z word($, ?); $= delword($, ?, 1) /*add the number to string; del from $.*/
end /*r*/
zz= z||z /*build a double-length string of Z. */
do j=1 for N /* [↓] display rows of random Latin sq*/
say translate(subword(zz, j, N), , '_') /*translate leading underbar to blank. */
end /*j*/ /*stick a fork in it, we're all done. */

View file

@ -0,0 +1,35 @@
sub latin-square { [[0],] };
sub random ( @ls, :$size = 5 ) {
# Build
for 1 ..^ $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 = ('A' .. 'Z').pick($size);
@ls.deepmap: { $_ = @symbols[$_] };
}
sub display ( @array ) { $_.fmt("%2s ").put for |@array, '' }
# The Task
# Default size 5
display random latin-square;
# Specified size
display random :size($_), latin-square for 5, 3, 9;
# Or, if you'd prefer:
display random latin-square, :size($_) for 12, 2, 1;

View file

@ -0,0 +1,344 @@
load "stdlib.ring"
load "guilib.ring"
###====================================================================================
size = 10
time1 = 0
bwidth = 0
bheight = 0
a2DSquare = newlist(size,size)
a2DFinal = newlist(size,size)
aList = 1:size
aList2 = RandomList(aList)
GenerateRows(aList2)
ShuffleCols(a2DSquare, a2DFinal)
C_SPACING = 1
Button = newlist(size,size)
LayoutButtonRow = list(size)
C_ButtonOrangeStyle = 'border-radius:1x;color:black; background-color: orange'
###====================================================================================
MyApp = New qApp {
StyleFusion()
win = new qWidget() {
workHeight = win.height()
fontSize = 8 + (300/size)
wwidth = win.width()
wheight = win.height()
bwidth = wwidth/size
bheight = wheight/size
setwindowtitle("Random Latin Squares")
move(555,0)
setfixedsize(1000,1000)
myfilter = new qallevents(win)
myfilter.setResizeEvent("resizeBoard()")
installeventfilter(myfilter)
LayoutButtonMain = new QVBoxLayout() {
setSpacing(C_SPACING)
setContentsmargins(50,50,50,50)
}
LayoutButtonStart = new QHBoxLayout() {
setSpacing(C_SPACING)
setContentsmargins(0,0,0,0)
}
btnStart = new qPushButton(win) {
setFont(new qFont("Calibri",fontsize,2100,0))
resize(bwidth,bheight)
settext(" Start ")
setstylesheet(C_ButtonOrangeStyle)
setclickevent("gameSolution()")
}
sizeBtn = new qlabel(win)
{
setFont(new qFont("Calibri",fontsize,2100,0))
resize(bwidth,bheight)
setStyleSheet("background-color:rgb(255,255,204)")
setText(" Size: ")
}
lineSize = new qLineEdit(win)
{
setFont(new qFont("Calibri",fontsize,2100,0))
resize(bwidth,bheight)
setStyleSheet("background-color:rgb(255,255,204)")
setAlignment( Qt_AlignHCenter)
setAlignment( Qt_AlignVCenter)
setreturnPressedEvent("newBoardSize()")
setText(string(size))
}
btnExit = new qPushButton(win) {
setFont(new qFont("Calibri",fontsize,2100,0))
resize(bwidth,bheight)
settext(" Exit ")
setstylesheet(C_ButtonOrangeStyle)
setclickevent("pExit()")
}
LayoutButtonStart.AddWidget(btnStart)
LayoutButtonStart.AddWidget(sizeBtn)
LayoutButtonStart.AddWidget(lineSize)
LayoutButtonStart.AddWidget(btnExit)
LayoutButtonMain.AddLayout(LayoutButtonStart)
for Row = 1 to size
LayoutButtonRow[Row] = new QHBoxLayout() {
setSpacing(C_SPACING)
setContentsmargins(0,0,0,0)
}
for Col = 1 to size
Button[Row][Col] = new qlabel(win) {
setFont(new qFont("Calibri",fontsize,2100,0))
resize(bwidth,bheight)
}
LayoutButtonRow[Row].AddWidget(Button[Row][Col])
next
LayoutButtonMain.AddLayout(LayoutButtonRow[Row])
next
setLayout(LayoutButtonMain)
show()
}
exec()
}
###====================================================================================
func newBoardSize()
nrSize = number(lineSize.text())
if nrSize = 1
? "Enter: Size > 1"
return
ok
for Row = 1 to size
for Col = 1 to size
Button[Row][Col].settext("")
next
next
newWindow(nrSize)
###====================================================================================
func newWindow(newSize)
time1 = clock()
for Row = 1 to size
for Col = 1 to size
Button[Row][Col].delete()
next
next
size = newSize
bwidth = ceil((win.width() - 8) / size)
bheight = ceil((win.height() - 32) / size)
fontSize = 8 + (300/size)
if size > 16
fontSize = 8 + (150/size)
ok
if size < 8
fontSize = 30 + (150/size)
ok
if size = 2
fontSize = 10 + (100/size)
ok
btnStart.setFont(new qFont("Calibri",fontsize,2100,0))
sizeBtn.setFont(new qFont("Calibri",fontsize,2100,0))
lineSize.setFont(new qFont("Calibri",fontsize,2100,0))
btnExit.setFont(new qFont("Calibri",fontsize,2100,0))
LayoutButtonStart = new QHBoxLayout() {
setSpacing(C_SPACING)
setContentsmargins(0,0,0,0)
}
Button = newlist(size,size)
LayoutButtonRow = list(size)
for Row = 1 to size
LayoutButtonRow[Row] = new QHBoxLayout() {
setSpacing(C_SPACING)
setContentsmargins(0,0,0,0)
}
for Col = 1 to size
Button[Row][Col] = new qlabel(win) {
setFont(new qFont("Calibri",fontsize,2100,0))
resize(bwidth,bheight)
}
LayoutButtonRow[Row].AddWidget(Button[Row][Col])
next
LayoutButtonMain.AddLayout(LayoutButtonRow[Row])
next
win.setLayout(LayoutButtonMain)
return
###====================================================================================
func resizeBoard
bwidth = ceil((win.width() - 8) / size)
bheight = ceil((win.height() - 32) / size)
for Row = 1 to size
for Col = 1 to size
Button[Row][Col].resize(bwidth,bheight)
next
next
###====================================================================================
Func pExit
MyApp.quit()
###====================================================================================
func gameSolution()
a2DSquare = newlist(size,size)
a2DFinal = newlist(size,size)
aList = 1:size
aList2 = RandomList(aList)
GenerateRows(aList2)
ShuffleCols(a2DSquare, a2DFinal)
for nRow = 1 to size
for nCol = 1 to size
Button[nRow][nCol].settext("-")
next
next
for nRow = 1 to size
for nCol = 1 to size
Button[nRow][nCol].resize(bwidth,bheight)
Button[nRow][nCol].settext(string(a2DSquare[nRow][nCol]))
next
next
time2 = clock()
time3 = (time2 - time1)/1000
? "Elapsed time: " + time3 + " ms at size = " + size + nl
###====================================================================================
// Scramble the numbers in the List
// Uniq random picks, then shorten list by each pick
Func RandomList(aInput)
aOutput = []
while len(aInput) > 1
nIndex = random(len(aInput)-1)
nIndex++
aOutput + aInput[nIndex]
del(aInput,nIndex)
end
aOutput + aInput[1]
return aOutput
###====================================================================================
// Generate Rows of data. Put them in the 2DArray
Func GenerateRows(aInput)
aOutput = []
size = len(aInput)
shift = 1
for k = 1 to size // Make 8 Rows of lists
aOutput = []
for i = 1 to size // make a list
pick = i + shift // shift every Row by +1 more
if pick > size pick = pick - size ok
aOutput + aInput[pick]
next
a2DSquare[k] = aOutput // Row of Output to a2DSquare
shift++ // shift next line by +1 more
if shift > size shift = 1 ok
next
return
###====================================================================================
// Shift random Rows into a2DFinal, then random Cols
Func ShuffleCols(a2DSquare, a2DFinal)
aSuffle = 1:size
aSuffle2 = RandomList(aSuffle) // Pick random Col to insert in a2DFinal
for i = 1 to size // Row
pick = aSuffle2[i]
for j = 1 to size // Col
a2DFinal[i][j] = a2DSquare[pick][j] // i-Row-Col j-Horz-Vert
next
next
a2DSquare = a2DFinal // Now do the verticals
aSuffle = 1:size
aSuffle2 = RandomList(aSuffle)
for i = 1 to size // Row
pick = aSuffle2[i]
for j = 1 to size // Col
a2DFinal[j][i] = a2DSquare[j][pick] //Reverse i-j , i-Row-Col j-Horz-Vert
next
next
return
###====================================================================================

View file

@ -0,0 +1,19 @@
N = 5
def generate_square
perms = (1..N).to_a.permutation(N).to_a.shuffle
square = []
N.times do
square << perms.pop
perms.reject!{|perm| perm.zip(square.last).any?{|el1, el2| el1 == el2} }
end
square
end
def print_square(square)
cell_size = N.digits.size + 1
strings = square.map!{|row| row.map!{|el| el.to_s.rjust(cell_size)}.join }
puts strings, "\n"
end
2.times{print_square( generate_square)}

View file

@ -0,0 +1,60 @@
import "random" for Random
var rand = Random.new()
var printSquare = Fn.new { |latin|
for (row in latin) System.print(row)
System.print()
}
var latinSquare = Fn.new { |n|
if (n <= 0) {
System.print("[]\n")
return
}
var latin = List.filled(n, null)
for (i in 0...n) {
latin[i] = List.filled(n, 0)
if (i == n - 1) break
for (j in 0...n) latin[i][j] = j
}
// first row
rand.shuffle(latin[0])
// middle row(s)
for (i in 1...n-1) {
var shuffled = false
while (!shuffled) {
rand.shuffle(latin[i])
var shuffling = false
for (k in 0...i) {
for (j in 0...n) {
if (latin[k][j] == latin[i][j]) {
shuffling = true
break
}
}
if (shuffling) break
}
if (!shuffling) shuffled = true
}
}
// last row
for (j in 0...n) {
var used = List.filled(n, false)
for (i in 0...n-1) used[latin[i][j]] = true
for (k in 0...n) {
if (!used[k]) {
latin[n-1][j] = k
break
}
}
}
printSquare.call(latin)
}
latinSquare.call(5)
latinSquare.call(5)
latinSquare.call(10) // for good measure

View file

@ -0,0 +1,216 @@
import "random" for Random
import "/sort" for Sort
import "/fmt" for Fmt
import "/math" for Int
var rand = Random.new()
var counts = List.filled(4, 0)
var aa = List.filled(16, 0)
var testSquares = [
[0, 1, 2, 3, 1, 0, 3, 2, 2, 3, 0, 1, 3, 2, 1, 0],
[0, 1, 2, 3, 1, 0, 3, 2, 2, 3, 1, 0, 3, 2, 0, 1],
[0, 1, 2, 3, 1, 2, 3, 0, 2, 3, 0, 1, 3, 0, 1, 2],
[0, 1, 2, 3, 1, 3, 0, 2, 2, 0, 3, 1, 3, 2, 1, 0]
]
// Checks whether two lists contain the same elements in the same order
var areSame = Fn.new { |l1, l2|
if (l1.count != l2.count) return false
for (i in 0...l1.count) {
if (l1[i] != l2[i]) return false
}
return true
}
// generate derangements of first n numbers, with 'start' in first place.
var dList = Fn.new { |n, start|
var r = []
start = start - 1 // use 0 basing
var a = List.filled(n, 0)
for (i in 0...n) a[i] = i
var t = a[0]
a[0] = start
a[start] = t
Sort.quick(a, 1, a.count-1, null)
var first = a[1]
var recurse // recursive closure permutes a[1..-1]
recurse = Fn.new { |last|
if (last == first) {
// bottom of recursion. you get here once for each permutation.
// test if permutation is deranged.
var j = 0 // j starts from 0, not 1
for (v in a.skip(1)) {
if (j+1 == v) return r // no, ignore it
j = j + 1
}
// yes, save a copy
var b = a.toList
for (i in 0...b.count) b[i] = b[i] + 1 // change back to 1 basing
r.add(b)
return r
}
var i = last
while (i >= 1) {
a.swap(i, last)
recurse.call(last - 1)
a.swap(i, last)
i = i - 1
}
}
recurse.call(n - 1)
return r
}
var copyMatrix = Fn.new { |m|
var le = m.count
var cpy = List.filled(le, null)
for (i in 0...le) cpy[i] = m[i].toList
return cpy
}
var reducedLatinSquares = Fn.new { |n|
var rls = []
if (n < 0) n = 0
var rlatin = List.filled(n, null)
for (i in 0...n) rlatin[i] = List.filled(n, 0)
if (n <= 1) {
rls.add(rlatin)
return rls
}
// first row
for (j in 0...n) rlatin[0][j] = j + 1
// recursive closure to compute reduced latin squares
var recurse
recurse = Fn.new { |i|
var rows = dList.call(n, i) // get derangements of first n numbers, with 'i' first.
for (r in 0...rows.count) {
var outer = false
rlatin[i-1] = rows[r].toList
for (k in 0...i-1) {
for (j in 1...n) {
if (rlatin[k][j] == rlatin[i-1][j]) {
if (r < rows.count-1) {
outer = true
break
} else if (i > 2) {
return
}
}
}
if (outer) break
}
if (outer) continue
if (i < n) {
recurse.call(i + 1)
} else {
var rl = copyMatrix.call(rlatin)
rls.add(rl)
}
}
return
}
// remaining rows
recurse.call(2)
return rls
}
var printSquare = Fn.new { |latin, n|
for (i in 0...n) {
for (j in 0...n) Fmt.write("$d ", latin[i][j]-1)
System.print()
}
System.print()
}
// generate permutations of first n numbers, starting from 0.
var pList = Fn.new { |n|
var fact = Int.factorial(n)
var perms = List.filled(fact, null)
var a = List.filled(n, 0)
for (i in 0...n) a[i] = i
var t = a.toList
perms[0] = t
n = n - 1
for (c in 1...fact) {
var i = n - 1
var j = n
while (a[i] > a[i+1]) i = i - 1
while (a[j] < a[i]) j = j - 1
a.swap(i, j)
j = n
i = i + 1
while (i < j) {
a.swap(i, j)
i = i + 1
j = j - 1
}
var t = a.toList
t.add(0)
perms[c] = t
}
return perms
}
var generateLatinSquares = Fn.new { |n, tests, echo|
var rls = reducedLatinSquares.call(n)
var perms = pList.call(n)
var perms2 = pList.call(n - 1)
for (test in 0...tests) {
var rn = rand.int(rls.count)
var rl = rls[rn] // select reduced random square at random
rn = rand.int(perms.count)
var rp = perms[rn] // select a random permuation of 'rl's columns
// permute columns
var t = List.filled(n, null)
for (i in 0...n) {
t[i] = List.filled(n, 0)
for (j in 0...n) t[i][j] = rl[i][rp[j]]
}
rn = rand.int(perms2.count)
rp = perms2[rn] // select a random permutation of 't's rows 2 to n
// permute rows 2 to n
var u = List.filled(n, null)
for (i in 0...n) {
u[i] = List.filled(n, 0)
for (j in 0...n) {
if (i == 0) {
u[i][j] = t[i][j]
} else {
u[i][j] = t[rp[i-1]+1][j]
}
}
}
if (test < echo) printSquare.call(u, n)
if (n == 4) {
for (i in 0..3) {
for (j in 0..3) u[i][j] = u[i][j] - 1
}
for (i in 0..3) {
for (j in 4*i...4*i+4) {
aa[j] = u[i][j - 4*i]
}
}
for (i in 0..3) {
if (areSame.call(testSquares[i], aa)) {
counts[i] = counts[i] + 1
break
}
}
}
}
}
System.print("Two randomly generated latin squares of order 5 are:\n")
generateLatinSquares.call(5, 2, 2)
System.print("Out of 1,000,000 randomly generated latin squares of order 4, ")
System.print("of which there are 576 instances ( => expected 1736 per instance),")
System.print("the following squares occurred the number of times shown:\n")
generateLatinSquares.call(4, 1e6, 0)
for (i in 0..3) System.print("%(testSquares[i]) : %(counts[i])")
System.print("\nA randomly generated latin square of order 6 is:\n")
generateLatinSquares.call(6, 1, 1)

View file

@ -0,0 +1,8 @@
fcn randomLatinSquare(n,symbols=[1..]){ //--> list of lists
if(n<=0) return(T);
square,syms := List(), symbols.walker().walk(n);
do(n){ syms=syms.copy(); square.append(syms.append(syms.pop(0))) }
// shuffle rows, transpose & shuffle columns
T.zip(square.shuffle().xplode()).shuffle();
}
fcn rls2String(square){ square.apply("concat"," ").concat("\n") }

View file

@ -0,0 +1,3 @@
foreach n in (T(1,2,5)){ randomLatinSquare(n) : rls2String(_).println("\n") }
randomLatinSquare(5, ["A".."Z"]) : rls2String(_).println("\n");
randomLatinSquare(10,"!@#$%^&*()") : rls2String(_).println("\n");