Latin Squares¶
A latin square of order \(n\) is an \(n \times n\) array such that each symbol \(s \in \{ 0, 1, \dots, n-1\}\) appears precisely once in each row, and precisely once in each column. A partial latin square of order \(n\) is an \(n \times n\) array such that each symbol \(s \in \{ 0, 1, \dots, n-1\}\) appears at most once in each row, and at most once in each column. Empty cells are denoted by \(-1\). A latin square \(L\) is a completion of a partial latin square \(P\) if \(P \subseteq L\). If \(P\) completes to just \(L\) then \(P\) has unique completion.
A latin bitrade \((T_1,\, T_2)\) is a pair of partial latin squares such that:
- \(\{ (i,\,j) \mid (i,\,j,\,k) \in T_1 \text{ for some symbol }k \} = \{ (i,\,j) \mid (i,\,j,\,k') \in T_2 \text{ for some symbol }k' \};\) 
- for each \((i,\,j,\,k) \in T_1\) and \((i,\,j,\,k') \in T_2\), \(k \neq k'\); 
- the symbols appearing in row \(i\) of \(T_1\) are the same as those of row \(i\) of \(T_2\); the symbols appearing in column \(j\) of \(T_1\) are the same as those of column \(j\) of \(T_2\). 
Intuitively speaking, a bitrade gives the difference between two latin squares, so if \((T_1,\, T_2)\) is a bitrade for the pair of latin squares \((L_1,\, L_2)\), then \(L1 = (L2 \setminus T_1) \cup T_2\) and \(L2 = (L1 \setminus T_2) \cup T_1\).
This file contains
- LatinSquare class definition; 
- some named latin squares (back circulant, forward circulant, abelian \(2\)-group); 
- methods - is_partial_latin_square()and- is_latin_square()to test if a- LatinSquareobject satisfies the definition of a latin square or partial latin square, respectively;
- tests for completion and unique completion (these use the C++ implementation of Knuth’s dancing links algorithm to solve the problem as a instance of \(0-1\) matrix exact cover); 
- functions for calculating the \(\tau_i\) representation of a bitrade and the genus of the associated hypermap embedding; 
- Markov chain of Jacobson and Matthews (1996) for generating latin squares uniformly at random (provides a generator interface); 
- a few examples of \(\tau_i\) representations of bitrades constructed from the action of a group on itself by right multiplication, functions for converting to a pair of - LatinSquareobjects.
EXAMPLES:
sage: from sage.combinat.matrices.latin import *
sage: B = back_circulant(5)
sage: B
[0 1 2 3 4]
[1 2 3 4 0]
[2 3 4 0 1]
[3 4 0 1 2]
[4 0 1 2 3]
sage: B.is_latin_square()
True
sage: B[0, 1] = 0
sage: B.is_latin_square()
False
sage: (a, b, c, G) = alternating_group_bitrade_generators(1)
sage: (T1, T2) = bitrade_from_group(a, b, c, G)
sage: T1
[ 0 -1  3  1]
[-1  1  0  2]
[ 1  3  2 -1]
[ 2  0 -1  3]
sage: T2
[ 1 -1  0  3]
[-1  0  2  1]
[ 2  1  3 -1]
[ 0  3 -1  2]
sage: T1.nr_filled_cells()
12
sage: genus(T1, T2)
1
>>> from sage.all import *
>>> from sage.combinat.matrices.latin import *
>>> B = back_circulant(Integer(5))
>>> B
[0 1 2 3 4]
[1 2 3 4 0]
[2 3 4 0 1]
[3 4 0 1 2]
[4 0 1 2 3]
>>> B.is_latin_square()
True
>>> B[Integer(0), Integer(1)] = Integer(0)
>>> B.is_latin_square()
False
>>> (a, b, c, G) = alternating_group_bitrade_generators(Integer(1))
>>> (T1, T2) = bitrade_from_group(a, b, c, G)
>>> T1
[ 0 -1  3  1]
[-1  1  0  2]
[ 1  3  2 -1]
[ 2  0 -1  3]
>>> T2
[ 1 -1  0  3]
[-1  0  2  1]
[ 2  1  3 -1]
[ 0  3 -1  2]
>>> T1.nr_filled_cells()
12
>>> genus(T1, T2)
1
Todo
- Latin squares with symbols from a ring instead of the integers \(\{ 0, 1, \dots, n-1 \}\). 
- Isotopism testing of latin squares and bitrades via graph isomorphism (nauty?). 
- Combinatorial constructions for bitrades. 
AUTHORS:
- Carlo Hamalainen (2008-03-23): initial version 
- class sage.combinat.matrices.latin.LatinSquare(*args)[source]¶
- Bases: - object- Latin squares. - This class implements a latin square of order n with rows and columns indexed by the set 0, 1, …, n-1 and symbols from the same set. The underlying latin square is a matrix(ZZ, n, n). If L is a latin square, then the cell at row r, column c is empty if and only if L[r, c] < 0. In this way we allow partial latin squares and can speak of completions to latin squares, etc. - There are two ways to declare a latin square: - Empty latin square of order n: - sage: n = 3 sage: L = LatinSquare(n) sage: L [-1 -1 -1] [-1 -1 -1] [-1 -1 -1] - >>> from sage.all import * >>> n = Integer(3) >>> L = LatinSquare(n) >>> L [-1 -1 -1] [-1 -1 -1] [-1 -1 -1] - Latin square from a matrix: - sage: M = matrix(ZZ, [[0, 1], [2, 3]]) sage: LatinSquare(M) [0 1] [2 3] - >>> from sage.all import * >>> M = matrix(ZZ, [[Integer(0), Integer(1)], [Integer(2), Integer(3)]]) >>> LatinSquare(M) [0 1] [2 3] - actual_row_col_sym_sizes()[source]¶
- Bitrades sometimes end up in partial latin squares with unused rows, columns, or symbols. This function works out the actual number of used rows, columns, and symbols. - Warning - We assume that the unused rows/columns occur in the lower right of self, and that the used symbols are in the range {0, 1, …, m} (no holes in that list). - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: B = back_circulant(3) sage: B[0,2] = B[1,2] = B[2,2] = -1 sage: B[0,0] = B[2,1] = -1 sage: B [-1 1 -1] [ 1 2 -1] [ 2 -1 -1] sage: B.actual_row_col_sym_sizes() (3, 2, 2) - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> B = back_circulant(Integer(3)) >>> B[Integer(0),Integer(2)] = B[Integer(1),Integer(2)] = B[Integer(2),Integer(2)] = -Integer(1) >>> B[Integer(0),Integer(0)] = B[Integer(2),Integer(1)] = -Integer(1) >>> B [-1 1 -1] [ 1 2 -1] [ 2 -1 -1] >>> B.actual_row_col_sym_sizes() (3, 2, 2) 
 - apply_isotopism(row_perm, col_perm, sym_perm)[source]¶
- An isotopism is a permutation of the rows, columns, and symbols of a partial latin square - self. Use isotopism() to convert a tuple (indexed from 0) to a Permutation object.- EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: B = back_circulant(5) sage: B [0 1 2 3 4] [1 2 3 4 0] [2 3 4 0 1] [3 4 0 1 2] [4 0 1 2 3] sage: alpha = isotopism((0,1,2,3,4)) sage: beta = isotopism((1,0,2,3,4)) sage: gamma = isotopism((2,1,0,3,4)) sage: B.apply_isotopism(alpha, beta, gamma) [3 4 2 0 1] [0 2 3 1 4] [1 3 0 4 2] [4 0 1 2 3] [2 1 4 3 0] - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> B = back_circulant(Integer(5)) >>> B [0 1 2 3 4] [1 2 3 4 0] [2 3 4 0 1] [3 4 0 1 2] [4 0 1 2 3] >>> alpha = isotopism((Integer(0),Integer(1),Integer(2),Integer(3),Integer(4))) >>> beta = isotopism((Integer(1),Integer(0),Integer(2),Integer(3),Integer(4))) >>> gamma = isotopism((Integer(2),Integer(1),Integer(0),Integer(3),Integer(4))) >>> B.apply_isotopism(alpha, beta, gamma) [3 4 2 0 1] [0 2 3 1 4] [1 3 0 4 2] [4 0 1 2 3] [2 1 4 3 0] 
 - clear_cells()[source]¶
- Mark every cell in - selfas being empty.- EXAMPLES: - sage: A = LatinSquare(matrix(ZZ, [[0, 1], [2, 3]])) sage: A.clear_cells() sage: A [-1 -1] [-1 -1] - >>> from sage.all import * >>> A = LatinSquare(matrix(ZZ, [[Integer(0), Integer(1)], [Integer(2), Integer(3)]])) >>> A.clear_cells() >>> A [-1 -1] [-1 -1] 
 - column(x)[source]¶
- Return column x of the latin square. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: back_circulant(3).column(0) (0, 1, 2) - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> back_circulant(Integer(3)).column(Integer(0)) (0, 1, 2) 
 - contained_in(Q)[source]¶
- Return - Trueif- selfis a subset of \(Q\).- EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: P = elementary_abelian_2group(2) sage: P[0, 0] = -1 sage: P.contained_in(elementary_abelian_2group(2)) True sage: back_circulant(4).contained_in(elementary_abelian_2group(2)) False - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> P = elementary_abelian_2group(Integer(2)) >>> P[Integer(0), Integer(0)] = -Integer(1) >>> P.contained_in(elementary_abelian_2group(Integer(2))) True >>> back_circulant(Integer(4)).contained_in(elementary_abelian_2group(Integer(2))) False 
 - disjoint_mate_dlxcpp_rows_and_map(allow_subtrade)[source]¶
- Internal function for find_disjoint_mates. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: B = back_circulant(4) sage: B.disjoint_mate_dlxcpp_rows_and_map(allow_subtrade = True) ([[0, 16, 32], [1, 17, 32], [2, 18, 32], [3, 19, 32], [4, 16, 33], [5, 17, 33], [6, 18, 33], [7, 19, 33], [8, 16, 34], [9, 17, 34], [10, 18, 34], [11, 19, 34], [12, 16, 35], [13, 17, 35], [14, 18, 35], [15, 19, 35], [0, 20, 36], [1, 21, 36], [2, 22, 36], [3, 23, 36], [4, 20, 37], [5, 21, 37], [6, 22, 37], [7, 23, 37], [8, 20, 38], [9, 21, 38], [10, 22, 38], [11, 23, 38], [12, 20, 39], [13, 21, 39], [14, 22, 39], [15, 23, 39], [0, 24, 40], [1, 25, 40], [2, 26, 40], [3, 27, 40], [4, 24, 41], [5, 25, 41], [6, 26, 41], [7, 27, 41], [8, 24, 42], [9, 25, 42], [10, 26, 42], [11, 27, 42], [12, 24, 43], [13, 25, 43], [14, 26, 43], [15, 27, 43], [0, 28, 44], [1, 29, 44], [2, 30, 44], [3, 31, 44], [4, 28, 45], [5, 29, 45], [6, 30, 45], [7, 31, 45], [8, 28, 46], [9, 29, 46], [10, 30, 46], [11, 31, 46], [12, 28, 47], [13, 29, 47], [14, 30, 47], [15, 31, 47]], {(0, 16, 32): (0, 0, 0), (0, 20, 36): (1, 0, 0), (0, 24, 40): (2, 0, 0), (0, 28, 44): (3, 0, 0), (1, 17, 32): (0, 0, 1), (1, 21, 36): (1, 0, 1), (1, 25, 40): (2, 0, 1), (1, 29, 44): (3, 0, 1), (2, 18, 32): (0, 0, 2), (2, 22, 36): (1, 0, 2), (2, 26, 40): (2, 0, 2), (2, 30, 44): (3, 0, 2), (3, 19, 32): (0, 0, 3), (3, 23, 36): (1, 0, 3), (3, 27, 40): (2, 0, 3), (3, 31, 44): (3, 0, 3), (4, 16, 33): (0, 1, 0), (4, 20, 37): (1, 1, 0), (4, 24, 41): (2, 1, 0), (4, 28, 45): (3, 1, 0), (5, 17, 33): (0, 1, 1), (5, 21, 37): (1, 1, 1), (5, 25, 41): (2, 1, 1), (5, 29, 45): (3, 1, 1), (6, 18, 33): (0, 1, 2), (6, 22, 37): (1, 1, 2), (6, 26, 41): (2, 1, 2), (6, 30, 45): (3, 1, 2), (7, 19, 33): (0, 1, 3), (7, 23, 37): (1, 1, 3), (7, 27, 41): (2, 1, 3), (7, 31, 45): (3, 1, 3), (8, 16, 34): (0, 2, 0), (8, 20, 38): (1, 2, 0), (8, 24, 42): (2, 2, 0), (8, 28, 46): (3, 2, 0), (9, 17, 34): (0, 2, 1), (9, 21, 38): (1, 2, 1), (9, 25, 42): (2, 2, 1), (9, 29, 46): (3, 2, 1), (10, 18, 34): (0, 2, 2), (10, 22, 38): (1, 2, 2), (10, 26, 42): (2, 2, 2), (10, 30, 46): (3, 2, 2), (11, 19, 34): (0, 2, 3), (11, 23, 38): (1, 2, 3), (11, 27, 42): (2, 2, 3), (11, 31, 46): (3, 2, 3), (12, 16, 35): (0, 3, 0), (12, 20, 39): (1, 3, 0), (12, 24, 43): (2, 3, 0), (12, 28, 47): (3, 3, 0), (13, 17, 35): (0, 3, 1), (13, 21, 39): (1, 3, 1), (13, 25, 43): (2, 3, 1), (13, 29, 47): (3, 3, 1), (14, 18, 35): (0, 3, 2), (14, 22, 39): (1, 3, 2), (14, 26, 43): (2, 3, 2), (14, 30, 47): (3, 3, 2), (15, 19, 35): (0, 3, 3), (15, 23, 39): (1, 3, 3), (15, 27, 43): (2, 3, 3), (15, 31, 47): (3, 3, 3)}) - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> B = back_circulant(Integer(4)) >>> B.disjoint_mate_dlxcpp_rows_and_map(allow_subtrade = True) ([[0, 16, 32], [1, 17, 32], [2, 18, 32], [3, 19, 32], [4, 16, 33], [5, 17, 33], [6, 18, 33], [7, 19, 33], [8, 16, 34], [9, 17, 34], [10, 18, 34], [11, 19, 34], [12, 16, 35], [13, 17, 35], [14, 18, 35], [15, 19, 35], [0, 20, 36], [1, 21, 36], [2, 22, 36], [3, 23, 36], [4, 20, 37], [5, 21, 37], [6, 22, 37], [7, 23, 37], [8, 20, 38], [9, 21, 38], [10, 22, 38], [11, 23, 38], [12, 20, 39], [13, 21, 39], [14, 22, 39], [15, 23, 39], [0, 24, 40], [1, 25, 40], [2, 26, 40], [3, 27, 40], [4, 24, 41], [5, 25, 41], [6, 26, 41], [7, 27, 41], [8, 24, 42], [9, 25, 42], [10, 26, 42], [11, 27, 42], [12, 24, 43], [13, 25, 43], [14, 26, 43], [15, 27, 43], [0, 28, 44], [1, 29, 44], [2, 30, 44], [3, 31, 44], [4, 28, 45], [5, 29, 45], [6, 30, 45], [7, 31, 45], [8, 28, 46], [9, 29, 46], [10, 30, 46], [11, 31, 46], [12, 28, 47], [13, 29, 47], [14, 30, 47], [15, 31, 47]], {(0, 16, 32): (0, 0, 0), (0, 20, 36): (1, 0, 0), (0, 24, 40): (2, 0, 0), (0, 28, 44): (3, 0, 0), (1, 17, 32): (0, 0, 1), (1, 21, 36): (1, 0, 1), (1, 25, 40): (2, 0, 1), (1, 29, 44): (3, 0, 1), (2, 18, 32): (0, 0, 2), (2, 22, 36): (1, 0, 2), (2, 26, 40): (2, 0, 2), (2, 30, 44): (3, 0, 2), (3, 19, 32): (0, 0, 3), (3, 23, 36): (1, 0, 3), (3, 27, 40): (2, 0, 3), (3, 31, 44): (3, 0, 3), (4, 16, 33): (0, 1, 0), (4, 20, 37): (1, 1, 0), (4, 24, 41): (2, 1, 0), (4, 28, 45): (3, 1, 0), (5, 17, 33): (0, 1, 1), (5, 21, 37): (1, 1, 1), (5, 25, 41): (2, 1, 1), (5, 29, 45): (3, 1, 1), (6, 18, 33): (0, 1, 2), (6, 22, 37): (1, 1, 2), (6, 26, 41): (2, 1, 2), (6, 30, 45): (3, 1, 2), (7, 19, 33): (0, 1, 3), (7, 23, 37): (1, 1, 3), (7, 27, 41): (2, 1, 3), (7, 31, 45): (3, 1, 3), (8, 16, 34): (0, 2, 0), (8, 20, 38): (1, 2, 0), (8, 24, 42): (2, 2, 0), (8, 28, 46): (3, 2, 0), (9, 17, 34): (0, 2, 1), (9, 21, 38): (1, 2, 1), (9, 25, 42): (2, 2, 1), (9, 29, 46): (3, 2, 1), (10, 18, 34): (0, 2, 2), (10, 22, 38): (1, 2, 2), (10, 26, 42): (2, 2, 2), (10, 30, 46): (3, 2, 2), (11, 19, 34): (0, 2, 3), (11, 23, 38): (1, 2, 3), (11, 27, 42): (2, 2, 3), (11, 31, 46): (3, 2, 3), (12, 16, 35): (0, 3, 0), (12, 20, 39): (1, 3, 0), (12, 24, 43): (2, 3, 0), (12, 28, 47): (3, 3, 0), (13, 17, 35): (0, 3, 1), (13, 21, 39): (1, 3, 1), (13, 25, 43): (2, 3, 1), (13, 29, 47): (3, 3, 1), (14, 18, 35): (0, 3, 2), (14, 22, 39): (1, 3, 2), (14, 26, 43): (2, 3, 2), (14, 30, 47): (3, 3, 2), (15, 19, 35): (0, 3, 3), (15, 23, 39): (1, 3, 3), (15, 27, 43): (2, 3, 3), (15, 31, 47): (3, 3, 3)}) 
 - dlxcpp_has_unique_completion()[source]¶
- Check if the partial latin square - selfof order n can be embedded in precisely one latin square of order n.- EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: back_circulant(2).dlxcpp_has_unique_completion() True sage: P = LatinSquare(2) sage: P.dlxcpp_has_unique_completion() False sage: P[0, 0] = 0 sage: P.dlxcpp_has_unique_completion() True - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> back_circulant(Integer(2)).dlxcpp_has_unique_completion() True >>> P = LatinSquare(Integer(2)) >>> P.dlxcpp_has_unique_completion() False >>> P[Integer(0), Integer(0)] = Integer(0) >>> P.dlxcpp_has_unique_completion() True 
 - dumps()[source]¶
- Since the latin square class does not hold any other private variables we just call dumps on self.square: - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: back_circulant(2) == loads(dumps(back_circulant(2))) True - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> back_circulant(Integer(2)) == loads(dumps(back_circulant(Integer(2)))) True 
 - filled_cells_map()[source]¶
- Number the filled cells of - selfwith integers from {1, 2, 3, …}.- INPUT: - self– partial latin square- self(empty cells have negative values)
 - OUTPUT: - A dictionary - cells_mapwhere- cells_map[(i,j)] = mmeans that- (i,j)is the- m-th filled cell in- P, while- cells_map[m] = (i,j).- EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: (a, b, c, G) = alternating_group_bitrade_generators(1) sage: (T1, T2) = bitrade_from_group(a, b, c, G) sage: D = T1.filled_cells_map() sage: {i: v for i,v in D.items() if i in ZZ} {1: (0, 0), 2: (0, 2), 3: (0, 3), 4: (1, 1), 5: (1, 2), 6: (1, 3), 7: (2, 0), 8: (2, 1), 9: (2, 2), 10: (3, 0), 11: (3, 1), 12: (3, 3)} sage: {i: v for i,v in D.items() if i not in ZZ} {(0, 0): 1, (0, 2): 2, (0, 3): 3, (1, 1): 4, (1, 2): 5, (1, 3): 6, (2, 0): 7, (2, 1): 8, (2, 2): 9, (3, 0): 10, (3, 1): 11, (3, 3): 12} - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> (a, b, c, G) = alternating_group_bitrade_generators(Integer(1)) >>> (T1, T2) = bitrade_from_group(a, b, c, G) >>> D = T1.filled_cells_map() >>> {i: v for i,v in D.items() if i in ZZ} {1: (0, 0), 2: (0, 2), 3: (0, 3), 4: (1, 1), 5: (1, 2), 6: (1, 3), 7: (2, 0), 8: (2, 1), 9: (2, 2), 10: (3, 0), 11: (3, 1), 12: (3, 3)} >>> {i: v for i,v in D.items() if i not in ZZ} {(0, 0): 1, (0, 2): 2, (0, 3): 3, (1, 1): 4, (1, 2): 5, (1, 3): 6, (2, 0): 7, (2, 1): 8, (2, 2): 9, (3, 0): 10, (3, 1): 11, (3, 3): 12} 
 - find_disjoint_mates(nr_to_find=None, allow_subtrade=False)[source]¶
- Warning - If allow_subtrade is - Truethen we may return a partial latin square that is not disjoint to- self. In that case, use bitrade(P, Q) to get an actual bitrade.- EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: B = back_circulant(4) sage: g = B.find_disjoint_mates(allow_subtrade = True) sage: B1 = next(g) sage: B0, B1 = bitrade(B, B1) sage: assert is_bitrade(B0, B1) sage: print(B0) [-1 1 2 -1] [-1 2 -1 0] [-1 -1 -1 -1] [-1 0 1 2] sage: print(B1) [-1 2 1 -1] [-1 0 -1 2] [-1 -1 -1 -1] [-1 1 2 0] - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> B = back_circulant(Integer(4)) >>> g = B.find_disjoint_mates(allow_subtrade = True) >>> B1 = next(g) >>> B0, B1 = bitrade(B, B1) >>> assert is_bitrade(B0, B1) >>> print(B0) [-1 1 2 -1] [-1 2 -1 0] [-1 -1 -1 -1] [-1 0 1 2] >>> print(B1) [-1 2 1 -1] [-1 0 -1 2] [-1 -1 -1 -1] [-1 1 2 0] 
 - gcs()[source]¶
- A greedy critical set of a latin square - selfis found by successively removing elements in a row-wise (bottom-up) manner, checking for unique completion at each step.- EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: A = elementary_abelian_2group(3) sage: G = A.gcs() sage: A [0 1 2 3 4 5 6 7] [1 0 3 2 5 4 7 6] [2 3 0 1 6 7 4 5] [3 2 1 0 7 6 5 4] [4 5 6 7 0 1 2 3] [5 4 7 6 1 0 3 2] [6 7 4 5 2 3 0 1] [7 6 5 4 3 2 1 0] sage: G [ 0 1 2 3 4 5 6 -1] [ 1 0 3 2 5 4 -1 -1] [ 2 3 0 1 6 -1 4 -1] [ 3 2 1 0 -1 -1 -1 -1] [ 4 5 6 -1 0 1 2 -1] [ 5 4 -1 -1 1 0 -1 -1] [ 6 -1 4 -1 2 -1 0 -1] [-1 -1 -1 -1 -1 -1 -1 -1] - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> A = elementary_abelian_2group(Integer(3)) >>> G = A.gcs() >>> A [0 1 2 3 4 5 6 7] [1 0 3 2 5 4 7 6] [2 3 0 1 6 7 4 5] [3 2 1 0 7 6 5 4] [4 5 6 7 0 1 2 3] [5 4 7 6 1 0 3 2] [6 7 4 5 2 3 0 1] [7 6 5 4 3 2 1 0] >>> G [ 0 1 2 3 4 5 6 -1] [ 1 0 3 2 5 4 -1 -1] [ 2 3 0 1 6 -1 4 -1] [ 3 2 1 0 -1 -1 -1 -1] [ 4 5 6 -1 0 1 2 -1] [ 5 4 -1 -1 1 0 -1 -1] [ 6 -1 4 -1 2 -1 0 -1] [-1 -1 -1 -1 -1 -1 -1 -1] 
 - is_completable()[source]¶
- Return - Trueif the partial latin square can be completed to a latin square.- EXAMPLES: - The following partial latin square has no completion because there is nowhere that we can place the symbol 0 in the third row: - sage: B = LatinSquare(3) - >>> from sage.all import * >>> B = LatinSquare(Integer(3)) - sage: B[0, 0] = 0 sage: B[1, 1] = 0 sage: B[2, 2] = 1 - >>> from sage.all import * >>> B[Integer(0), Integer(0)] = Integer(0) >>> B[Integer(1), Integer(1)] = Integer(0) >>> B[Integer(2), Integer(2)] = Integer(1) - sage: B [ 0 -1 -1] [-1 0 -1] [-1 -1 1] - >>> from sage.all import * >>> B [ 0 -1 -1] [-1 0 -1] [-1 -1 1] - sage: B.is_completable() False - >>> from sage.all import * >>> B.is_completable() False - sage: B[2, 2] = 0 sage: B.is_completable() True - >>> from sage.all import * >>> B[Integer(2), Integer(2)] = Integer(0) >>> B.is_completable() True 
 - is_empty_column(c)[source]¶
- Check if column c of the partial latin square - selfis empty.- EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: L = back_circulant(4) sage: L.is_empty_column(0) False sage: L[0,0] = L[1,0] = L[2,0] = L[3,0] = -1 sage: L.is_empty_column(0) True - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> L = back_circulant(Integer(4)) >>> L.is_empty_column(Integer(0)) False >>> L[Integer(0),Integer(0)] = L[Integer(1),Integer(0)] = L[Integer(2),Integer(0)] = L[Integer(3),Integer(0)] = -Integer(1) >>> L.is_empty_column(Integer(0)) True 
 - is_empty_row(r)[source]¶
- Check if row r of the partial latin square - selfis empty.- EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: L = back_circulant(4) sage: L.is_empty_row(0) False sage: L[0,0] = L[0,1] = L[0,2] = L[0,3] = -1 sage: L.is_empty_row(0) True - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> L = back_circulant(Integer(4)) >>> L.is_empty_row(Integer(0)) False >>> L[Integer(0),Integer(0)] = L[Integer(0),Integer(1)] = L[Integer(0),Integer(2)] = L[Integer(0),Integer(3)] = -Integer(1) >>> L.is_empty_row(Integer(0)) True 
 - is_latin_square()[source]¶
- selfis a latin square if it is an n by n matrix, and each symbol in [0, 1, …, n-1] appears exactly once in each row, and exactly once in each column.- EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: elementary_abelian_2group(4).is_latin_square() True - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> elementary_abelian_2group(Integer(4)).is_latin_square() True - sage: forward_circulant(7).is_latin_square() True - >>> from sage.all import * >>> forward_circulant(Integer(7)).is_latin_square() True 
 - is_partial_latin_square()[source]¶
- selfis a partial latin square if it is an n by n matrix, and each symbol in [0, 1, …, n-1] appears at most once in each row, and at most once in each column.- EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: LatinSquare(4).is_partial_latin_square() True sage: back_circulant(3).gcs().is_partial_latin_square() True sage: back_circulant(6).is_partial_latin_square() True - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> LatinSquare(Integer(4)).is_partial_latin_square() True >>> back_circulant(Integer(3)).gcs().is_partial_latin_square() True >>> back_circulant(Integer(6)).is_partial_latin_square() True 
 - is_uniquely_completable()[source]¶
- Return - Trueif the partial latin square- selfhas exactly one completion to a latin square. This is just a wrapper for the current best-known algorithm, Dancing Links by Knuth. See dancing_links.spyx- EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: back_circulant(4).gcs().is_uniquely_completable() True - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> back_circulant(Integer(4)).gcs().is_uniquely_completable() True - sage: G = elementary_abelian_2group(3).gcs() sage: G.is_uniquely_completable() True - >>> from sage.all import * >>> G = elementary_abelian_2group(Integer(3)).gcs() >>> G.is_uniquely_completable() True - sage: G[0, 0] = -1 sage: G.is_uniquely_completable() False - >>> from sage.all import * >>> G[Integer(0), Integer(0)] = -Integer(1) >>> G.is_uniquely_completable() False 
 - latex()[source]¶
- Return LaTeX code for the latin square. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: print(back_circulant(3).latex()) \begin{array}{|c|c|c|}\hline 0 & 1 & 2\\\hline 1 & 2 & 0\\\hline 2 & 0 & 1\\\hline\end{array} - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> print(back_circulant(Integer(3)).latex()) \begin{array}{|c|c|c|}\hline 0 & 1 & 2\\\hline 1 & 2 & 0\\\hline 2 & 0 & 1\\\hline\end{array} 
 - list()[source]¶
- Convert the latin square into a list, in a row-wise manner. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: back_circulant(3).list() [0, 1, 2, 1, 2, 0, 2, 0, 1] - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> back_circulant(Integer(3)).list() [0, 1, 2, 1, 2, 0, 2, 0, 1] 
 - ncols()[source]¶
- Number of columns in the latin square. - EXAMPLES: - sage: LatinSquare(3).ncols() 3 - >>> from sage.all import * >>> LatinSquare(Integer(3)).ncols() 3 
 - nr_distinct_symbols()[source]¶
- Return the number of distinct symbols in the partial latin square - self.- EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: back_circulant(5).nr_distinct_symbols() 5 sage: L = LatinSquare(10) sage: L.nr_distinct_symbols() 0 sage: L[0, 0] = 0 sage: L[0, 1] = 1 sage: L.nr_distinct_symbols() 2 - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> back_circulant(Integer(5)).nr_distinct_symbols() 5 >>> L = LatinSquare(Integer(10)) >>> L.nr_distinct_symbols() 0 >>> L[Integer(0), Integer(0)] = Integer(0) >>> L[Integer(0), Integer(1)] = Integer(1) >>> L.nr_distinct_symbols() 2 
 - nr_filled_cells()[source]¶
- Return the number of filled cells (i.e. cells with a positive value) in the partial latin square - self.- EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: LatinSquare(matrix([[0, -1], [-1, 0]])).nr_filled_cells() 2 - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> LatinSquare(matrix([[Integer(0), -Integer(1)], [-Integer(1), Integer(0)]])).nr_filled_cells() 2 
 - nrows()[source]¶
- Number of rows in the latin square. - EXAMPLES: - sage: LatinSquare(3).nrows() 3 - >>> from sage.all import * >>> LatinSquare(Integer(3)).nrows() 3 
 - permissable_values(r, c)[source]¶
- Find all values that do not appear in row r and column c of the latin square - self. If- self[r, c]is filled then we return the empty list.- INPUT: - self– LatinSquare
- r– integer; row of the latin square
- c– integer; column of the latin square
 - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: L = back_circulant(5) sage: L[0, 0] = -1 sage: L.permissable_values(0, 0) [0] - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> L = back_circulant(Integer(5)) >>> L[Integer(0), Integer(0)] = -Integer(1) >>> L.permissable_values(Integer(0), Integer(0)) [0] 
 - random_empty_cell()[source]¶
- Find an empty cell of self, uniformly at random. - INPUT: - self– LatinSquare
 - OUTPUT: - [r, c]– cell such that- self[r, c]is empty, or returns- Noneif- selfis a (full) latin square
 - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: P = back_circulant(2) sage: P[1,1] = -1 sage: P.random_empty_cell() [1, 1] - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> P = back_circulant(Integer(2)) >>> P[Integer(1),Integer(1)] = -Integer(1) >>> P.random_empty_cell() [1, 1] 
 - row(x)[source]¶
- Return row x of the latin square. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: back_circulant(3).row(0) (0, 1, 2) - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> back_circulant(Integer(3)).row(Integer(0)) (0, 1, 2) 
 - set_immutable()[source]¶
- A latin square is immutable if the underlying matrix is immutable. - EXAMPLES: - sage: L = LatinSquare(matrix(ZZ, [[0, 1], [2, 3]])) sage: L.set_immutable() sage: {L : 0} # this would fail without set_immutable() {[0 1] [2 3]: 0} - >>> from sage.all import * >>> L = LatinSquare(matrix(ZZ, [[Integer(0), Integer(1)], [Integer(2), Integer(3)]])) >>> L.set_immutable() >>> {L : Integer(0)} # this would fail without set_immutable() {[0 1] [2 3]: 0} 
 - top_left_empty_cell()[source]¶
- Return the least - [r, c]such that- self[r, c]is an empty cell. If all cells are filled then we return- None.- INPUT: - self– LatinSquare
 - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: B = back_circulant(5) sage: B[3, 4] = -1 sage: B.top_left_empty_cell() [3, 4] - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> B = back_circulant(Integer(5)) >>> B[Integer(3), Integer(4)] = -Integer(1) >>> B.top_left_empty_cell() [3, 4] 
 - vals_in_col(c)[source]¶
- Return a dictionary with key e if and only if column c of - selfhas the symbol e.- EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: B = back_circulant(3) sage: B[0, 0] = -1 sage: back_circulant(3).vals_in_col(0) {0: True, 1: True, 2: True} - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> B = back_circulant(Integer(3)) >>> B[Integer(0), Integer(0)] = -Integer(1) >>> back_circulant(Integer(3)).vals_in_col(Integer(0)) {0: True, 1: True, 2: True} 
 - vals_in_row(r)[source]¶
- Return a dictionary with key e if and only if row r of - selfhas the symbol e.- EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: B = back_circulant(3) sage: B[0, 0] = -1 sage: back_circulant(3).vals_in_row(0) {0: True, 1: True, 2: True} - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> B = back_circulant(Integer(3)) >>> B[Integer(0), Integer(0)] = -Integer(1) >>> back_circulant(Integer(3)).vals_in_row(Integer(0)) {0: True, 1: True, 2: True} 
 
- sage.combinat.matrices.latin.LatinSquare_generator(L_start, check_assertions=False)[source]¶
- Generator for a sequence of uniformly distributed latin squares, given L_start as the initial latin square. - This code implements the Markov chain algorithm of Jacobson and Matthews (1996), see below for the BibTex entry. This generator will never throw the - StopIterationexception, so it provides an infinite sequence of latin squares.- EXAMPLES: - Use the back circulant latin square of order 4 as the initial square and print the next two latin squares given by the Markov chain: - sage: from sage.combinat.matrices.latin import * sage: g = LatinSquare_generator(back_circulant(4)) sage: next(g).is_latin_square() True - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> g = LatinSquare_generator(back_circulant(Integer(4))) >>> next(g).is_latin_square() True - REFERENCES: [JacMat96]- Mark T. Jacobson and Peter Matthews, “Generating uniformly distributed random Latin squares”, Journal of Combinatorial Designs, 4 (1996) 
- sage.combinat.matrices.latin.alternating_group_bitrade_generators(m)[source]¶
- Construct generators a, b, c for the alternating group on 3m+1 points, such that a*b*c = 1. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: a, b, c, G = alternating_group_bitrade_generators(1) sage: (a, b, c, G) ((1,2,3), (1,4,2), (2,4,3), Permutation Group with generators [(1,2,3), (1,4,2)]) sage: a*b*c () - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> a, b, c, G = alternating_group_bitrade_generators(Integer(1)) >>> (a, b, c, G) ((1,2,3), (1,4,2), (2,4,3), Permutation Group with generators [(1,2,3), (1,4,2)]) >>> a*b*c () - sage: (T1, T2) = bitrade_from_group(a, b, c, G) sage: T1 [ 0 -1 3 1] [-1 1 0 2] [ 1 3 2 -1] [ 2 0 -1 3] sage: T2 [ 1 -1 0 3] [-1 0 2 1] [ 2 1 3 -1] [ 0 3 -1 2] - >>> from sage.all import * >>> (T1, T2) = bitrade_from_group(a, b, c, G) >>> T1 [ 0 -1 3 1] [-1 1 0 2] [ 1 3 2 -1] [ 2 0 -1 3] >>> T2 [ 1 -1 0 3] [-1 0 2 1] [ 2 1 3 -1] [ 0 3 -1 2] 
- sage.combinat.matrices.latin.back_circulant(n)[source]¶
- The back-circulant latin square of order n is the Cayley table for (Z_n, +), the integers under addition modulo n. - INPUT: - n– integer; order of the latin square
 - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: back_circulant(5) [0 1 2 3 4] [1 2 3 4 0] [2 3 4 0 1] [3 4 0 1 2] [4 0 1 2 3] - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> back_circulant(Integer(5)) [0 1 2 3 4] [1 2 3 4 0] [2 3 4 0 1] [3 4 0 1 2] [4 0 1 2 3] 
- sage.combinat.matrices.latin.beta1(rce, T1, T2)[source]¶
- Find the unique (x, c, e) in T2 such that (r, c, e) is in T1. - INPUT: - rce– tuple (or list) (r, c, e) in T1
- T1,- T2– latin bitrade
 - OUTPUT: (x, c, e) in T2 - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: T1 = back_circulant(5) sage: x = isotopism( (0,1,2,3,4) ) sage: y = isotopism(5) # identity sage: z = isotopism(5) # identity sage: T2 = T1.apply_isotopism(x, y, z) sage: is_bitrade(T1, T2) True sage: beta1([0, 0, 0], T1, T2) (1, 0, 0) - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> T1 = back_circulant(Integer(5)) >>> x = isotopism( (Integer(0),Integer(1),Integer(2),Integer(3),Integer(4)) ) >>> y = isotopism(Integer(5)) # identity >>> z = isotopism(Integer(5)) # identity >>> T2 = T1.apply_isotopism(x, y, z) >>> is_bitrade(T1, T2) True >>> beta1([Integer(0), Integer(0), Integer(0)], T1, T2) (1, 0, 0) 
- sage.combinat.matrices.latin.beta2(rce, T1, T2)[source]¶
- Find the unique (r, x, e) in T2 such that (r, c, e) is in T1. - INPUT: - rce– tuple (or list) (r, c, e) in T1
- T1,- T2– latin bitrade
 - OUTPUT: (r, x, e) in T2 - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: T1 = back_circulant(5) sage: x = isotopism( (0,1,2,3,4) ) sage: y = isotopism(5) # identity sage: z = isotopism(5) # identity sage: T2 = T1.apply_isotopism(x, y, z) sage: is_bitrade(T1, T2) True sage: beta2([0, 0, 0], T1, T2) (0, 1, 0) - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> T1 = back_circulant(Integer(5)) >>> x = isotopism( (Integer(0),Integer(1),Integer(2),Integer(3),Integer(4)) ) >>> y = isotopism(Integer(5)) # identity >>> z = isotopism(Integer(5)) # identity >>> T2 = T1.apply_isotopism(x, y, z) >>> is_bitrade(T1, T2) True >>> beta2([Integer(0), Integer(0), Integer(0)], T1, T2) (0, 1, 0) 
- sage.combinat.matrices.latin.beta3(rce, T1, T2)[source]¶
- Find the unique (r, c, x) in T2 such that (r, c, e) is in T1. - INPUT: - rce– tuple (or list) (r, c, e) in T1
- T1, T2– latin bitrade
 - OUTPUT: (r, c, x) in T2. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: T1 = back_circulant(5) sage: x = isotopism( (0,1,2,3,4) ) sage: y = isotopism(5) # identity sage: z = isotopism(5) # identity sage: T2 = T1.apply_isotopism(x, y, z) sage: is_bitrade(T1, T2) True sage: beta3([0, 0, 0], T1, T2) (0, 0, 4) - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> T1 = back_circulant(Integer(5)) >>> x = isotopism( (Integer(0),Integer(1),Integer(2),Integer(3),Integer(4)) ) >>> y = isotopism(Integer(5)) # identity >>> z = isotopism(Integer(5)) # identity >>> T2 = T1.apply_isotopism(x, y, z) >>> is_bitrade(T1, T2) True >>> beta3([Integer(0), Integer(0), Integer(0)], T1, T2) (0, 0, 4) 
- sage.combinat.matrices.latin.bitrade(T1, T2)[source]¶
- Form the bitrade (Q1, Q2) from (T1, T2) by setting empty the cells (r, c) such that T1[r, c] == T2[r, c]. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: B1 = back_circulant(5) sage: alpha = isotopism((0,1,2,3,4)) sage: beta = isotopism((1,0,2,3,4)) sage: gamma = isotopism((2,1,0,3,4)) sage: B2 = B1.apply_isotopism(alpha, beta, gamma) sage: T1, T2 = bitrade(B1, B2) sage: T1 [ 0 1 -1 3 4] [ 1 -1 -1 4 0] [ 2 -1 4 0 1] [ 3 4 0 1 2] [ 4 0 1 2 3] sage: T2 [ 3 4 -1 0 1] [ 0 -1 -1 1 4] [ 1 -1 0 4 2] [ 4 0 1 2 3] [ 2 1 4 3 0] - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> B1 = back_circulant(Integer(5)) >>> alpha = isotopism((Integer(0),Integer(1),Integer(2),Integer(3),Integer(4))) >>> beta = isotopism((Integer(1),Integer(0),Integer(2),Integer(3),Integer(4))) >>> gamma = isotopism((Integer(2),Integer(1),Integer(0),Integer(3),Integer(4))) >>> B2 = B1.apply_isotopism(alpha, beta, gamma) >>> T1, T2 = bitrade(B1, B2) >>> T1 [ 0 1 -1 3 4] [ 1 -1 -1 4 0] [ 2 -1 4 0 1] [ 3 4 0 1 2] [ 4 0 1 2 3] >>> T2 [ 3 4 -1 0 1] [ 0 -1 -1 1 4] [ 1 -1 0 4 2] [ 4 0 1 2 3] [ 2 1 4 3 0] 
- sage.combinat.matrices.latin.bitrade_from_group(a, b, c, G)[source]¶
- Given group elements a, b, c in G such that abc = 1 and the subgroups a, b, c intersect (pairwise) only in the identity, construct a bitrade (T1, T2) where rows, columns, and symbols correspond to cosets of a, b, and c, respectively. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: a, b, c, G = alternating_group_bitrade_generators(1) sage: (T1, T2) = bitrade_from_group(a, b, c, G) sage: T1 [ 0 -1 3 1] [-1 1 0 2] [ 1 3 2 -1] [ 2 0 -1 3] sage: T2 [ 1 -1 0 3] [-1 0 2 1] [ 2 1 3 -1] [ 0 3 -1 2] - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> a, b, c, G = alternating_group_bitrade_generators(Integer(1)) >>> (T1, T2) = bitrade_from_group(a, b, c, G) >>> T1 [ 0 -1 3 1] [-1 1 0 2] [ 1 3 2 -1] [ 2 0 -1 3] >>> T2 [ 1 -1 0 3] [-1 0 2 1] [ 2 1 3 -1] [ 0 3 -1 2] 
- sage.combinat.matrices.latin.cells_map_as_square(cells_map, n)[source]¶
- Return a LatinSquare with cells numbered from 1, 2, … to given the dictionary cells_map. - Note - The value n should be the maximum of the number of rows and columns of the original partial latin square - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: (a, b, c, G) = alternating_group_bitrade_generators(1) sage: (T1, T2) = bitrade_from_group(a, b, c, G) sage: T1 [ 0 -1 3 1] [-1 1 0 2] [ 1 3 2 -1] [ 2 0 -1 3] - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> (a, b, c, G) = alternating_group_bitrade_generators(Integer(1)) >>> (T1, T2) = bitrade_from_group(a, b, c, G) >>> T1 [ 0 -1 3 1] [-1 1 0 2] [ 1 3 2 -1] [ 2 0 -1 3] - There are 12 filled cells in T: - sage: cells_map_as_square(T1.filled_cells_map(), max(T1.nrows(), T1.ncols())) [ 1 -1 2 3] [-1 4 5 6] [ 7 8 9 -1] [10 11 -1 12] - >>> from sage.all import * >>> cells_map_as_square(T1.filled_cells_map(), max(T1.nrows(), T1.ncols())) [ 1 -1 2 3] [-1 4 5 6] [ 7 8 9 -1] [10 11 -1 12] 
- sage.combinat.matrices.latin.check_bitrade_generators(a, b, c)[source]¶
- Three group elements a, b, c will generate a bitrade if a*b*c = 1 and the subgroups a, b, c intersect (pairwise) in just the identity. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: a, b, c, G = p3_group_bitrade_generators(3) sage: check_bitrade_generators(a, b, c) True sage: check_bitrade_generators(a, b, libgap(gap('()'))) False - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> a, b, c, G = p3_group_bitrade_generators(Integer(3)) >>> check_bitrade_generators(a, b, c) True >>> check_bitrade_generators(a, b, libgap(gap('()'))) False 
- sage.combinat.matrices.latin.coin()[source]¶
- Simulate a fair coin (returns - Trueor- False) using ZZ.random_element(2).- EXAMPLES: - sage: from sage.combinat.matrices.latin import coin sage: x = coin() sage: x == 0 or x == 1 True - >>> from sage.all import * >>> from sage.combinat.matrices.latin import coin >>> x = coin() >>> x == Integer(0) or x == Integer(1) True 
- sage.combinat.matrices.latin.column_containing_sym(L, r, x)[source]¶
- Given an improper latin square L with L[r, c1] = L[r, c2] = x, return c1 or c2 with equal probability. This is an internal function and should only be used in LatinSquare_generator(). - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: L = matrix([(1, 0, 2, 3), (0, 2, 3, 0), (2, 3, 0, 1), (3, 0, 1, 2)]) sage: L [1 0 2 3] [0 2 3 0] [2 3 0 1] [3 0 1 2] sage: c = column_containing_sym(L, 1, 0) sage: c == 0 or c == 3 True - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> L = matrix([(Integer(1), Integer(0), Integer(2), Integer(3)), (Integer(0), Integer(2), Integer(3), Integer(0)), (Integer(2), Integer(3), Integer(0), Integer(1)), (Integer(3), Integer(0), Integer(1), Integer(2))]) >>> L [1 0 2 3] [0 2 3 0] [2 3 0 1] [3 0 1 2] >>> c = column_containing_sym(L, Integer(1), Integer(0)) >>> c == Integer(0) or c == Integer(3) True 
- sage.combinat.matrices.latin.direct_product(L1, L2, L3, L4)[source]¶
- The ‘direct product’ of four latin squares L1, L2, L3, L4 of order n is the latin square of order 2n consisting of - ----------- | L1 | L2 | ----------- | L3 | L4 | ----------- - where the subsquares L2 and L3 have entries offset by n. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: direct_product(back_circulant(4), back_circulant(4), elementary_abelian_2group(2), elementary_abelian_2group(2)) [0 1 2 3 4 5 6 7] [1 2 3 0 5 6 7 4] [2 3 0 1 6 7 4 5] [3 0 1 2 7 4 5 6] [4 5 6 7 0 1 2 3] [5 4 7 6 1 0 3 2] [6 7 4 5 2 3 0 1] [7 6 5 4 3 2 1 0] - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> direct_product(back_circulant(Integer(4)), back_circulant(Integer(4)), elementary_abelian_2group(Integer(2)), elementary_abelian_2group(Integer(2))) [0 1 2 3 4 5 6 7] [1 2 3 0 5 6 7 4] [2 3 0 1 6 7 4 5] [3 0 1 2 7 4 5 6] [4 5 6 7 0 1 2 3] [5 4 7 6 1 0 3 2] [6 7 4 5 2 3 0 1] [7 6 5 4 3 2 1 0] 
- sage.combinat.matrices.latin.dlxcpp_find_completions(P, nr_to_find=None)[source]¶
- Return a list of all latin squares L of the same order as P such that P is contained in L. The optional parameter nr_to_find limits the number of latin squares that are found. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: dlxcpp_find_completions(LatinSquare(2)) [[0 1] [1 0], [1 0] [0 1]] - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> dlxcpp_find_completions(LatinSquare(Integer(2))) [[0 1] [1 0], [1 0] [0 1]] - sage: dlxcpp_find_completions(LatinSquare(2), 1) [[0 1] [1 0]] - >>> from sage.all import * >>> dlxcpp_find_completions(LatinSquare(Integer(2)), Integer(1)) [[0 1] [1 0]] 
- sage.combinat.matrices.latin.dlxcpp_rows_and_map(P)[source]¶
- Internal function for - dlxcpp_find_completions. Given a partial latin square P we construct a list of rows of a 0-1 matrix M such that an exact cover of M corresponds to a completion of P to a latin square.- EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: dlxcpp_rows_and_map(LatinSquare(2)) ([[0, 4, 8], [1, 5, 8], [2, 4, 9], [3, 5, 9], [0, 6, 10], [1, 7, 10], [2, 6, 11], [3, 7, 11]], {(0, 4, 8): (0, 0, 0), (0, 6, 10): (1, 0, 0), (1, 5, 8): (0, 0, 1), (1, 7, 10): (1, 0, 1), (2, 4, 9): (0, 1, 0), (2, 6, 11): (1, 1, 0), (3, 5, 9): (0, 1, 1), (3, 7, 11): (1, 1, 1)}) - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> dlxcpp_rows_and_map(LatinSquare(Integer(2))) ([[0, 4, 8], [1, 5, 8], [2, 4, 9], [3, 5, 9], [0, 6, 10], [1, 7, 10], [2, 6, 11], [3, 7, 11]], {(0, 4, 8): (0, 0, 0), (0, 6, 10): (1, 0, 0), (1, 5, 8): (0, 0, 1), (1, 7, 10): (1, 0, 1), (2, 4, 9): (0, 1, 0), (2, 6, 11): (1, 1, 0), (3, 5, 9): (0, 1, 1), (3, 7, 11): (1, 1, 1)}) 
- sage.combinat.matrices.latin.elementary_abelian_2group(s)[source]¶
- Return the latin square based on the Cayley table for the elementary abelian 2-group of order 2s. - INPUT: - s– integer; order of the latin square will be 2s
 - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: elementary_abelian_2group(3) [0 1 2 3 4 5 6 7] [1 0 3 2 5 4 7 6] [2 3 0 1 6 7 4 5] [3 2 1 0 7 6 5 4] [4 5 6 7 0 1 2 3] [5 4 7 6 1 0 3 2] [6 7 4 5 2 3 0 1] [7 6 5 4 3 2 1 0] - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> elementary_abelian_2group(Integer(3)) [0 1 2 3 4 5 6 7] [1 0 3 2 5 4 7 6] [2 3 0 1 6 7 4 5] [3 2 1 0 7 6 5 4] [4 5 6 7 0 1 2 3] [5 4 7 6 1 0 3 2] [6 7 4 5 2 3 0 1] [7 6 5 4 3 2 1 0] 
- sage.combinat.matrices.latin.forward_circulant(n)[source]¶
- The forward-circulant latin square of order n is the Cayley table for the operation r + c = (n-c+r) mod n. - INPUT: - n– integer; order of the latin square
 - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: forward_circulant(5) [0 4 3 2 1] [1 0 4 3 2] [2 1 0 4 3] [3 2 1 0 4] [4 3 2 1 0] - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> forward_circulant(Integer(5)) [0 4 3 2 1] [1 0 4 3 2] [2 1 0 4 3] [3 2 1 0 4] [4 3 2 1 0] 
- sage.combinat.matrices.latin.genus(T1, T2)[source]¶
- Return the genus of hypermap embedding associated with the bitrade (T1, T2). - Informally, we compute the [tau_1, tau_2, tau_3] permutation representation of the bitrade. Each cycle of tau_1, tau_2, and tau_3 gives a rotation scheme for a black, white, and star vertex (respectively). The genus then comes from Euler’s formula. - For more details see Carlo Hamalainen: Partitioning 3-homogeneous latin bitrades. To appear in Geometriae Dedicata, available at arXiv 0710.0938 - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: (a, b, c, G) = alternating_group_bitrade_generators(1) sage: (T1, T2) = bitrade_from_group(a, b, c, G) sage: genus(T1, T2) 1 sage: (a, b, c, G) = pq_group_bitrade_generators(3, 7) sage: (T1, T2) = bitrade_from_group(a, b, c, G) sage: genus(T1, T2) 3 - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> (a, b, c, G) = alternating_group_bitrade_generators(Integer(1)) >>> (T1, T2) = bitrade_from_group(a, b, c, G) >>> genus(T1, T2) 1 >>> (a, b, c, G) = pq_group_bitrade_generators(Integer(3), Integer(7)) >>> (T1, T2) = bitrade_from_group(a, b, c, G) >>> genus(T1, T2) 3 
- sage.combinat.matrices.latin.group_to_LatinSquare(G)[source]¶
- Construct a latin square on the symbols [0, 1, …, n-1] for a group with an n by n Cayley table. - EXAMPLES: - sage: from sage.combinat.matrices.latin import group_to_LatinSquare sage: group_to_LatinSquare(DihedralGroup(2)) [0 1 2 3] [1 0 3 2] [2 3 0 1] [3 2 1 0] - >>> from sage.all import * >>> from sage.combinat.matrices.latin import group_to_LatinSquare >>> group_to_LatinSquare(DihedralGroup(Integer(2))) [0 1 2 3] [1 0 3 2] [2 3 0 1] [3 2 1 0] - sage: G = libgap.Group(PermutationGroupElement((1,2,3))) sage: group_to_LatinSquare(G) [0 1 2] [1 2 0] [2 0 1] - >>> from sage.all import * >>> G = libgap.Group(PermutationGroupElement((Integer(1),Integer(2),Integer(3)))) >>> group_to_LatinSquare(G) [0 1 2] [1 2 0] [2 0 1] 
- sage.combinat.matrices.latin.is_bitrade(T1, T2)[source]¶
- Combinatorially, a pair (T1, T2) of partial latin squares is a bitrade if they are disjoint, have the same shape, and have row and column balance. For definitions of each of these terms see the relevant function in this file. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: T1 = back_circulant(5) sage: x = isotopism( (0,1,2,3,4) ) sage: y = isotopism(5) # identity sage: z = isotopism(5) # identity sage: T2 = T1.apply_isotopism(x, y, z) sage: is_bitrade(T1, T2) True - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> T1 = back_circulant(Integer(5)) >>> x = isotopism( (Integer(0),Integer(1),Integer(2),Integer(3),Integer(4)) ) >>> y = isotopism(Integer(5)) # identity >>> z = isotopism(Integer(5)) # identity >>> T2 = T1.apply_isotopism(x, y, z) >>> is_bitrade(T1, T2) True 
- sage.combinat.matrices.latin.is_disjoint(T1, T2)[source]¶
- The partial latin squares T1 and T2 are disjoint if T1[r, c] != T2[r, c] or T1[r, c] == T2[r, c] == -1 for each cell [r, c]. - EXAMPLES: - sage: from sage.combinat.matrices.latin import is_disjoint, back_circulant, isotopism sage: is_disjoint(back_circulant(2), back_circulant(2)) False - >>> from sage.all import * >>> from sage.combinat.matrices.latin import is_disjoint, back_circulant, isotopism >>> is_disjoint(back_circulant(Integer(2)), back_circulant(Integer(2))) False - sage: T1 = back_circulant(5) sage: x = isotopism( (0,1,2,3,4) ) sage: y = isotopism(5) # identity sage: z = isotopism(5) # identity sage: T2 = T1.apply_isotopism(x, y, z) sage: is_disjoint(T1, T2) True - >>> from sage.all import * >>> T1 = back_circulant(Integer(5)) >>> x = isotopism( (Integer(0),Integer(1),Integer(2),Integer(3),Integer(4)) ) >>> y = isotopism(Integer(5)) # identity >>> z = isotopism(Integer(5)) # identity >>> T2 = T1.apply_isotopism(x, y, z) >>> is_disjoint(T1, T2) True 
- sage.combinat.matrices.latin.is_primary_bitrade(a, b, c, G)[source]¶
- A bitrade generated from elements a, b, c is primary if a, b, c = G. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: (a, b, c, G) = p3_group_bitrade_generators(5) sage: is_primary_bitrade(a, b, c, G) True - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> (a, b, c, G) = p3_group_bitrade_generators(Integer(5)) >>> is_primary_bitrade(a, b, c, G) True 
- sage.combinat.matrices.latin.is_row_and_col_balanced(T1, T2)[source]¶
- Partial latin squares T1 and T2 are balanced if the symbols appearing in row r of T1 are the same as the symbols appearing in row r of T2, for each r, and if the same condition holds on columns. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: T1 = matrix([[0,1,-1,-1], [-1,-1,-1,-1], [-1,-1,-1,-1], [-1,-1,-1,-1]]) sage: T2 = matrix([[0,1,-1,-1], [-1,-1,-1,-1], [-1,-1,-1,-1], [-1,-1,-1,-1]]) sage: is_row_and_col_balanced(T1, T2) True sage: T2 = matrix([[0,3,-1,-1], [-1,-1,-1,-1], [-1,-1,-1,-1], [-1,-1,-1,-1]]) sage: is_row_and_col_balanced(T1, T2) False - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> T1 = matrix([[Integer(0),Integer(1),-Integer(1),-Integer(1)], [-Integer(1),-Integer(1),-Integer(1),-Integer(1)], [-Integer(1),-Integer(1),-Integer(1),-Integer(1)], [-Integer(1),-Integer(1),-Integer(1),-Integer(1)]]) >>> T2 = matrix([[Integer(0),Integer(1),-Integer(1),-Integer(1)], [-Integer(1),-Integer(1),-Integer(1),-Integer(1)], [-Integer(1),-Integer(1),-Integer(1),-Integer(1)], [-Integer(1),-Integer(1),-Integer(1),-Integer(1)]]) >>> is_row_and_col_balanced(T1, T2) True >>> T2 = matrix([[Integer(0),Integer(3),-Integer(1),-Integer(1)], [-Integer(1),-Integer(1),-Integer(1),-Integer(1)], [-Integer(1),-Integer(1),-Integer(1),-Integer(1)], [-Integer(1),-Integer(1),-Integer(1),-Integer(1)]]) >>> is_row_and_col_balanced(T1, T2) False 
- sage.combinat.matrices.latin.is_same_shape(T1, T2)[source]¶
- Two partial latin squares T1, T2 have the same shape if T1[r, c] = 0 if and only if T2[r, c] = 0. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: is_same_shape(elementary_abelian_2group(2), back_circulant(4)) True sage: is_same_shape(LatinSquare(5), LatinSquare(5)) True sage: is_same_shape(forward_circulant(5), LatinSquare(5)) False - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> is_same_shape(elementary_abelian_2group(Integer(2)), back_circulant(Integer(4))) True >>> is_same_shape(LatinSquare(Integer(5)), LatinSquare(Integer(5))) True >>> is_same_shape(forward_circulant(Integer(5)), LatinSquare(Integer(5))) False 
- sage.combinat.matrices.latin.isotopism(p)[source]¶
- Return a Permutation object that represents an isotopism (for rows, columns or symbols of a partial latin square). - Technically, all this function does is take as input a representation of a permutation of \(0,...,n-1\) and return a - Permutationobject defined on \(1,...,n\).- For a definition of isotopism, see the wikipedia section on isotopism. - INPUT: - According to the type of input (see examples below): - an integer \(n\) – the function returns the identity on \(1,...,n\) 
- a string representing a permutation in disjoint cycles notation, e.g. \((0,1,2)(3,4,5)\) – the corresponding permutation is returned, shifted by 1 to act on \(1,...,n\) 
- list/tuple of tuples – assumes disjoint cycle notation, see previous entry 
- a list of integers – the function adds \(1\) to each member of the list, and returns the corresponding permutation 
- a - PermutationGroupElement- p– returns a permutation describing- pwithout any shift
 - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: isotopism(5) # identity on 5 points [1, 2, 3, 4, 5] - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> isotopism(Integer(5)) # identity on 5 points [1, 2, 3, 4, 5] - sage: G = PermutationGroup(['(1,2,3)(4,5)']) sage: g = G.gen(0) sage: isotopism(g) [2, 3, 1, 5, 4] - >>> from sage.all import * >>> G = PermutationGroup(['(1,2,3)(4,5)']) >>> g = G.gen(Integer(0)) >>> isotopism(g) [2, 3, 1, 5, 4] - sage: isotopism([0,3,2,1]) # 0 goes to 0, 1 goes to 3, etc. [1, 4, 3, 2] - >>> from sage.all import * >>> isotopism([Integer(0),Integer(3),Integer(2),Integer(1)]) # 0 goes to 0, 1 goes to 3, etc. [1, 4, 3, 2] - sage: isotopism( (0,1,2) ) # single cycle, presented as a tuple [2, 3, 1] - >>> from sage.all import * >>> isotopism( (Integer(0),Integer(1),Integer(2)) ) # single cycle, presented as a tuple [2, 3, 1] - sage: x = isotopism( ((0,1,2), (3,4)) ) # tuple of cycles sage: x [2, 3, 1, 5, 4] sage: x.to_cycles() [(1, 2, 3), (4, 5)] - >>> from sage.all import * >>> x = isotopism( ((Integer(0),Integer(1),Integer(2)), (Integer(3),Integer(4))) ) # tuple of cycles >>> x [2, 3, 1, 5, 4] >>> x.to_cycles() [(1, 2, 3), (4, 5)] 
- sage.combinat.matrices.latin.next_conjugate(L)[source]¶
- Permute L[r, c] = e to the conjugate L[c, e] = r. - We assume that L is an n by n matrix and has values in the range 0, 1, …, n-1. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: L = back_circulant(6) sage: L [0 1 2 3 4 5] [1 2 3 4 5 0] [2 3 4 5 0 1] [3 4 5 0 1 2] [4 5 0 1 2 3] [5 0 1 2 3 4] sage: next_conjugate(L) [0 1 2 3 4 5] [5 0 1 2 3 4] [4 5 0 1 2 3] [3 4 5 0 1 2] [2 3 4 5 0 1] [1 2 3 4 5 0] sage: L == next_conjugate(next_conjugate(next_conjugate(L))) True - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> L = back_circulant(Integer(6)) >>> L [0 1 2 3 4 5] [1 2 3 4 5 0] [2 3 4 5 0 1] [3 4 5 0 1 2] [4 5 0 1 2 3] [5 0 1 2 3 4] >>> next_conjugate(L) [0 1 2 3 4 5] [5 0 1 2 3 4] [4 5 0 1 2 3] [3 4 5 0 1 2] [2 3 4 5 0 1] [1 2 3 4 5 0] >>> L == next_conjugate(next_conjugate(next_conjugate(L))) True 
- sage.combinat.matrices.latin.p3_group_bitrade_generators(p)[source]¶
- Generators for a group of order p3 where p is a prime. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: p3_group_bitrade_generators(3) # random output ((2,6,7)(3,8,9), (1,2,3)(4,7,8)(5,6,9), (1,9,2)(3,7,4)(5,8,6), Permutation Group with generators [(2,6,7)(3,8,9), (1,2,3)(4,7,8)(5,6,9)]) - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> p3_group_bitrade_generators(Integer(3)) # random output ((2,6,7)(3,8,9), (1,2,3)(4,7,8)(5,6,9), (1,9,2)(3,7,4)(5,8,6), Permutation Group with generators [(2,6,7)(3,8,9), (1,2,3)(4,7,8)(5,6,9)]) 
- sage.combinat.matrices.latin.pq_group_bitrade_generators(p, q)[source]¶
- Generators for a group of order pq where p and q are primes such that (q % p) == 1. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: pq_group_bitrade_generators(3,7) ((2,3,5)(4,7,6), (1,2,3,4,5,6,7), (1,4,2)(3,5,6), Permutation Group with generators [(2,3,5)(4,7,6), (1,2,3,4,5,6,7)]) - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> pq_group_bitrade_generators(Integer(3),Integer(7)) ((2,3,5)(4,7,6), (1,2,3,4,5,6,7), (1,4,2)(3,5,6), Permutation Group with generators [(2,3,5)(4,7,6), (1,2,3,4,5,6,7)]) 
- sage.combinat.matrices.latin.row_containing_sym(L, c, x)[source]¶
- Given an improper latin square L with L[r1, c] = L[r2, c] = x, return r1 or r2 with equal probability. This is an internal function and should only be used in LatinSquare_generator(). - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: L = matrix([(0, 1, 0, 3), (3, 0, 2, 1), (1, 0, 3, 2), (2, 3, 1, 0)]) sage: L [0 1 0 3] [3 0 2 1] [1 0 3 2] [2 3 1 0] sage: c = row_containing_sym(L, 1, 0) sage: c == 1 or c == 2 True - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> L = matrix([(Integer(0), Integer(1), Integer(0), Integer(3)), (Integer(3), Integer(0), Integer(2), Integer(1)), (Integer(1), Integer(0), Integer(3), Integer(2)), (Integer(2), Integer(3), Integer(1), Integer(0))]) >>> L [0 1 0 3] [3 0 2 1] [1 0 3 2] [2 3 1 0] >>> c = row_containing_sym(L, Integer(1), Integer(0)) >>> c == Integer(1) or c == Integer(2) True 
- sage.combinat.matrices.latin.tau1(T1, T2, cells_map)[source]¶
- The definition of \(\tau_1\) is \[\begin{split}\tau_1 : T1 \rightarrow T1 \\ \tau_1 = \beta_2^{-1} \beta_3\end{split}\]- where the composition is left to right and \(\beta_i : T2 \rightarrow T1\) changes just the \(i\)-th coordinate of a triple. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: T1 = back_circulant(5) sage: x = isotopism( (0,1,2,3,4) ) sage: y = isotopism(5) # identity sage: z = isotopism(5) # identity sage: T2 = T1.apply_isotopism(x, y, z) sage: is_bitrade(T1, T2) True sage: (cells_map, t1, t2, t3) = tau123(T1, T2) sage: t1 = tau1(T1, T2, cells_map) sage: t1 [2, 3, 4, 5, 1, 7, 8, 9, 10, 6, 12, 13, 14, 15, 11, 17, 18, 19, 20, 16, 22, 23, 24, 25, 21] sage: t1.to_cycles() [(1, 2, 3, 4, 5), (6, 7, 8, 9, 10), (11, 12, 13, 14, 15), (16, 17, 18, 19, 20), (21, 22, 23, 24, 25)] - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> T1 = back_circulant(Integer(5)) >>> x = isotopism( (Integer(0),Integer(1),Integer(2),Integer(3),Integer(4)) ) >>> y = isotopism(Integer(5)) # identity >>> z = isotopism(Integer(5)) # identity >>> T2 = T1.apply_isotopism(x, y, z) >>> is_bitrade(T1, T2) True >>> (cells_map, t1, t2, t3) = tau123(T1, T2) >>> t1 = tau1(T1, T2, cells_map) >>> t1 [2, 3, 4, 5, 1, 7, 8, 9, 10, 6, 12, 13, 14, 15, 11, 17, 18, 19, 20, 16, 22, 23, 24, 25, 21] >>> t1.to_cycles() [(1, 2, 3, 4, 5), (6, 7, 8, 9, 10), (11, 12, 13, 14, 15), (16, 17, 18, 19, 20), (21, 22, 23, 24, 25)] 
- sage.combinat.matrices.latin.tau123(T1, T2)[source]¶
- Compute the tau_i representation for a bitrade (T1, T2). - See the functions tau1, tau2, and tau3 for the mathematical definitions. - OUTPUT: - (cells_map, t1, t2, t3) 
 - where cells_map is a map to/from the filled cells of T1, and t1, t2, t3 are the tau1, tau2, tau3 permutations. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: (a, b, c, G) = pq_group_bitrade_generators(3, 7) sage: (T1, T2) = bitrade_from_group(a, b, c, G) sage: T1 [ 0 1 3 -1 -1 -1 -1] [ 1 2 4 -1 -1 -1 -1] [ 2 3 5 -1 -1 -1 -1] [ 3 4 6 -1 -1 -1 -1] [ 4 5 0 -1 -1 -1 -1] [ 5 6 1 -1 -1 -1 -1] [ 6 0 2 -1 -1 -1 -1] sage: T2 [ 1 3 0 -1 -1 -1 -1] [ 2 4 1 -1 -1 -1 -1] [ 3 5 2 -1 -1 -1 -1] [ 4 6 3 -1 -1 -1 -1] [ 5 0 4 -1 -1 -1 -1] [ 6 1 5 -1 -1 -1 -1] [ 0 2 6 -1 -1 -1 -1] sage: (cells_map, t1, t2, t3) = tau123(T1, T2) sage: D = cells_map sage: {i: v for i,v in D.items() if i in ZZ} {1: (0, 0), 2: (0, 1), 3: (0, 2), 4: (1, 0), 5: (1, 1), 6: (1, 2), 7: (2, 0), 8: (2, 1), 9: (2, 2), 10: (3, 0), 11: (3, 1), 12: (3, 2), 13: (4, 0), 14: (4, 1), 15: (4, 2), 16: (5, 0), 17: (5, 1), 18: (5, 2), 19: (6, 0), 20: (6, 1), 21: (6, 2)} sage: {i: v for i,v in D.items() if i not in ZZ} {(0, 0): 1, (0, 1): 2, (0, 2): 3, (1, 0): 4, (1, 1): 5, (1, 2): 6, (2, 0): 7, (2, 1): 8, (2, 2): 9, (3, 0): 10, (3, 1): 11, (3, 2): 12, (4, 0): 13, (4, 1): 14, (4, 2): 15, (5, 0): 16, (5, 1): 17, (5, 2): 18, (6, 0): 19, (6, 1): 20, (6, 2): 21} sage: cells_map_as_square(cells_map, max(T1.nrows(), T1.ncols())) [ 1 2 3 -1 -1 -1 -1] [ 4 5 6 -1 -1 -1 -1] [ 7 8 9 -1 -1 -1 -1] [10 11 12 -1 -1 -1 -1] [13 14 15 -1 -1 -1 -1] [16 17 18 -1 -1 -1 -1] [19 20 21 -1 -1 -1 -1] sage: t1 [3, 1, 2, 6, 4, 5, 9, 7, 8, 12, 10, 11, 15, 13, 14, 18, 16, 17, 21, 19, 20] sage: t2 [4, 8, 15, 7, 11, 18, 10, 14, 21, 13, 17, 3, 16, 20, 6, 19, 2, 9, 1, 5, 12] sage: t3 [20, 18, 10, 2, 21, 13, 5, 3, 16, 8, 6, 19, 11, 9, 1, 14, 12, 4, 17, 15, 7] - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> (a, b, c, G) = pq_group_bitrade_generators(Integer(3), Integer(7)) >>> (T1, T2) = bitrade_from_group(a, b, c, G) >>> T1 [ 0 1 3 -1 -1 -1 -1] [ 1 2 4 -1 -1 -1 -1] [ 2 3 5 -1 -1 -1 -1] [ 3 4 6 -1 -1 -1 -1] [ 4 5 0 -1 -1 -1 -1] [ 5 6 1 -1 -1 -1 -1] [ 6 0 2 -1 -1 -1 -1] >>> T2 [ 1 3 0 -1 -1 -1 -1] [ 2 4 1 -1 -1 -1 -1] [ 3 5 2 -1 -1 -1 -1] [ 4 6 3 -1 -1 -1 -1] [ 5 0 4 -1 -1 -1 -1] [ 6 1 5 -1 -1 -1 -1] [ 0 2 6 -1 -1 -1 -1] >>> (cells_map, t1, t2, t3) = tau123(T1, T2) >>> D = cells_map >>> {i: v for i,v in D.items() if i in ZZ} {1: (0, 0), 2: (0, 1), 3: (0, 2), 4: (1, 0), 5: (1, 1), 6: (1, 2), 7: (2, 0), 8: (2, 1), 9: (2, 2), 10: (3, 0), 11: (3, 1), 12: (3, 2), 13: (4, 0), 14: (4, 1), 15: (4, 2), 16: (5, 0), 17: (5, 1), 18: (5, 2), 19: (6, 0), 20: (6, 1), 21: (6, 2)} >>> {i: v for i,v in D.items() if i not in ZZ} {(0, 0): 1, (0, 1): 2, (0, 2): 3, (1, 0): 4, (1, 1): 5, (1, 2): 6, (2, 0): 7, (2, 1): 8, (2, 2): 9, (3, 0): 10, (3, 1): 11, (3, 2): 12, (4, 0): 13, (4, 1): 14, (4, 2): 15, (5, 0): 16, (5, 1): 17, (5, 2): 18, (6, 0): 19, (6, 1): 20, (6, 2): 21} >>> cells_map_as_square(cells_map, max(T1.nrows(), T1.ncols())) [ 1 2 3 -1 -1 -1 -1] [ 4 5 6 -1 -1 -1 -1] [ 7 8 9 -1 -1 -1 -1] [10 11 12 -1 -1 -1 -1] [13 14 15 -1 -1 -1 -1] [16 17 18 -1 -1 -1 -1] [19 20 21 -1 -1 -1 -1] >>> t1 [3, 1, 2, 6, 4, 5, 9, 7, 8, 12, 10, 11, 15, 13, 14, 18, 16, 17, 21, 19, 20] >>> t2 [4, 8, 15, 7, 11, 18, 10, 14, 21, 13, 17, 3, 16, 20, 6, 19, 2, 9, 1, 5, 12] >>> t3 [20, 18, 10, 2, 21, 13, 5, 3, 16, 8, 6, 19, 11, 9, 1, 14, 12, 4, 17, 15, 7] - sage: t1.to_cycles() [(1, 3, 2), (4, 6, 5), (7, 9, 8), (10, 12, 11), (13, 15, 14), (16, 18, 17), (19, 21, 20)] sage: t2.to_cycles() [(1, 4, 7, 10, 13, 16, 19), (2, 8, 14, 20, 5, 11, 17), (3, 15, 6, 18, 9, 21, 12)] sage: t3.to_cycles() [(1, 20, 15), (2, 18, 4), (3, 10, 8), (5, 21, 7), (6, 13, 11), (9, 16, 14), (12, 19, 17)] - >>> from sage.all import * >>> t1.to_cycles() [(1, 3, 2), (4, 6, 5), (7, 9, 8), (10, 12, 11), (13, 15, 14), (16, 18, 17), (19, 21, 20)] >>> t2.to_cycles() [(1, 4, 7, 10, 13, 16, 19), (2, 8, 14, 20, 5, 11, 17), (3, 15, 6, 18, 9, 21, 12)] >>> t3.to_cycles() [(1, 20, 15), (2, 18, 4), (3, 10, 8), (5, 21, 7), (6, 13, 11), (9, 16, 14), (12, 19, 17)] - The product t1*t2*t3 is the identity, i.e. it fixes every point: - sage: len((t1*t2*t3).fixed_points()) == T1.nr_filled_cells() True - >>> from sage.all import * >>> len((t1*t2*t3).fixed_points()) == T1.nr_filled_cells() True 
- sage.combinat.matrices.latin.tau2(T1, T2, cells_map)[source]¶
- The definition of \(\tau_2\) is \[\begin{split}\tau_2 : T1 \rightarrow T1 \\ \tau_2 = \beta_3^{-1} \beta_1\end{split}\]- where the composition is left to right and \(\beta_i : T2 \rightarrow T1\) changes just the \(i\)-th coordinate of a triple. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: T1 = back_circulant(5) sage: x = isotopism( (0,1,2,3,4) ) sage: y = isotopism(5) # identity sage: z = isotopism(5) # identity sage: T2 = T1.apply_isotopism(x, y, z) sage: is_bitrade(T1, T2) True sage: (cells_map, t1, t2, t3) = tau123(T1, T2) sage: t2 = tau2(T1, T2, cells_map) sage: t2 [21, 22, 23, 24, 25, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] sage: t2.to_cycles() [(1, 21, 16, 11, 6), (2, 22, 17, 12, 7), (3, 23, 18, 13, 8), (4, 24, 19, 14, 9), (5, 25, 20, 15, 10)] - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> T1 = back_circulant(Integer(5)) >>> x = isotopism( (Integer(0),Integer(1),Integer(2),Integer(3),Integer(4)) ) >>> y = isotopism(Integer(5)) # identity >>> z = isotopism(Integer(5)) # identity >>> T2 = T1.apply_isotopism(x, y, z) >>> is_bitrade(T1, T2) True >>> (cells_map, t1, t2, t3) = tau123(T1, T2) >>> t2 = tau2(T1, T2, cells_map) >>> t2 [21, 22, 23, 24, 25, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] >>> t2.to_cycles() [(1, 21, 16, 11, 6), (2, 22, 17, 12, 7), (3, 23, 18, 13, 8), (4, 24, 19, 14, 9), (5, 25, 20, 15, 10)] 
- sage.combinat.matrices.latin.tau3(T1, T2, cells_map)[source]¶
- The definition of \(\tau_3\) is \[\begin{split}\tau_3 : T1 \rightarrow T1 \\ \tau_3 = \beta_1^{-1} \beta_2\end{split}\]- where the composition is left to right and \(\beta_i : T2 \rightarrow T1\) changes just the \(i\)-th coordinate of a triple. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: T1 = back_circulant(5) sage: x = isotopism( (0,1,2,3,4) ) sage: y = isotopism(5) # identity sage: z = isotopism(5) # identity sage: T2 = T1.apply_isotopism(x, y, z) sage: is_bitrade(T1, T2) True sage: (cells_map, t1, t2, t3) = tau123(T1, T2) sage: t3 = tau3(T1, T2, cells_map) sage: t3 [10, 6, 7, 8, 9, 15, 11, 12, 13, 14, 20, 16, 17, 18, 19, 25, 21, 22, 23, 24, 5, 1, 2, 3, 4] sage: t3.to_cycles() [(1, 10, 14, 18, 22), (2, 6, 15, 19, 23), (3, 7, 11, 20, 24), (4, 8, 12, 16, 25), (5, 9, 13, 17, 21)] - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> T1 = back_circulant(Integer(5)) >>> x = isotopism( (Integer(0),Integer(1),Integer(2),Integer(3),Integer(4)) ) >>> y = isotopism(Integer(5)) # identity >>> z = isotopism(Integer(5)) # identity >>> T2 = T1.apply_isotopism(x, y, z) >>> is_bitrade(T1, T2) True >>> (cells_map, t1, t2, t3) = tau123(T1, T2) >>> t3 = tau3(T1, T2, cells_map) >>> t3 [10, 6, 7, 8, 9, 15, 11, 12, 13, 14, 20, 16, 17, 18, 19, 25, 21, 22, 23, 24, 5, 1, 2, 3, 4] >>> t3.to_cycles() [(1, 10, 14, 18, 22), (2, 6, 15, 19, 23), (3, 7, 11, 20, 24), (4, 8, 12, 16, 25), (5, 9, 13, 17, 21)] 
- sage.combinat.matrices.latin.tau_to_bitrade(t1, t2, t3)[source]¶
- Given permutations t1, t2, t3 that represent a latin bitrade, convert them to an explicit latin bitrade (T1, T2). The result is unique up to isotopism. - EXAMPLES: - sage: from sage.combinat.matrices.latin import * sage: T1 = back_circulant(5) sage: x = isotopism( (0,1,2,3,4) ) sage: y = isotopism(5) # identity sage: z = isotopism(5) # identity sage: T2 = T1.apply_isotopism(x, y, z) sage: _, t1, t2, t3 = tau123(T1, T2) sage: U1, U2 = tau_to_bitrade(t1, t2, t3) sage: assert is_bitrade(U1, U2) sage: U1 [0 1 2 3 4] [1 2 3 4 0] [2 3 4 0 1] [3 4 0 1 2] [4 0 1 2 3] sage: U2 [4 0 1 2 3] [0 1 2 3 4] [1 2 3 4 0] [2 3 4 0 1] [3 4 0 1 2] - >>> from sage.all import * >>> from sage.combinat.matrices.latin import * >>> T1 = back_circulant(Integer(5)) >>> x = isotopism( (Integer(0),Integer(1),Integer(2),Integer(3),Integer(4)) ) >>> y = isotopism(Integer(5)) # identity >>> z = isotopism(Integer(5)) # identity >>> T2 = T1.apply_isotopism(x, y, z) >>> _, t1, t2, t3 = tau123(T1, T2) >>> U1, U2 = tau_to_bitrade(t1, t2, t3) >>> assert is_bitrade(U1, U2) >>> U1 [0 1 2 3 4] [1 2 3 4 0] [2 3 4 0 1] [3 4 0 1 2] [4 0 1 2 3] >>> U2 [4 0 1 2 3] [0 1 2 3 4] [1 2 3 4 0] [2 3 4 0 1] [3 4 0 1 2]