From 26423171f7e3daab8c4164b2bcba485df875dbdd Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 27 Apr 2014 10:18:16 +0200 Subject: [PATCH 01/18] trac #16248: Some trivial Orthogonal Arrays --- src/sage/combinat/designs/orthogonal_arrays.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/designs/orthogonal_arrays.py b/src/sage/combinat/designs/orthogonal_arrays.py index 45b1bfec647..7a6e0456baa 100644 --- a/src/sage/combinat/designs/orthogonal_arrays.py +++ b/src/sage/combinat/designs/orthogonal_arrays.py @@ -212,7 +212,9 @@ def orthogonal_array(k,n,t=2,check=True): sage: designs.orthogonal_array(4,2) Traceback (most recent call last): ... - EmptySetError: No Orthogonal Array exists when k>=n+t + EmptySetError: No Orthogonal Array exists when k>=n+t except when n=1 + sage: designs.orthogonal_array(16,1) + [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] """ from sage.rings.arith import is_prime_power from sage.rings.finite_rings.constructor import FiniteField @@ -221,13 +223,16 @@ def orthogonal_array(k,n,t=2,check=True): if k < 2: raise ValueError("undefined for k less than 2") + if n == 1: + OA = [[0]*k] + elif k >= n+t: from sage.categories.sets_cat import EmptySetError # When t=2 then k2 the submatrix defined by the rows whose first t-2 elements # are 0s yields a OA with t=2 and k-(t-2) columns. Thus k-(t-2) < n+2, # i.e. k=n+t") + raise EmptySetError("No Orthogonal Array exists when k>=n+t except when n=1") elif t != 2: raise NotImplementedError("only implemented for t=2") @@ -302,7 +307,8 @@ def is_orthogonal_array(M,k,n,t): if t != 2: raise NotImplementedError("only implemented for t=2") - if not all(len(l) == k for l in M): + if (not all(len(l) == k for l in M) or + len(M) != n**2): return False from itertools import combinations From d4f445b189ad16b28a436d9fd2fe82db53ebf3b1 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 2 May 2014 15:04:15 +0200 Subject: [PATCH 02/18] trac #16277: MOLS constructions rom the Handbook of Combinatorial Designs --- src/doc/en/reference/combinat/designs.rst | 1 + src/sage/combinat/designs/database.py | 1423 +++++++++++++++++ .../combinat/designs/orthogonal_arrays.py | 208 ++- 3 files changed, 1630 insertions(+), 2 deletions(-) create mode 100644 src/sage/combinat/designs/database.py diff --git a/src/doc/en/reference/combinat/designs.rst b/src/doc/en/reference/combinat/designs.rst index 4d414d18bf4..e4d7b1b4940 100644 --- a/src/doc/en/reference/combinat/designs.rst +++ b/src/doc/en/reference/combinat/designs.rst @@ -20,4 +20,5 @@ Constructions ../sage/combinat/designs/steiner_quadruple_systems ../sage/combinat/designs/latin_squares ../sage/combinat/designs/orthogonal_arrays + ../sage/combinat/designs/database diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py new file mode 100644 index 00000000000..479d53ce53c --- /dev/null +++ b/src/sage/combinat/designs/database.py @@ -0,0 +1,1423 @@ +r""" +Database of small combinatorial designs + +This module implements known constructions combinatorial designs, and in +particular of :mod:`Orthogonal Arrays +`. Most of them come from the chapter +on :mod:`Mutually Orthogonal Latin Squares +` from the Handbook of Combinatorial +Designs. + +All the designs returned by these functions can be obtained through the +``designs.`` functions. + +Implemented constructions : +:func:`OA(6,20) `, +:func:`OA(7,21) `, +:func:`OA(5,22) `, +:func:`OA(9,24) `, +:func:`OA(6,26) `, +:func:`OA(7,28) `, +:func:`OA(6,30) `, +:func:`OA(7,33) `, +:func:`OA(6,34) `, +:func:`OA(7,35) `, +:func:`OA(10,36) `, +:func:`OA(6,38) `, +:func:`OA(7,39) `, +:func:`OA(9,40) `, +:func:`OA(7,42) `, +:func:`OA(7,44) `, +:func:`OA(8,45) `, +:func:`OA(6,46) `, +:func:`OA(10,48) `, +:func:`OA(8,50) `, +:func:`OA(7,51) `, +:func:`OA(7,52) `, +:func:`OA(7,54) `, +:func:`OA(8,55) `, +:func:`OA(9,56) `, +:func:`OA(7,60) `, +:func:`OA(7,62) `, +:func:`OA(9,75) `, +:func:`OA(11,80) `, +:func:`OA(10,82) `, +:func:`OA(10,100) `, +:func:`OA(12,144) `, +:func:`OA(12,210) ` + +**Dictionaries** + +The functions defined here are used by +:func:`~sage.combinat.designs.orthogonal_arrays.orthogonal_array`. Thus, the +functions are indexed by a dictionary which associates to every integer ``n`` a +pair ``(k,f)`` where ``f`` is a function such that ``f()`` is a `OA(k,n)`. This +dictionary is defined in this module at the end of the file. + +REFERENCES: + +.. [DesignHandbook] Handbook of Combinatorial Designs (2ed) + Charles Colbourn, Jeffrey Dinitz + Chapman & Hall/CRC + 2012 + +Functions +--------- +""" + +from sage.combinat.designs.orthogonal_arrays import (OA_from_quasi_difference_matrix, + OA_from_Vmt, + OA_from_wider_OA) + +# Cyclic shift of a list +cyclic_shift = lambda l,i : l[-i:]+l[:-i] + +def OA_6_20(): + r""" + Returns an OA(6,20) + + As explained in the Handbook III.3.49 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(6,20) # indirect doctest + """ + M=[[None, 7, 13, 1, 16, 9, 2], + [ 0, 1, 15, 7, 17, 6, 14], + [ 0, 11, 10, 11, 5, 4, 3], + [ 7,None, 13, 16, 1, 2, 9], + [ 1, 0, 15, 17, 7, 14, 6], + [ 11, 0, 10, 5, 11, 3, 4]] + + Mb=[[],[],[],[],[],[]] + + for R in zip(*M): + a,b,c,d,e,f = R + Mb[0].extend([a,b,c]) + Mb[1].extend([b,c,a]) + Mb[2].extend([c,a,b]) + Mb[3].extend([d,f,e]) + Mb[4].extend([e,d,f]) + Mb[5].extend([f,e,d]) + + from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + M = OA_from_quasi_difference_matrix(Mb,AdditiveCyclic(19),add_col=False) + + return M + +def OA_7_21(): + r""" + Returns an OA(7,21) + + As explained in the Handbook III.3.50 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(7,21) # indirect doctest + """ + M = [[ 8, 17, 20, 2], + [ 9, 16, 4, 15], + [ 11, 5, 10, 6], + [ 14, 1, 3, 13], + [ 18, 19, 12, 7]] + + Mb = [[0],[0],[0],[0],[0],[0]] + for a,b,c,d,e in zip(*M): + Mb[0].extend([a,b,c,d,e]) + Mb[1].extend([b,c,d,e,a]) + Mb[2].extend([c,d,e,a,b]) + Mb[3].extend([d,e,a,b,c]) + Mb[4].extend([e,a,b,c,d]) + Mb[5].extend([0,0,0,0,0]) + + from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + M = OA_from_quasi_difference_matrix(Mb,AdditiveCyclic(21)) + return M + +def OA_5_22(): + r""" + Returns an OA(5,22) + + As explained in the Handbook III.3.51 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(5,22) # indirect doctest + """ + from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(21) + M = [ + [ 1, 13, 18, 3, 16, 19,None], + [ 16, 19, 1, 13, 18, 3, 0], + [ 18, 3, 16, 19, 1, 13, 0], + [ 6, 15, 6, 15, 6, 15, 0], + [ 12, 9, 19, 16, 5, 2, 0], + ] + + Mb=[[],[],[],[],[]] + + for R in zip(*M): + a,b,c,d,e = [G(x) if x is not None else None for x in R] + Mb[0].extend([a,16*c,4*b]) + Mb[1].extend([b,None if a is None else 16*a,4*c]) + Mb[2].extend([c,16*b,None if a is None else 4*a]) + Mb[3].extend([d,16*d+7,4*d+14]) + Mb[4].extend([e,16*e+14,4*e+7]) + + Mb[0].extend([0,0]) + Mb[1].extend([7,14]) + Mb[2].extend([14,7]) + Mb[3].extend([None,0]) + Mb[4].extend([0,None]) + + M = OA_from_quasi_difference_matrix(Mb,G,add_col=False) + return M + +def OA_9_24(): + r""" + Returns an OA(9,24) + + As explained in the Handbook III.3.52 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(9,24) # indirect doctest + """ + M = ("0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 "+ + "0000 0010 0100 0110 1000 1010 1100 1110 2000 2010 2100 2110 "+ + "0000 0011 1001 2110 0111 2011 2111 1000 0100 1100 1101 2010 "+ + "0000 1010 1011 2000 1101 2110 0001 0101 2100 2001 0111 1100 "+ + "0000 0001 2010 1111 2111 2100 1101 0011 1010 2101 1000 0110 "+ + "0000 1000 2001 1011 0100 1100 0110 2101 2111 0010 1111 2011 "+ + "0000 1001 0111 2100 2000 0010 1110 2011 1100 1011 0101 2111 "+ + "0000 1011 2101 0100 2110 1001 2000 0110 0101 1111 2011 1010 ") + + from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup + G = AdditiveAbelianGroup([3,2,2,2]) + rlabel = {(x%2,x%3):x for x in range(6)} + M = [G([int(c),int(d),rlabel[int(b),int(a)]]) for a,b,c,d in M.split()] + M = [M[i*12:(i+1)*12] for i in range(8)] + Mb = [[] for _ in range(8)] + for a,b,c,d,e,f,g,h in zip(*M): + Mb[0].extend([a, a + G([0,0,rlabel[0,0]])]) + Mb[1].extend([b, b + G([0,1,rlabel[0,0]])]) + Mb[2].extend([c, c + G([1,0,rlabel[0,0]])]) + Mb[3].extend([d, d + G([1,1,rlabel[0,0]])]) + Mb[4].extend([e, e + G([0,0,rlabel[1,0]])]) + Mb[5].extend([f, f + G([0,1,rlabel[1,0]])]) + Mb[6].extend([g, g + G([1,0,rlabel[1,0]])]) + Mb[7].extend([h, h + G([1,1,rlabel[1,0]])]) + + M = OA_from_quasi_difference_matrix(Mb,G) + return M + +def OA_6_26(): + r""" + Returns an OA(6,26) + + As explained in the Handbook III.3.53 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(6,26) # indirect doctest + """ + M = [ + [None,None,None,None,None], + [ 0, 0, 0, 0, 0], + [ 1, 6, 7, 8, 14], + [ 3, 11, 20, 18, 10], + [ 6, 10, 14, 1, 5], + [ 4, 19, 5, 12, 2], + ] + + from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(21) + Mb=[[0],[0],[0],[0],[0],[0]] + + for R in zip(*M): + a,b,c,d,e,f = R + Mb[0].extend([a,b,c,d,e,f]) + Mb[1].extend([b,c,d,e,f,a]) + Mb[2].extend([c,d,e,f,a,b]) + Mb[3].extend([d,e,f,a,b,c]) + Mb[4].extend([e,f,a,b,c,d]) + Mb[5].extend([f,a,b,c,d,e]) + + M = OA_from_quasi_difference_matrix(Mb,G,add_col = False) + return M + +def OA_7_28(): + r""" + Returns an OA(7,28) + + As explained in the Handbook III.3.54 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(7,28) # indirect doctest + """ + z=2 + M = [ + [(0,0), (z+1,6),(1,1) ,(1,1) ,(1,3) ,(1,4) ,(0,0) ,(1,4), (z,5) ], + [(z,2), (0,0) ,(1,5) ,(z,1) ,(z,2) ,(z,6) ,(z+1,3),(0,0), (z,1) ], + [(z,3), (z+1,4),(0,0) ,(z+1,5),(z+1,2),(z+1,4),(z+1,2),(1,6), (0,0) ], + [(0,5), (z,6) ,(0,5) ,(0,6) ,(z,3) ,(0,0) ,(0,4) ,(1,5), (z+1,4)], + [(0,3), (0,3) ,(z+1,5),(0,0) ,(0,5) ,(z+1,6),(1,1) ,(0,1), (z,3) ], + [(1,3), (0,6) ,(0,6) ,(1,5) ,(0,0) ,(0,3) ,(z+1,6),(z,2), (0,2) ], + ] + + from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup + from sage.modules.free_module_element import free_module_element as vector + G = AdditiveAbelianGroup([2,2,7]) + M = [[G(vector([x//2,x%2,y])) for x,y in L] for L in M] + + Mb=[[0],[0],[0],[0],[0],[0]] + + for R in zip(*M): + a,b,c,d,e,f = R + Mb[0].extend([a,b,c]) + Mb[1].extend([b,c,a]) + Mb[2].extend([c,a,b]) + Mb[3].extend([d,f,e]) + Mb[4].extend([e,d,f]) + Mb[5].extend([f,e,d]) + + M = OA_from_quasi_difference_matrix(Mb,G,add_col = True) + return M + +def OA_6_30(): + r""" + Returns an OA(6,30) + + As explained in the Handbook III.3.55 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(6,30) # indirect doctest + """ + M = [ + [(0,0),None,(0,0),(0,0),(0,0),(0,0),(0,0)], + [(0,0),(0,0),None,(0,4),(0,2),(0,3),(0,1)], + [(0,0),(3,1),(3,0),None,(4,0),(1,0),(2,0)], + [(0,0),(3,0),(0,2),(1,2),None,(0,1),(0,3)], + [(0,0),(3,3),(1,2),(4,2),(2,0),None,(0,4)], + [(0,0),(4,2),(2,4),(0,3),(2,3),(3,2),None] + ] + + from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup + from sage.modules.free_module_element import free_module_element as vector + G = AdditiveAbelianGroup([5,5]) + M = [[None if x is None else G(vector(x)) for x in L] for L in M] + + Mb=[[],[],[],[],[],[]] + + for R in zip(*M): + a,b,c,d,e,f = R + for i in range(5): + Mb[0].append(None if a is None else a+G(vector((i,i)))) + Mb[1].append(None if b is None else b+G(vector((2*i,i)))) + Mb[2].append(None if c is None else c+G(vector((i,0)))) + Mb[3].append(None if d is None else d+G(vector((4*i,0)))) + Mb[4].append(None if e is None else e+G(vector((3*i,4*i)))) + Mb[5].append(None if f is None else f+G(vector((4*i,4*i)))) + + M = OA_from_quasi_difference_matrix(Mb,G,add_col = False) + return M + +def OA_7_33(): + r""" + Returns an OA(7,33) + + As explained in the Handbook III.3.56 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(7,33) # indirect doctest + """ + M = [ + [ 0, 0, 0, 0, 0, 0], + [ 15, 11, 22, 4, 17, 8], + [ 19, 7, 14, 32, 22, 18], + [ 22, 19, 8, 24, 21, 6], + [ 9, 12, 15, 7, 26, 14], + [ 14, 28, 23, 2, 19, 3] + ] + + from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(33) + + Mb=[[0,1,7],[0,4,28],[0,16,13],[0,31,19],[0,25,10],[0,22,0]] + + for R in zip(*M): + a,b,c,d,e,f = R + for i in range(5): + Mb[0].append(a) + Mb[1].append(b) + Mb[2].append(c) + Mb[3].append(d) + Mb[4].append(e) + Mb[5].append(f) + a,b,c,d,e,f = 4*e,4*a,4*b,4*c,4*d,4*f + + M = OA_from_quasi_difference_matrix(Mb,G,add_col = True) + return M + +def OA_6_34(): + r""" + Returns an OA(6,34) + + As explained in the Handbook III.3.57 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(6,34) # indirect doctest + """ + M = [ + [None, 0, 0, 0, 0, 0], + [ 30, 17, 10, 25, 23, 8], + [ 22, 4, 32, 29, 28, 22], + [ 25, 10, 20, 15, 21, 16], + [ 0, 12, 15, 16, 32, 23], + [ 6, 11, 18, 14, 9, 20] + ] + + from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(33) + + Mb=[[0,1,3,10,5],[0,4,12,7,20],[0,16,15,28,14],[0,31,27,13,23],[0,25,9,19,26],[0,11,11,0,None]] + + times4 = lambda x : None if x is None else 4*x + for R in zip(*M): + a,b,c,d,e,f = [None if x is None else G(x) for x in R] + for i in range(5): + Mb[0].append(a) + Mb[1].append(b) + Mb[2].append(c) + Mb[3].append(d) + Mb[4].append(e) + Mb[5].append(f) + a,b,c,d,e,f = map(times4,[e,a,b,c,d,f]) + + M = OA_from_quasi_difference_matrix(Mb,G,add_col = False) + return M + +def OA_7_35(): + r""" + Returns an OA(7,35) + + As explained in the Handbook III.3.58 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(7,35) # indirect doctest + """ + M = [ + [ 0, 15, 30, 10, 25, 1, 16, 31, 11, 26, 2, 17, 32, 12, 6, 3, 18, 33, 27, 21, 4, 19, 13, 7, 22, 5, 34, 28, 8, 23, 20, 14, 29, 9, 24], + [ 0, 22, 16, 3, 4, 9, 10, 32, 26, 13, 18, 5, 27, 14, 15, 20, 7, 1, 23, 31, 29, 2, 24, 11, 19, 17, 25, 12, 6, 28, 33, 34, 21, 8, 30], + [ 0, 29, 2, 31, 18, 10, 32, 26, 34, 28, 27, 21, 15, 9, 17, 30, 3, 4, 5, 20, 12, 6, 14, 22, 16, 8, 23, 24, 25, 33, 11, 19, 13, 7, 1], + [ 0, 8, 9, 17, 11, 25, 19, 27, 28, 1, 15, 23, 31, 4, 26, 12, 6, 14, 29, 16, 2, 3, 18, 33, 34, 20, 7, 22, 30, 24, 10, 32, 5, 13, 21], + [ 0, 1, 23, 24, 32, 33, 6, 7, 29, 30, 10, 11, 12, 13, 28, 8, 9, 31, 4, 5, 27, 14, 15, 16, 3, 25, 26, 34, 21, 22, 2, 17, 18, 19, 20], + [0]*35 + ] + + from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(35) + + M = OA_from_quasi_difference_matrix(M,G,add_col = True) + return M + +def OA_10_36(): + r""" + Returns an OA(10,36) + + As explained in the Handbook III.3.59 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(10,36) # indirect doctest + """ + M = [ + [(0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0)], + [(0,0,0,0), (0,1,0,0), (1,0,0,0), (1,1,0,0), (0,0,0,1), (0,1,0,1), (1,0,0,1), (1,1,0,1), (0,0,0,2), (0,1,0,2), (1,0,0,2), (1,1,0,2)], + [(0,0,0,0), (1,1,1,2), (0,0,2,1), (0,0,1,2), (0,1,2,0), (0,1,0,2), (1,1,1,1), (0,1,1,1), (1,1,1,0), (1,0,2,2), (1,0,0,1), (1,0,1,0)], + [(0,0,0,0), (0,0,1,0), (1,0,1,0), (0,1,0,0), (1,1,0,0), (1,0,2,0), (1,0,0,0), (0,1,2,0), (1,1,2,0), (0,0,2,0), (1,1,1,0), (0,1,1,0)], + [(0,0,0,0), (0,1,2,0), (0,0,1,0), (1,1,1,0), (1,0,2,0), (1,0,1,0), (0,1,0,0), (0,0,2,0), (0,1,1,0), (1,1,0,0), (1,1,2,0), (1,0,0,0)], + [(0,0,0,0), (0,1,1,0), (0,1,2,0), (1,1,2,0), (1,1,0,2), (0,0,1,2), (1,1,2,2), (1,0,0,2), (1,0,0,1), (1,0,1,1), (0,0,2,1), (0,1,1,1)], + [(0,0,0,0), (1,0,1,0), (1,1,0,1), (1,0,1,2), (1,0,2,2), (0,0,2,1), (0,1,0,1), (0,1,0,0), (1,1,2,2), (0,1,1,0), (0,0,1,2), (1,1,2,1)], + [(0,0,0,0), (1,1,0,0), (0,1,1,0), (1,0,2,1), (0,1,0,2), (1,0,2,2), (0,0,2,2), (1,1,1,0), (1,0,1,1), (0,1,2,1), (1,1,1,1), (0,0,0,2)], + [(0,0,0,0), (1,0,0,0), (1,1,1,0), (0,1,1,2), (1,1,2,1), (0,1,1,1), (0,0,1,1), (1,0,2,0), (0,1,2,2), (1,1,0,2), (1,0,2,2), (0,0,0,1)] + ] + + from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup + from sage.modules.free_module_element import free_module_element as vector + G = AdditiveAbelianGroup([2,2,3,3]) + M = [[G(vector(x)) for x in L] for L in M] + + Mb=[[],[],[],[],[],[],[],[],[]] + + for R in zip(*M): + a,b,c,d,e,f,g,h,i = R + for y in range(3): + Mb[0].append(a+G(vector([0,0,0,0]))) + Mb[1].append(b+G(vector([0,0,y,0]))) + Mb[2].append(c+G(vector([0,0,2*y,0]))) + Mb[3].append(d+G(vector([0,0,0,y]))) + Mb[4].append(e+G(vector([0,0,0,2*y]))) + Mb[5].append(f+G(vector([0,0,y,y]))) + Mb[6].append(g+G(vector([0,0,2*y,2*y]))) + Mb[7].append(h+G(vector([0,0,y,2*y]))) + Mb[8].append(i+G(vector([0,0,2*y,y]))) + + M = OA_from_quasi_difference_matrix(Mb,G,add_col = True) + return M + +def OA_6_38(): + r""" + Returns an OA(6,38) + + As explained in the Handbook III.3.60 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(6,38) # indirect doctest + """ + M = [ + [None, 10, 1, 2, 6, 3, 22, 5, 7, 9, 14, 18, 28], + [ 0, 1, 10, 20, 23, 30, 35, 13, 33, 16, 29, 32, 21], + [ 0, 26, 26, 15, 8, 4, 17, 19, 34, 12, 31, 24, 25], + [ 10,None, 10, 6, 2, 22, 3, 7, 5, 14, 9, 28, 18], + [ 1, 0, 26, 23, 20, 35, 30, 33, 13, 29, 16, 21, 32], + [ 26, 0, 1, 8, 15, 17, 4, 34, 19, 31, 12, 25, 24] + ] + + from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(37) + + Mb=[[],[],[],[],[],[]] + + for R in zip(*M): + a,b,c,d,e,f = R + Mb[0].extend([a,b,c]) + Mb[1].extend([b,c,a]) + Mb[2].extend([c,a,b]) + Mb[3].extend([d,f,e]) + Mb[4].extend([e,d,f]) + Mb[5].extend([f,e,d]) + + M = OA_from_quasi_difference_matrix(Mb,G,add_col = False) + return M + +def OA_7_39(): + r""" + Returns an OA(7,39) + + As explained in the Handbook III.3.61 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(7,39) # indirect doctest + """ + M = [ + [ 0, 0, 0, 0, 0, 0], + [ 4, 23, 13, 5, 12, 11], + [ 25, 11, 22, 34, 23, 6], + [ 13, 4, 20, 17, 15, 29], + [ 27, 21, 8, 16, 19, 26], + [ 16, 19, 34, 38, 26, 21] + ] + + from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(39) + + Mb=[[0,1,-1],[0,16,-16],[0,22,-22],[0,17,-17],[0,38,-38],[0,23,-23]] + + for R in zip(*M): + a,b,c,d,e,f = [None if x is None else G(x) for x in R] + for i in range(3): + Mb[0].extend([a,-a]) + Mb[1].extend([b,-b]) + Mb[2].extend([c,-c]) + Mb[3].extend([d,-d]) + Mb[4].extend([e,-e]) + Mb[5].extend([f,-f]) + a,b,c,d,e,f = [16*x for x in [c,a,b,f,d,e]] + + M = OA_from_quasi_difference_matrix(Mb,G,add_col = True) + return M + +def OA_9_40(): + r""" + Returns an OA(9,40) + + As explained in the Handbook III.3.62 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(9,40) # indirect doctest + """ + from sage.rings.finite_rings.constructor import FiniteField + + F8 = FiniteField(8,'x') + F5 = FiniteField(5) + F5F8 = F5.cartesian_product(F8) + w = F8.primitive_element() + assert w**3 == w+1 + + A = [ + [(0,None),(0,None),(0,None),(0,None),(0,None),(0,None),(0,None),(0,None),(0,None),(0,None)], + [(0,None),(1,None), (2,2), (3,2), (4,2),(2,None),(3,None),(4,None), (0,2), (1,2)], + [(0,None), (2,5), (4,5), (1,2), (3,6), (3,4), (0,0), (2,1), (4,1), (1,6)], + [(0,None), (3,4), (1,4), (4,0), (2,5),(3,None), (1,0), (4,1), (2,2), (0,3)], + [(0,None), (4,6),(3,None), (2,3), (1,4), (2,1),(1,None), (0,4), (4,0), (3,2)], + [(0,None), (1,2), (4,6), (4,4), (1,0), (0,6), (2,3), (3,6), (3,5), (2,5)], + [(1,None), (0,3), (1,2), (4,5),(4,None), (2,3), (0,0), (2,2), (3,0),(3,None)], + [(4,None), (1,3), (0,0), (1,1), (4,0), (3,1), (2,5),(0,None), (2,1),(3,None)] + ] + Y = [ + [None, 0, 1, 6, 5, 4, 3, 2], + [None, 1, 2, 0, 6, 5, 4, 3], + ] + r = lambda x : F8(0) if x is None else w**x + + A = [[(F5(a),r(b)) for a,b in L] for L in A] + Y = [[r(b) for b in L] for L in Y] + + def t(i,(x,y)): + a,b = A[x][y] + b = Y[i][x] + return F5F8((F5(0),b)) + + R = {w:(0,1,0), + w**2:(1,0,0), + w**3:(0,1,1), + w**4:(1,1,0), + w**5:(1,1,1), + w**6:(1,0,1), + w**7:(0,0,1), + F8(0):(0,0,0) + } + Mb = [[] for _ in range(8)] + for y in range(len(A[0])): + for x in range(len(A)): + t1,t2 = t(0,(x,y)), t(1,(x,y)) + e = F5F8(A[x][y]) + Mb[x].extend([e,e+t1,e+t2,e+t1+t2]) + + M = OA_from_quasi_difference_matrix(Mb,F5F8,add_col = True) + return M + +def OA_7_42(): + r""" + Returns an OA(7,42) + + As explained in the Handbook III.3.63 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(7,42) # indirect doctest + """ + M = [ + [None,None,None,None,None,None,None], + [ 0, 0, 0, 0, 0, 0, 0], + [ 18, -18, 11, -11, 5, -5, 4], + [ 26, -26, 10, -10, 30, -30, 23], + [ 20, -20, 3, -3, 33, -33, 23], + [ 5, -5, 25, -25, 24, -24, 4], + [ 17, -17, 4, -4, 22, -22, 0] + ] + + from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(35) + + Mb=[[],[],[],[],[],[],[]] + + for R in zip(*M): + for i in range(7): + Mb[i].extend(cyclic_shift(R,i)) + + M = OA_from_quasi_difference_matrix(Mb,G,add_col = False) + return M + +def OA_7_44(): + r""" + Returns an OA(7,44) + + As explained in the Handbook III.3.64 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(7,44) # indirect doctest + """ + from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + from sage.categories.cartesian_product import cartesian_product + + G2 = AdditiveCyclic(2) + G11 = AdditiveCyclic(11) + G2211 = cartesian_product((G2,G2,G11)) + + M = [ + [(0,0,0), (0,0,0), (0,0,0), (0,0,0), (0,0,0), (0,0,0), (0,0,0), (0,0,0)], + [(1,1,4), (0,1,4), (1,1,7), (1,0,6), (1,1,9), (0,1,2), (0,1,5), (0,1,1)], + [(1,0,6), (0,1,3), (1,0,0), (0,1,9), (1,1,1), (0,1,4), (1,1,9), (1,0,9)], + [(1,1,6), (1,1,9), (0,1,2), (1,1,0), (0,1,0), (1,1,5), (0,0,4), (0,0,9)], + [(1,0,9), (0,0,2), (0,0,1), (1,0,2), (0,0,7), (1,1,6), (1,1,0), (1,0,7)], + [(1,0,1), (1,0,6), (1,1,3), (0,1,5), (0,0,5), (0,1,3), (0,1,0), (1,1,0)] + ] + + M = [[G2211(x) for x in L] for L in M] + + Mb=[[],[],[],[],[],[]] + + for R in zip(*M): + for c in range(5): + (x1,y1,z1),(x2,y2,z2),(x3,y3,z3),(x4,y4,z4),(x5,y5,z5),(x6,y6,z6) = R + for i,e in enumerate(R): + Mb[i].append(e) + R = [(x5,y5,5*z5), + (x1,y1,5*z1), + (x2,y2,5*z2), + (x3,y3,5*z3), + (x4,y4,5*z4), + (x6,y6,5*z6)] + + for x,y,z in [(0,0,0), (1,0,1),(1,1,2),(0,0,8)]: + Mb[0].append((x,y,z)) + Mb[1].append((x,y,5*z)) + Mb[2].append((x,y,3*z)) + Mb[3].append((x,y,4*z)) + Mb[4].append((x,y,9*z)) + Mb[5].append((0,0,0)) + + M = OA_from_quasi_difference_matrix(Mb,G2211,add_col = True) + return M + +def OA_8_45(): + r""" + Returns an OA(8,45) + + As explained in the Handbook III.3.65 [DesignHandbook]_. + + ... whose description contained a very deadly typo, kindly fixed by Julian + R. Abel. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(8,45) # indirect doctest + """ + from sage.rings.finite_rings.constructor import FiniteField + from sage.categories.cartesian_product import cartesian_product + + G533 = cartesian_product((FiniteField(5),FiniteField(3),FiniteField(3))) + + M = [ + [(0,0,0), (2,2,1), (3,1,1), (4,1,2), (4,0,1), (0,1,1), (0,2,1), (3,2,2)], + [(0,0,0), (1,2,1), (4,2,2), (1,2,0), (4,1,0), (3,1,1), (3,0,0), (2,1,2)], + [(0,0,0), (4,1,1), (2,2,1), (3,2,0), (1,2,0), (2,1,0), (1,0,0), (3,2,1)], + [(0,0,0), (0,1,0), (2,1,1), (4,0,0), (0,0,2), (4,2,2), (3,2,2), (1,2,2)], + [(0,0,0), (3,1,2), (2,1,0), (0,2,2), (4,2,1), (0,2,1), (2,0,1), (1,1,2)], + [(0,0,0), (2,1,1), (1,2,2), (3,0,1), (2,0,1), (1,0,0), (4,2,1), (1,1,0)], + [(0,0,0), (0,0,0), (0,0,0), (0,0,0), (0,0,0), (0,0,0), (0,0,0), (0,0,0)] + ] + + for i in range(6): + M[i].extend(M[5-i][1:8]) + + M[6].extend(M[6][1:8]) + + Mb=[[],[],[],[],[],[],[]] + + for R in zip(*M): + (x1,y1,z1),(x2,y2,z2),(x3,y3,z3),(x4,y4,z4),(x5,y5,z5),(x6,y6,z6),(x7,y7,z7) = R + for i in range(3): + Mb[0].append((x1, y1 , z1+i )) + Mb[1].append((x2, y2+2*i, z2 )) + Mb[2].append((x3, y3+i , z3+2*i)) + Mb[3].append((x4, y4+2*i, z4+i )) + Mb[4].append((x5, y5+i , z5 )) + Mb[5].append((x6, y6 , z6+2*i)) + Mb[6].append((x7, y7 , z7 )) + + M = OA_from_quasi_difference_matrix(Mb,G533,add_col = True) + return M + +def OA_6_46(): + r""" + Returns an OA(6,46) + + As explained in the Handbook III.3.66 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_Vmt` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(6,46) # indirect doctest + """ + M = OA_from_Vmt(4,9,[0, 1, 3, 2, 8]) + return M + +def OA_10_48(): + r""" + Returns an OA(10,48) + + As explained in the Handbook III.3.67 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(10,48) # indirect doctest + """ + from sage.rings.finite_rings.constructor import FiniteField + F16 = FiniteField(16,'x') + F3 = FiniteField(3) + F3F16 = F3.cartesian_product(F16) + w = F16.primitive_element() + assert w**4 == w+1 + + A = [ + [ (0, 4), (2, 2), (2,2), (0,13), (0,4), (2,13), (0,1), (0,7), (1,7) , (2,2) , (0,6), (2,9)], + [ (2, 7), (0, 9), (2,7), (2,3) , (0,3), (0,9) , (1,12), (0,6), (0,12), (2,14), (2,7), (0,11)], + [ (2,12), (2,12), (0,14), (0,14), (2,8), (0,8) , (0,2), (1,2), (0,11), (0,1) , (2,4), (2,12)], + [ (1, 3), (0, 2), (0,10), (0,14), (0,9), (1,3) , (0,12), (2,13), (2,1) , (2,9) , (2,0), (1,7)], + [ (0, 0), (1, 8), (0,7), (1,8) , (0,4), (0,14), (2,6), (0,2), (2,3) , (1,12), (2,14), (2,5)], + [ (0,12), (0, 5), (1,13), (0,4) , (1,13), (0,9) , (2,8), (2,11), (0,7) , (2,10), (1,2), (2,4)], + [ (1,12), (2, 0), (1,14), (0,6) , (1,9), (0,14), (1,4), (0,5), (1,8) , (1,3) , (2,1), (1,1)], + [ (1, 4), (1, 2), (2,5), (0,4) , (0,11), (1,14), (1,13), (1,9), (0,10), (1,6) , (1,8), (2,6)], + [ (2,10), (1, 9), (1,7), (1,4) , (0,9), (0,1) , (0,0), (1,3), (1,14), (2,11), (1,11), (1,13)], + ] + + A = [[F3F16((F3(a),w**b)) for a,b in L] for L in A] + + Mb = [[] for _ in range(9)] + for L in zip(*A): + for i,e in enumerate(L): + Mb[i].append(e) + + for u in [0,1,4]: + V = [12,2,7,0,5,10,3,8,13] + for i,(e,x) in enumerate(zip(L,V)): + Mb[i].append(e+F3F16((F3(0),w**(x+u)))) + + M = OA_from_quasi_difference_matrix(Mb,F3F16,add_col = True) + return M + +def OA_8_50(): + r""" + Returns an OA(8,50) + + As explained in the Handbook III.3.68 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_Vmt` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(8,50) # indirect doctest + """ + M = OA_from_Vmt(6,7,[0, 1, 3, 16, 35, 26, 36]) + return M + +def OA_7_51(): + r""" + Returns an OA(7,51) + + As explained in the Handbook III.3.69 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(7,51) # indirect doctest + """ + from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(51) + + M = [ + [ 5, 33, 29, 30, 1], + [ 8, 3, 47, 10, 13], + [ 14, 27, 6, 12, 28], + [ 9, 16, 44, 49, 11], + [ 34, 32, 36, 26, 20] + ] + + Mb=[[0],[0],[0],[0],[0],[0]*51] + + for R in zip(*M): + for i in range(5): + for RR in [R, [-x for x in R]]: + for i,x in enumerate(RR): + Mb[i].append(x) + R = cyclic_shift(R,1) + + M = OA_from_quasi_difference_matrix(Mb,G,add_col = True) + return M + +def OA_7_52(): + r""" + Returns an OA(7,52) + + As explained in the Handbook III.3.70 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(7,52) # indirect doctest + """ + from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + from sage.rings.finite_rings.constructor import FiniteField + F4 = FiniteField(4,'z') + G13 = FiniteField(13) + G = F4.cartesian_product(G13) + z = F4('z') + assert z**2 == z+1 + + M = [ + [ (0,0), (0,0), (0,0), (0,0), (0,0)], + [(z**2,10), (0,7), (1,10), (z,10),(z**2,3)], + [ (z,10), (z**2,2), (1,11), (z,2),(z**2,7)], + [ (z,8),(z**2,12), (0,10),(z**2,11),(z**2,6)], + [ (1,2), (0,2), (z**2,8), (z,3), (z,7)], + [ (1,6), (z,12), (0,7), (z**2,6), (z,2)] + ] + + M2 = [ + [ (1,1),(z**2,11)], + [ (z,3), (1,7)], + [ (z**2,9), (z,8)], + [ (1,4), (z**2,3)], + [ (z,12), (1,9)], + [(z**2,10), (z,1)] + ] + + M = [[G(x) for x in L] for L in M] + M2= [[G(x) for x in L] for L in M2] + + Mb=[[(0,0)]*6] + + from itertools import product + p = lambda x,y : G(tuple([x*yy for yy in G(y)])) + + def t1(i,R): + if i > 1: + return t1(1,t1(i-1,R)) + ((x1,y1),(x2,y2),(x3,y3),(x4,y4),(x5,y5),(x6,y6)) = R + return [(z*x3, 3*y3), (z*x1, 3*y1), (z*x2, 3*y2), (z*x6, 3*y6), (z*x4, 3*y4), (z*x5, 3*y5)] + + def t2(i,R): + if i > 1: + return t2(1,t2(i-1,R)) + ((x1,y1),(x2,y2),(x3,y3),(x4,y4),(x5,y5),(x6,y6)) = R + return [( x3, y3), ( x1, y1), ( x2, y2), ( x5, y5), ( x6, y6), ( x4, y4)] + + for R in zip(*M): + for c1,c2 in product([1,2,3],repeat=2): + Mb.append(t2(c2,t1(c1,R))) + + for R in zip(*M2): + for c2 in [1,2,3]: + Mb.append(t2(c2,R)) + + Mb = zip(*Mb) + M = OA_from_quasi_difference_matrix(Mb,G,add_col = True) + return M + +def OA_7_54(): + r""" + Returns an OA(7,54) + + As explained in the Handbook III.3.71 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(7,54) # indirect doctest + """ + from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(45) + + M = [ + [None,None,None,None,None,None,None,None,None], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0], + [ 1, 27, 16, 7, -1, -27, -16, -7, 3], + [ 24, 40, 1, 35, -24, -40, -1, -35, 7], + [ 10, 30, 22, 44, -10, -30, -22, -44, 7], + [ 5, 18, 14, 33, -5, -18, -14, -33, 3], + [ 30, 16, 33, 27, -30, -16, -33, -27, 0], + ] + + Mb=[[] for _ in range(7)] + + for R in zip(*M): + for c in range(7): + for i,x in enumerate(cyclic_shift(R,c)): + Mb[i].append(x) + + M = OA_from_quasi_difference_matrix(Mb,G,add_col = False) + return M + +def OA_8_55(): + r""" + Returns an OA(8,55) + + As explained in the Handbook III.3.72 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(8,55) # indirect doctest + """ + from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(55) + + M = [ + [ 1 , 7 , 14 , 19 , 28 , 33 , 40 , 46 , 50], + [ 2 , 13 , 25 , 38 , 52 , 12 , 20 , 32 , 45], + [ 39 , 6 , 8 , 26 , 24 , 51 , 11 , 34 , 37], + [ 54 , 48 , 41 , 36 , 27 , 22 , 15 , 9 , 5], + [ 53 , 42 , 30 , 17 , 3 , 43 , 35 , 23 , 10], + [ 16 , 49 , 47 , 29 , 31 , 4 , 44 , 21 , 18] + ] + + Mb=[[0],[0],[0],[0],[0],[0],[0]*55] + + for R in zip(*M): + for c in range(6): + for i,x in enumerate(cyclic_shift(R,c)): + Mb[i].append(x) + + M = OA_from_quasi_difference_matrix(Mb,G,add_col = True) + return M + + +def OA_9_56(): + r""" + Returns an OA(9,56) + + As explained in the Handbook III.3.73 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(9,56) # indirect doctest + """ + from sage.rings.finite_rings.constructor import FiniteField + F8 = FiniteField(8,'z') + F7 = FiniteField(7) + G = F8.cartesian_product(F7) + + w = F8.primitive_element() + assert w**3 == w+1 + + M = [ + [(0,0), (w**0,0), (w**1,0), (w**2,0), (w**3,0), (w**4,0), (w**5,0), (w**6,0)], + [(0,1), (w**1,6), (w**2,1), (w**3,1), (w**4,6), (w**5,1), (w**6,6), (w**0,6)], + [(0,4), (w**2,3), (w**3,4), (w**4,4), (w**5,3), (w**6,4), (w**0,3), (w**1,3)], + [(0,2), (w**3,5), (w**4,2), (w**5,2), (w**6,5), (w**0,2), (w**1,5), (w**2,5)], + [(0,2), (w**4,5), (w**5,2), (w**6,2), (w**0,5), (w**1,2), (w**2,5), (w**3,5)], + [(0,4), (w**5,3), (w**6,4), (w**0,4), (w**1,3), (w**2,4), (w**3,3), (w**4,3)], + [(0,1), (w**6,6), (w**0,1), (w**1,1), (w**2,6), (w**3,1), (w**4,6), (w**5,6)], + [(1,0), ( 1,0), ( 1,0), ( 1,0), ( 1,0), ( 1,0), ( 1,0), ( 1,0)] + ] + + Mb=[[] for _ in range(8)] + + for R in zip(*M): + for _ in range(7): + for i,e in enumerate(R): + Mb[i].append(e) + (x1,y1),(x2,y2),(x3,y3),(x4,y4),(x5,y5),(x6,y6),(x7,y7),(x8,y8) = R + R = [(w*x7,y7), (w*x1,y1), (w*x2,y2), (w*x3,y3), (w*x4,y4), (w*x5,y5), (w*x6,y6), (w*x8,y8)] + + M = OA_from_quasi_difference_matrix(Mb,G,add_col = True) + return M + +def OA_7_60(): + r""" + Returns an OA(7,60) + + As explained in [JulianAbel13]_. + + REFERENCES: + + .. [JulianAbel13] Existence of Five MOLS of Orders 18 and 60 + R. Julian R. Abel + Journal of Combinatorial Designs + 2013 + + http://onlinelibrary.wiley.com/doi/10.1002/jcd.21384/abstract + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(7,60) # indirect doctest + """ + M60 = [[(0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)], + [(1, 10), (1, 6), (0, 17), (0, 7), (1, 5), (0, 9), (0, 3), (1, 13), (1, 17), (0, 13)], + [(1, 22), (1, 1), (1, 8), (0, 9), (1, 21), (1, 29), (1, 0), (0, 2), (0, 12), (1, 15)], + [(1, 24), (1, 1), (0, 14), (0, 0), (0, 16), (0, 18), (0, 8), (0, 28), (0, 17), (0, 7)], + [(0, 17), (0, 7), (0, 20), (0, 1), (1, 4), (0, 26), (0, 19), (0, 28), (1, 21), (0, 6)], + [(1, 14), (1, 9), (0, 10), (0, 27), (1, 20), (0, 11), (0, 13), (1, 12), (0, 28), (1, 18)]] + + from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup + G = AdditiveAbelianGroup([2,30]) + M60b=[[],[],[],[],[],[]] + onezero = G((1,0)) + + for R in zip(*M60): + a,b,c,d,e,f = map(G,R) + M60b[0].extend([a,c,b,-d,-e,-f]) + M60b[1].extend([b,a,c,-e,-f,-d]) + M60b[2].extend([c,b,a,-f,-d,-e]) + M60b[3].extend([d,e,f,-a+onezero,-c+onezero,-b+onezero]) + M60b[4].extend([e,f,d,-b+onezero,-a+onezero,-c+onezero]) + M60b[5].extend([f,d,e,-c+onezero,-b+onezero,-a+onezero]) + + M = OA_from_quasi_difference_matrix(M60b,G) + return M + +def OA_7_62(): + r""" + Returns an OA(7,62) + + As explained in the Handbook III.3.74 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(7,62) # indirect doctest + """ + from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(54) + + M = [ + [ 0 ,None,None,None, 0 ,None ,None ,None,None,None], + [17 , 0 , 0 , 0 , -17 , 0 , 0 , 0 , 1 , 11 ], + [29 , 28 , 35 , 23 , -29 , -28 , -35 , -23, 3 , 19 ], + [36 , 50 , 5 , 33 , -36 , -50 , -5 , -33, 7 , 33 ], + [31 , 2 , 43 , 30 , -31 , - 2 , -43 , -30, 34 , 33 ], + [16 , 47 , 44 , 51 , -16 , -47 , -44 , -51, 30 , 19 ], + [41 , 11 , 1 , 17 , -41 , -11 , - 1 , -17, 28 , 11 ] + ] + + Mb=[[] for _ in range(7)] + + for R in zip(*M): + for c in range(7): + for i,x in enumerate(cyclic_shift(R,c)): + Mb[i].append(x) + + M = OA_from_quasi_difference_matrix(Mb,G,add_col = False) + return M + +def OA_9_75(): + r""" + Returns an OA(9,75) + + As explained in the Handbook III.3.75 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(9,75) # indirect doctest + """ + from sage.rings.finite_rings.constructor import FiniteField + from sage.categories.cartesian_product import cartesian_product + + F3 = FiniteField(3) + F5 = FiniteField(5) + G = cartesian_product((F3,F5,F5)) + + M = [ + [(2,0,0), (0,0,0), (0,0,0), (1,0,0), (0,0,0), (1,0,0), (1,0,0), (0,0,0)], + [(0,2,3), (1,4,4), (1,1,3), (1,0,4), (2,4,3), (0,0,3), (1,4,4), (0,0,0)], + [(1,3,2), (2,1,1), (1,4,0), (0,3,0), (1,0,4), (2,4,1), (0,1,2), (0,0,0)], + [(0,2,4), (1,3,1), (2,0,2), (0,0,1), (2,4,0), (1,2,2), (0,0,0), (0,0,0)], + [(1,1,2), (2,2,3), (0,3,1), (1,4,2), (2,1,0), (1,4,3), (2,4,4), (0,0,0)], + [(0,1,4), (0,4,4), (2,4,1), (1,3,0), (1,3,1), (2,0,0), (2,4,0), (0,0,0)], + [(0,4,4), (2,0,1), (2,3,3), (2,3,2), (0,0,2), (2,1,2), (1,4,2), (0,0,0)], + [(2,4,2), (2,4,1), (2,3,1), (1,2,2), (1,3,0), (0,0,2), (2,4,2), (0,0,0)] + ] + + for i in range(8): + M[i].extend(M[7-i][:7]) + + Mb=[] + + for R in zip(*M): + for x in range(5): + V = [(0,0,x), (0,x,0), (0,x,2*x),(0,2*x,2*x), (0,3*x,3*x), (0,4*x,3*x), (0,4*x,0), (0,0,4*x)] + Mb.append([G(e)+G(ee) for e,ee in zip(R,V)]) + + Mb = zip(*Mb) + M = OA_from_quasi_difference_matrix(Mb,G,add_col = True) + return M + +def OA_11_80(): + r""" + Returns an OA(11,80) + + As explained in the Handbook III.3.76 [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(11,80) # indirect doctest + """ + from sage.rings.finite_rings.constructor import FiniteField + F16 = FiniteField(2**4,'w') + F5 = FiniteField(5) + G = F5.cartesian_product(F16) + + w = F16.primitive_element() + assert w**4 == w+1 + + A = [ + [(0,None), (0,None), (0,None), (0,None), (0,None), (0,None), (0,None), (0,None), (0,None), (0,None)], + [(0,None), (1,None), (2,3), (3,None), (4,3), (2,None), (3,3), (4,None), (0,3), (1,3)], + [(0,None), (2,8), (4,6), (1,3), (3,3), (3,13), (0,13), (2,6), (4,14), (1,12)], + [(0,None), (3,11), (1,0), (4,9), (2,0), (3,7), (1,8), (4,10), (2,10), (0,11)], + [(0,None), (4,8), (3,14), (2,14), (1,12), (2,10), (1,10), (0,3), (4,5), (3,8)], + [(0,None), (1,8), (4,14), (4,12), (1,1), (0,1), (2,8), (3,12), (3,6), (2,1)], + [(1,None), (0,6), (1,1), (4,4), (4,13), (2,6), (0,14), (2,9), (3,0), (3,3)], + [(4,None), (1,9), (0,7), (1,1), (4,8), (3,5), (2,14), (0,0), (2,None), (3,0)], + [(4,None), (4,6), (1,2), (0,None), (1,13), (3,8), (3,2), (2,0), (0,14), (2,None)], + [(1,None), (4,9), (4,1), (1,0), (0,4), (2,5), (3,None), (3,5), (2,None), (0,None)] + ] + Y = [ + [None, 0, 1, 14, 12, 7, 2, 11, 3, 6], + [None, 1, 2, 0 , 13, 8, 3, 12, 4, 7], + [None, 2, 3, 1 , 14, 9, 4, 13, 5, 8] + ] + r = lambda x : F16(0) if x is None else w**x + + A = [[(F5(a),r(b)) for a,b in L] for L in A] + Y = [[r(b) for b in L] for L in Y] + + def t(i,(x,y)): + a,b = A[x][y] + b = Y[i][x] + return G((F5(0),b)) + + Mb = [[] for _ in range(10)] + + for y in range(len(A[0])): + for x in range(len(A)): + t1,t2,t3 = t(0,(x,y)), t(1,(x,y)), t(2,(x,y)) + e = G(A[x][y]) + Mb[x].extend([e,e+t1,e+t2,e+t1+t2,e+t3,e+t3+t1,e+t3+t2,e+t3+t2+t1]) + + M = OA_from_quasi_difference_matrix(Mb,G,add_col = True) + return M + +def OA_10_82(): + r""" + Returns an OA(10,82) + + Given by Julian R. Abel, using a `V(m,t)` from the Handbook + [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_Vmt` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(10,82) # indirect doctest + """ + M = OA_from_Vmt(8,9,[0,1,20,70,23,59,3,8,19]) + return M + +def OA_10_100(): + r""" + Returns an OA(10,100) + + Given by Julian R. Abel, using a `V(m,t)` from the Handbook + [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_Vmt` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(10,100) # indirect doctest + """ + M = OA_from_Vmt(8,11,[0,1,6,56,22,35,47,23,60]) + return M + +def OA_12_144(): + r""" + Returns an OA(12,144) + + Given by Julian R. Abel, using a `V(m,t)` from the Handbook + [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_Vmt` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(12,144) # indirect doctest + """ + M = OA_from_Vmt(10,13,[0, 1, 5, 10, 22, 6, 14, 9, 53, 129, 84]) + return M + +def OA_12_210(): + r""" + Returns an OA(12,210) + + Given by Julian R. Abel, using a `V(m,t)` from the Handbook + [DesignHandbook]_. + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_Vmt` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(12,210) # indirect doctest + """ + M = OA_from_Vmt(10,19,[0, 1, 3, 96, 143, 156, 182, 142, 4, 189, 25]) + return M + +# Index of the OA constructions +# +# Associates to n the pair (k,f) where f() is a function that returns an OA(k,n) +# +# This dictionary is used by designs.orthogonal_array(k,n). + +OA_constructions = { + 20 : (6 , OA_6_20), + 21 : (7 , OA_7_21), + 22 : (5 , OA_5_22), + 24 : (9 , OA_9_24), + 26 : (6 , OA_6_26), + 28 : (7 , OA_7_28), + 30 : (6 , OA_6_30), + 33 : (7 , OA_7_33), + 34 : (6 , OA_6_34), + 35 : (7 , OA_7_35), + 36 : (10 , OA_10_36), + 38 : (6 , OA_6_38), + 39 : (7 , OA_7_39), + 40 : (9 , OA_9_40), + 42 : (7 , OA_7_42), + 44 : (7 , OA_7_44), + 45 : (8 , OA_8_45), + 46 : (6 , OA_6_46), + 48 : (10 , OA_10_48), + 50 : (8 , OA_8_50), + 51 : (7 , OA_7_51), + 52 : (7 , OA_7_52), + 54 : (7 , OA_7_54), + 55 : (8 , OA_8_55), + 56 : (9 , OA_9_56), + 60 : (7 , OA_7_60), + 62 : (7 , OA_7_62), + 75 : (9 , OA_9_75), + 80 : (11 , OA_11_80), + 82 : (10 , OA_10_82), + 100 : (10 , OA_10_100), + 144 : (12 , OA_12_144), + 210 : (12 , OA_12_210) +} diff --git a/src/sage/combinat/designs/orthogonal_arrays.py b/src/sage/combinat/designs/orthogonal_arrays.py index f5feaa397e3..0232436e082 100644 --- a/src/sage/combinat/designs/orthogonal_arrays.py +++ b/src/sage/combinat/designs/orthogonal_arrays.py @@ -105,8 +105,8 @@ def transversal_design(k,n,check=True,availability=False, who_asked=tuple()): sage: designs.transversal_design(5, 18,availability=True) Unknown - sage: TD_5_20 = designs.transversal_design(5, 20) - sage: designs.transversal_design(6, 20,availability=True) + sage: TD_5_20 = designs.transversal_design(6, 20) + sage: designs.transversal_design(7, 20,availability=True) Unknown TESTS: @@ -558,6 +558,7 @@ def orthogonal_array(k,n,t=2,check=True,availability=False,who_asked=tuple()): from sage.rings.arith import is_prime_power from sage.rings.finite_rings.constructor import FiniteField from latin_squares import mutually_orthogonal_latin_squares + from database import OA_constructions if k < 2: raise ValueError("undefined for k less than 2") @@ -583,6 +584,13 @@ def orthogonal_array(k,n,t=2,check=True,availability=False,who_asked=tuple()): from itertools import product OA = map(list, product(range(n), repeat=k)) + elif n in OA_constructions and k <= OA_constructions[n][0]: + if availability: + return True + _, construction = OA_constructions[n] + + OA = OA_from_wider_OA(construction(),k) + # Theorem 6.39 from [Stinson2004] elif t == 2 and 2 <= k and k <= n and is_prime_power(n): if availability: @@ -639,6 +647,202 @@ def orthogonal_array(k,n,t=2,check=True,availability=False,who_asked=tuple()): return OA +def OA_from_quasi_difference_matrix(M,G,add_col=True): + r""" + Returns an Orthogonal Array from a Quasi-Difference matrix + + **Difference Matrices** + + Let `G` be a group of order `g`. A *difference matrix* `M` is a `k \times g` + matrix with entries from `G` such that for any `1\leq i < j < k` the set + `\{d_{il}-d_{jl}:1\leq l \leq g\}` is equal to `G`. + + By concatenating the `g` matrices `M+x` (where `x\in G`), one obtains a + matrix of size `x\times g^2` which is also an `OA(k,g)`. + + **Quasi-difference Matrices** + + A quasi-difference matrix is a difference matrix with missing entries. The + construction above can be applied again in this case, where the missing + entries in each column of `M` are replaced by unique values on which `G` has + a trivial action. + + This produces an incomplete orthogonal array with a "hole" (i.e. missing + rows) of size 'u' (i.e. the number of missing values per row of `M`). If + there exists an `OA(k,u)`, then adding the rows of this `OA(k,u)` to the + incomplete orthogonal array should lead to an OA... + + **Formal definition** (from the Handbook of Combinatorial Designs [DesignHandbook]_) + + Let `G` be an abelian group of order `n`. A + `(n,k;\lambda,\mu;u)`-quasi-difference matrix (QDM) is a matrix `Q=(q_{ij})` + with `k` rows and `\lambda(n-1+2u)+\mu` columns, with each entry either + empty or containing an element of `G`. Each row contains exactly `\lambda u` + entries, and each column contains at most one empty entry. Furthermore, for + each `1 \leq i < j \leq k` the multiset + + .. MATH:: + + \{ q_{il} - q_{jl}: 1 \leq l \leq \lambda (n-1+2u)+\mu, \text{ with }q_{il}\text{ and }q_{jl}\text{ not empty}\} + + contains every nonzero element of `G` exactly `\lambda` times, and contains + 0 exactly `\mu` times. + + **Construction** + + If a `(n,k;\lambda,\mu;u)`-QDM exists and `\mu \leq \lambda`, then an + `ITD_\lambda (k,n+u;u)` exists. Start with a `(n,k;\lambda,\mu;u)`-QDM `A` + over the group `G`. Append `\lambda-\mu` columns of zeroes. Then select `u` + elements `\infty_1,\dots,\infty_u` not in `G`, and replace the empty + entries, each by one of these infinite symbols, so that `\infty_i` appears + exactly once in each row. Develop the resulting matrix over the group `G` + (leaving infinite symbols fixed), to obtain a `k\times \lambda (n^2+2nu)` + matrix `T`. Then `T` is an orthogonal array with `k` rows and index + `\lambda`, having `n+u` symbols and one hole of size `u`. + + Adding to `T` an `OA(k,u)` with elements `\infty_1,\dots,\infty_u` yields + the `ITD_\lambda(k,n+u;u)`. + + For more information, see the Handbook of Combinatorial Designs + [DesignHandbook]_ or + ``_. + + INPUT: + + - ``M`` -- the difference matrix whose entries belong to ``G`` + + - ``G`` -- a group + + - ``add_col`` (boolean) -- whether to add a column to the final OA equal to + `(x_1,\dots,x_g,x_1,\dots,x_g,\dots)` where `G=\{x_1,\dots,x_g\}`. + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(6,20,2) # indirect doctest + """ + Gn = G.cardinality() + k = len(M)+bool(add_col) + G_to_int = {v:i for i,v in enumerate(G)} + + new_M = [] + for line in M: + new_line = [] + # Concatenating the line+x, for all x \in G + for g in G: + inf = Gn + for x in line: + if x is None: + new_line.append(inf) + inf = inf + 1 + else: + new_line.append(G_to_int[g+G(x)]) + new_M.append(new_line) + + if add_col: + new_M.append([i%(Gn) for i in range(len(new_line))]) + + # new_M = transpose(new_M) + new_M = zip(*new_M) + + # Filling holes with a smaller orthogonal array + if inf > Gn: + for L in orthogonal_array(k,inf-Gn,2): + new_M.append(tuple([x+Gn for x in L])) + + return new_M + +def OA_from_Vmt(m,t,V): + r""" + Returns an Orthogonal Array from a V(m,t) + + *Definition* + + Let `q` be a prime power and let `q=mt+1` for `m,t` integers. Let `\omega` + be a primitive element of `\mathbb{F}_q`. A `V(m,t)` vector is a vector + `(a_1,\dots,a_{m+1}` for which, for each `1\leq k < m`, the differences + + .. MATH:: + + \{a_{i+k}-a_i:1\leq i \leq m+1,i+k\neq m+2\} + + represent the `m` cyclotomic classes of `\mathbb_{mt+1}` (compute subscripts + modulo `m+2`). In other words, for fixed `k`, is + `a_{i+k}-a_i=\omega^{mx+\alpha}` and `a_{j+k}-a_j=\omega^{my+\beta}` then + `\alpha\not\equiv\beta \mod{m}` + + *Construction of a quasi-difference matrix from a `V(m,t)` vector* + + Starting with a `V(m,t)` vector `(a_1,\dots,a_{m+1})`, form a single column + of length `m+2` whose first entry is empty, and whose remaining entries are + `(a_1,\dots,a_{m+1})`. Form `t` columns by multiplying this column by the + `t` th roots, i.e. the powers of `\omega^m`. From each of these `t` columns, + form `m+2` columns by taking the `m+2` cyclic shifts of the column. The + result is a `(a,m+2;1,0;t)-QDM`. + + For more information, refer to the Handbook of Combinatorial Designs + [DesignHandbook]_. + + INPUT: + + - ``m,t`` (integers) + + - ``V`` -- the vector `V(m,t)`. + + .. SEEALSO:: + + :func:`OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: _ = designs.orthogonal_array(6,46) # indirect doctest + """ + from sage.rings.finite_rings.constructor import FiniteField + q = m*t+1 + Fq = FiniteField(q) + w = Fq.primitive_element() + + # Cyclic shift of a list + cyclic_shift = lambda l,i : l[-i:]+l[:-i] + + M = [] + wm = w**m + for i in range(t): + L = [None] + for e in V: + L.append(e*wm**i) + for ii in range(m+2): + M.append(cyclic_shift(L,ii)) + + M.append([0]*q) + M = zip(*M) + M = OA_from_quasi_difference_matrix(M,Fq,add_col = False) + + return M + +def OA_from_wider_OA(OA,k): + r""" + Returns the first `k` columns of `OA`. + + If `OA` has `k` columns, this function returns `OA` immediately. + + INPUT: + + - ``OA`` -- an orthogonal array. + + - ``k`` (integer) + + EXAMPLES:: + + sage: from sage.combinat.designs.orthogonal_arrays import OA_from_wider_OA + sage: OA_from_wider_OA(designs.orthogonal_array(6,20,2),1)[:5] + [(19,), (0,), (0,), (7,), (1,)] + sage: _ = designs.orthogonal_array(5,46) # indirect doctest + + """ + if len(OA[0]) == k: + return OA + return [L[:k] for L in OA] + def is_orthogonal_array(M,k,n,t): r""" Check that the integer matrix `M` is an `OA(k,n,t)`. From 0f3a755de6b9d10b12067f00691f359f93a484fa Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 2 May 2014 17:24:59 +0200 Subject: [PATCH 03/18] trac #16235: A pair of orthogonal latin squares of order 10 --- src/sage/combinat/designs/database.py | 115 +++++++++++++----- src/sage/combinat/designs/latin_squares.py | 46 +++++-- .../combinat/designs/orthogonal_arrays.py | 4 +- 3 files changed, 119 insertions(+), 46 deletions(-) diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index 479d53ce53c..d550e964f7a 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -12,39 +12,42 @@ ``designs.`` functions. Implemented constructions : -:func:`OA(6,20) `, -:func:`OA(7,21) `, -:func:`OA(5,22) `, -:func:`OA(9,24) `, -:func:`OA(6,26) `, -:func:`OA(7,28) `, -:func:`OA(6,30) `, -:func:`OA(7,33) `, -:func:`OA(6,34) `, -:func:`OA(7,35) `, -:func:`OA(10,36) `, -:func:`OA(6,38) `, -:func:`OA(7,39) `, -:func:`OA(9,40) `, -:func:`OA(7,42) `, -:func:`OA(7,44) `, -:func:`OA(8,45) `, -:func:`OA(6,46) `, -:func:`OA(10,48) `, -:func:`OA(8,50) `, -:func:`OA(7,51) `, -:func:`OA(7,52) `, -:func:`OA(7,54) `, -:func:`OA(8,55) `, -:func:`OA(9,56) `, -:func:`OA(7,60) `, -:func:`OA(7,62) `, -:func:`OA(9,75) `, -:func:`OA(11,80) `, -:func:`OA(10,82) `, -:func:`OA(10,100) `, -:func:`OA(12,144) `, -:func:`OA(12,210) ` + +- :func:`OA(6,20) `, + :func:`OA(7,21) `, + :func:`OA(5,22) `, + :func:`OA(9,24) `, + :func:`OA(6,26) `, + :func:`OA(7,28) `, + :func:`OA(6,30) `, + :func:`OA(7,33) `, + :func:`OA(6,34) `, + :func:`OA(7,35) `, + :func:`OA(10,36) `, + :func:`OA(6,38) `, + :func:`OA(7,39) `, + :func:`OA(9,40) `, + :func:`OA(7,42) `, + :func:`OA(7,44) `, + :func:`OA(8,45) `, + :func:`OA(6,46) `, + :func:`OA(10,48) `, + :func:`OA(8,50) `, + :func:`OA(7,51) `, + :func:`OA(7,52) `, + :func:`OA(7,54) `, + :func:`OA(8,55) `, + :func:`OA(9,56) `, + :func:`OA(7,60) `, + :func:`OA(7,62) `, + :func:`OA(9,75) `, + :func:`OA(11,80) `, + :func:`OA(10,82) `, + :func:`OA(10,100) `, + :func:`OA(12,144) `, + :func:`OA(12,210) ` + +- :func:`two MOLS of order 10 ` **Dictionaries** @@ -72,6 +75,52 @@ # Cyclic shift of a list cyclic_shift = lambda l,i : l[-i:]+l[:-i] +def MOLS_10_2(): + r""" + Returns a pair of MOLS of order 10 + + Data obtained from + ``_ + + EXAMPLES:: + + sage: designs.mutually_orthogonal_latin_squares(10,2) # indirect doctest + [ + [1 8 9 0 2 4 6 3 5 7] [1 7 6 5 0 9 8 2 3 4] + [7 2 8 9 0 3 5 4 6 1] [8 2 1 7 6 0 9 3 4 5] + [6 1 3 8 9 0 4 5 7 2] [9 8 3 2 1 7 0 4 5 6] + [5 7 2 4 8 9 0 6 1 3] [0 9 8 4 3 2 1 5 6 7] + [0 6 1 3 5 8 9 7 2 4] [2 0 9 8 5 4 3 6 7 1] + [9 0 7 2 4 6 8 1 3 5] [4 3 0 9 8 6 5 7 1 2] + [8 9 0 1 3 5 7 2 4 6] [6 5 4 0 9 8 7 1 2 3] + [2 3 4 5 6 7 1 8 9 0] [3 4 5 6 7 1 2 8 0 9] + [3 4 5 6 7 1 2 0 8 9] [5 6 7 1 2 3 4 0 9 8] + [4 5 6 7 1 2 3 9 0 8], [7 1 2 3 4 5 6 9 8 0] + ] + """ + from sage.matrix.constructor import Matrix + return [Matrix([[1,8,9,0,2,4,6,3,5,7], + [7,2,8,9,0,3,5,4,6,1], + [6,1,3,8,9,0,4,5,7,2], + [5,7,2,4,8,9,0,6,1,3], + [0,6,1,3,5,8,9,7,2,4], + [9,0,7,2,4,6,8,1,3,5], + [8,9,0,1,3,5,7,2,4,6], + [2,3,4,5,6,7,1,8,9,0], + [3,4,5,6,7,1,2,0,8,9], + [4,5,6,7,1,2,3,9,0,8]]), + + Matrix([[1,7,6,5,0,9,8,2,3,4], + [8,2,1,7,6,0,9,3,4,5], + [9,8,3,2,1,7,0,4,5,6], + [0,9,8,4,3,2,1,5,6,7], + [2,0,9,8,5,4,3,6,7,1], + [4,3,0,9,8,6,5,7,1,2], + [6,5,4,0,9,8,7,1,2,3], + [3,4,5,6,7,1,2,8,0,9], + [5,6,7,1,2,3,4,0,9,8], + [7,1,2,3,4,5,6,9,8,0]])] + def OA_6_20(): r""" Returns an OA(6,20) diff --git a/src/sage/combinat/designs/latin_squares.py b/src/sage/combinat/designs/latin_squares.py index d383ee8096d..a2b3a5b40be 100644 --- a/src/sage/combinat/designs/latin_squares.py +++ b/src/sage/combinat/designs/latin_squares.py @@ -186,6 +186,22 @@ def mutually_orthogonal_latin_squares(n,k, partitions = False, check = True, ava ValueError: There exist at most n-1 MOLS of size n. sage: designs.mutually_orthogonal_latin_squares(6,3,availability=True) False + sage: designs.mutually_orthogonal_latin_squares(10,2,availability=True) + True + sage: designs.mutually_orthogonal_latin_squares(10,2) + [ + [1 8 9 0 2 4 6 3 5 7] [1 7 6 5 0 9 8 2 3 4] + [7 2 8 9 0 3 5 4 6 1] [8 2 1 7 6 0 9 3 4 5] + [6 1 3 8 9 0 4 5 7 2] [9 8 3 2 1 7 0 4 5 6] + [5 7 2 4 8 9 0 6 1 3] [0 9 8 4 3 2 1 5 6 7] + [0 6 1 3 5 8 9 7 2 4] [2 0 9 8 5 4 3 6 7 1] + [9 0 7 2 4 6 8 1 3 5] [4 3 0 9 8 6 5 7 1 2] + [8 9 0 1 3 5 7 2 4 6] [6 5 4 0 9 8 7 1 2 3] + [2 3 4 5 6 7 1 8 9 0] [3 4 5 6 7 1 2 8 0 9] + [3 4 5 6 7 1 2 0 8 9] [5 6 7 1 2 3 4 0 9 8] + [4 5 6 7 1 2 3 9 0 8], [7 1 2 3 4 5 6 9 8 0] + ] + """ from sage.rings.finite_rings.constructor import FiniteField from sage.combinat.designs.block_design import AffineGeometryDesign @@ -200,7 +216,14 @@ def mutually_orthogonal_latin_squares(n,k, partitions = False, check = True, ava else: raise ValueError("There exist at most n-1 MOLS of size n.") - if is_prime_power(n): + elif n == 10 and k == 2: + if availability: + return True + + from database import MOLS_10_2 + matrices = MOLS_10_2() + + elif is_prime_power(n): if availability: return True @@ -243,16 +266,6 @@ def mutually_orthogonal_latin_squares(n,k, partitions = False, check = True, ava matrices = [[M[i*n:(i+1)*n] for i in range(n)] for M in matrices] matrices = [Matrix(M) for M in matrices] - if partitions: - partitions = [[[i*n+j for j in range(n)] for i in range(n)], - [[j*n+i for j in range(n)] for i in range(n)]] - for m in matrices: - partition = [[] for i in range(n)] - for i in range(n): - for j in range(n): - partition[m[i,j]].append(i*n+j) - partitions.append(partition) - else: if availability: return False @@ -262,6 +275,17 @@ def mutually_orthogonal_latin_squares(n,k, partitions = False, check = True, ava if check: assert are_mutually_orthogonal_latin_squares(matrices) + # partitions have been requested but have not been computed yet + if partitions is True: + partitions = [[[i*n+j for j in range(n)] for i in range(n)], + [[j*n+i for j in range(n)] for i in range(n)]] + for m in matrices: + partition = [[] for i in range(n)] + for i in range(n): + for j in range(n): + partition[m[i,j]].append(i*n+j) + partitions.append(partition) + if partitions: return partitions else: diff --git a/src/sage/combinat/designs/orthogonal_arrays.py b/src/sage/combinat/designs/orthogonal_arrays.py index 0232436e082..7c0127d4234 100644 --- a/src/sage/combinat/designs/orthogonal_arrays.py +++ b/src/sage/combinat/designs/orthogonal_arrays.py @@ -85,8 +85,8 @@ def transversal_design(k,n,check=True,availability=False, who_asked=tuple()): Some examples of the maximal number of transversal Sage is able to build:: - sage: TD_3_10 = designs.transversal_design(3,10) - sage: designs.transversal_design(4,10,availability=True) + sage: TD_4_10 = designs.transversal_design(4,10) + sage: designs.transversal_design(5,10,availability=True) Unknown sage: TD_6_12 = designs.transversal_design(6,12) From 490aa7e9c919ef8bd62d9da41489c3825ff14f72 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sat, 3 May 2014 09:02:57 +0200 Subject: [PATCH 04/18] trac #16277: Reviewer's remarks --- src/sage/combinat/designs/database.py | 411 ++++++++++++++++-- .../combinat/designs/orthogonal_arrays.py | 48 +- 2 files changed, 386 insertions(+), 73 deletions(-) diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index 479d53ce53c..2dbab52411b 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -72,6 +72,53 @@ # Cyclic shift of a list cyclic_shift = lambda l,i : l[-i:]+l[:-i] +def TD_6_12(): + r""" + Returns a `TD(6,12)` as build in [Hanani75]_. + + This design is Lemma 3.21 from [Hanani75]_. + + EXAMPLE:: + + sage: from sage.combinat.designs.database import TD_6_12 + sage: from sage.combinat.designs.orthogonal_arrays import is_transversal_design + sage: TD = TD_6_12() + sage: is_transversal_design(TD,6,12) + True + + The design is available from the general constructor:: + + sage: designs.transversal_design(6,12,availability=True) + True + + REFERENCES: + + .. [Hanani75] Haim Hanani, + Balanced incomplete block designs and related designs, + http://dx.doi.org/10.1016/0012-365X(75)90040-0, + Discrete Mathematics, Volume 11, Issue 3, 1975, Pages 255-369. + """ + from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup + G = AdditiveAbelianGroup([2,6]) + d = [[(0,0),(0,0),(0,0),(0,0),(0,0),(0,0)], + [(0,0),(0,1),(1,0),(0,3),(1,2),(0,4)], + [(0,0),(0,2),(1,2),(1,0),(0,1),(1,5)], + [(0,0),(0,3),(0,2),(0,1),(1,5),(1,4)], + [(0,0),(0,4),(1,1),(1,3),(0,5),(0,2)], + [(0,0),(0,5),(0,1),(1,5),(1,3),(1,1)], + [(0,0),(1,0),(1,3),(0,2),(0,3),(1,2)], + [(0,0),(1,1),(1,5),(1,2),(1,4),(1,0)], + [(0,0),(1,2),(0,4),(0,5),(0,2),(1,3)], + [(0,0),(1,3),(1,4),(0,4),(1,1),(0,1)], + [(0,0),(1,4),(0,5),(1,1),(1,0),(0,3)], + [(0,0),(1,5),(0,3),(1,4),(0,4),(0,5)]] + + r = lambda x : int(x[0])*6+int(x[1]) + TD = [[i*12+r(G(x)+g) for i,x in enumerate(X)] for X in d for g in G] + for x in TD: x.sort() + + return TD + def OA_6_20(): r""" Returns an OA(6,20) @@ -84,7 +131,16 @@ def OA_6_20(): EXAMPLES:: - sage: _ = designs.orthogonal_array(6,20) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_6_20 + sage: OA = OA_6_20() + sage: print is_orthogonal_array(OA,6,20,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(6,20,availability=True) + True """ M=[[None, 7, 13, 1, 16, 9, 2], [ 0, 1, 15, 7, 17, 6, 14], @@ -121,7 +177,16 @@ def OA_7_21(): EXAMPLES:: - sage: _ = designs.orthogonal_array(7,21) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_7_21 + sage: OA = OA_7_21() + sage: print is_orthogonal_array(OA,7,21,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(7,21,availability=True) + True """ M = [[ 8, 17, 20, 2], [ 9, 16, 4, 15], @@ -154,7 +219,16 @@ def OA_5_22(): EXAMPLES:: - sage: _ = designs.orthogonal_array(5,22) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_5_22 + sage: OA = OA_5_22() + sage: print is_orthogonal_array(OA,5,22,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(5,22,availability=True) + True """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic G = AdditiveCyclic(21) @@ -197,7 +271,16 @@ def OA_9_24(): EXAMPLES:: - sage: _ = designs.orthogonal_array(9,24) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_9_24 + sage: OA = OA_9_24() + sage: print is_orthogonal_array(OA,9,24,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(9,24,availability=True) + True """ M = ("0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 "+ "0000 0010 0100 0110 1000 1010 1100 1110 2000 2010 2100 2110 "+ @@ -239,7 +322,16 @@ def OA_6_26(): EXAMPLES:: - sage: _ = designs.orthogonal_array(6,26) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_6_26 + sage: OA = OA_6_26() + sage: print is_orthogonal_array(OA,6,26,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(6,26,availability=True) + True """ M = [ [None,None,None,None,None], @@ -278,7 +370,16 @@ def OA_7_28(): EXAMPLES:: - sage: _ = designs.orthogonal_array(7,28) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_7_28 + sage: OA = OA_7_28() + sage: print is_orthogonal_array(OA,7,28,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(7,28,availability=True) + True """ z=2 M = [ @@ -321,7 +422,16 @@ def OA_6_30(): EXAMPLES:: - sage: _ = designs.orthogonal_array(6,30) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_6_30 + sage: OA = OA_6_30() + sage: print is_orthogonal_array(OA,6,30,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(6,30,availability=True) + True """ M = [ [(0,0),None,(0,0),(0,0),(0,0),(0,0),(0,0)], @@ -364,7 +474,16 @@ def OA_7_33(): EXAMPLES:: - sage: _ = designs.orthogonal_array(7,33) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_7_33 + sage: OA = OA_7_33() + sage: print is_orthogonal_array(OA,7,33,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(7,33,availability=True) + True """ M = [ [ 0, 0, 0, 0, 0, 0], @@ -406,7 +525,16 @@ def OA_6_34(): EXAMPLES:: - sage: _ = designs.orthogonal_array(6,34) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_6_34 + sage: OA = OA_6_34() + sage: print is_orthogonal_array(OA,6,34,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(6,34,availability=True) + True """ M = [ [None, 0, 0, 0, 0, 0], @@ -449,7 +577,16 @@ def OA_7_35(): EXAMPLES:: - sage: _ = designs.orthogonal_array(7,35) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_7_35 + sage: OA = OA_7_35() + sage: print is_orthogonal_array(OA,7,35,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(7,35,availability=True) + True """ M = [ [ 0, 15, 30, 10, 25, 1, 16, 31, 11, 26, 2, 17, 32, 12, 6, 3, 18, 33, 27, 21, 4, 19, 13, 7, 22, 5, 34, 28, 8, 23, 20, 14, 29, 9, 24], @@ -478,7 +615,16 @@ def OA_10_36(): EXAMPLES:: - sage: _ = designs.orthogonal_array(10,36) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_10_36 + sage: OA = OA_10_36() + sage: print is_orthogonal_array(OA,10,36,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(10,36,availability=True) + True """ M = [ [(0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0)], @@ -527,7 +673,16 @@ def OA_6_38(): EXAMPLES:: - sage: _ = designs.orthogonal_array(6,38) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_6_38 + sage: OA = OA_6_38() + sage: print is_orthogonal_array(OA,6,38,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(6,38,availability=True) + True """ M = [ [None, 10, 1, 2, 6, 3, 22, 5, 7, 9, 14, 18, 28], @@ -567,7 +722,16 @@ def OA_7_39(): EXAMPLES:: - sage: _ = designs.orthogonal_array(7,39) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_7_39 + sage: OA = OA_7_39() + sage: print is_orthogonal_array(OA,7,39,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(7,39,availability=True) + True """ M = [ [ 0, 0, 0, 0, 0, 0], @@ -609,7 +773,16 @@ def OA_9_40(): EXAMPLES:: - sage: _ = designs.orthogonal_array(9,40) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_9_40 + sage: OA = OA_9_40() + sage: print is_orthogonal_array(OA,9,40,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(9,40,availability=True) + True """ from sage.rings.finite_rings.constructor import FiniteField @@ -674,7 +847,16 @@ def OA_7_42(): EXAMPLES:: - sage: _ = designs.orthogonal_array(7,42) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_7_42 + sage: OA = OA_7_42() + sage: print is_orthogonal_array(OA,7,42,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(7,42,availability=True) + True """ M = [ [None,None,None,None,None,None,None], @@ -710,7 +892,16 @@ def OA_7_44(): EXAMPLES:: - sage: _ = designs.orthogonal_array(7,44) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_7_44 + sage: OA = OA_7_44() + sage: print is_orthogonal_array(OA,7,44,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(7,44,availability=True) + True """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic from sage.categories.cartesian_product import cartesian_product @@ -770,7 +961,16 @@ def OA_8_45(): EXAMPLES:: - sage: _ = designs.orthogonal_array(8,45) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_8_45 + sage: OA = OA_8_45() + sage: print is_orthogonal_array(OA,8,45,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(8,45,availability=True) + True """ from sage.rings.finite_rings.constructor import FiniteField from sage.categories.cartesian_product import cartesian_product @@ -820,7 +1020,16 @@ def OA_6_46(): EXAMPLES:: - sage: _ = designs.orthogonal_array(6,46) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_6_46 + sage: OA = OA_6_46() + sage: print is_orthogonal_array(OA,6,46,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(6,46,availability=True) + True """ M = OA_from_Vmt(4,9,[0, 1, 3, 2, 8]) return M @@ -837,7 +1046,16 @@ def OA_10_48(): EXAMPLES:: - sage: _ = designs.orthogonal_array(10,48) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_10_48 + sage: OA = OA_10_48() + sage: print is_orthogonal_array(OA,10,48,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(10,48,availability=True) + True """ from sage.rings.finite_rings.constructor import FiniteField F16 = FiniteField(16,'x') @@ -885,7 +1103,16 @@ def OA_8_50(): EXAMPLES:: - sage: _ = designs.orthogonal_array(8,50) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_8_50 + sage: OA = OA_8_50() + sage: print is_orthogonal_array(OA,8,50,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(8,50,availability=True) + True """ M = OA_from_Vmt(6,7,[0, 1, 3, 16, 35, 26, 36]) return M @@ -902,7 +1129,16 @@ def OA_7_51(): EXAMPLES:: - sage: _ = designs.orthogonal_array(7,51) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_7_51 + sage: OA = OA_7_51() + sage: print is_orthogonal_array(OA,7,51,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(7,51,availability=True) + True """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic G = AdditiveCyclic(51) @@ -939,7 +1175,16 @@ def OA_7_52(): EXAMPLES:: - sage: _ = designs.orthogonal_array(7,52) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_7_52 + sage: OA = OA_7_52() + sage: print is_orthogonal_array(OA,7,52,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(7,52,availability=True) + True """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic from sage.rings.finite_rings.constructor import FiniteField @@ -1011,7 +1256,16 @@ def OA_7_54(): EXAMPLES:: - sage: _ = designs.orthogonal_array(7,54) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_7_54 + sage: OA = OA_7_54() + sage: print is_orthogonal_array(OA,7,54,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(7,54,availability=True) + True """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic G = AdditiveCyclic(45) @@ -1048,7 +1302,16 @@ def OA_8_55(): EXAMPLES:: - sage: _ = designs.orthogonal_array(8,55) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_8_55 + sage: OA = OA_8_55() + sage: print is_orthogonal_array(OA,8,55,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(8,55,availability=True) + True """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic G = AdditiveCyclic(55) @@ -1085,7 +1348,16 @@ def OA_9_56(): EXAMPLES:: - sage: _ = designs.orthogonal_array(9,56) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_9_56 + sage: OA = OA_9_56() + sage: print is_orthogonal_array(OA,9,56,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(9,56,availability=True) + True """ from sage.rings.finite_rings.constructor import FiniteField F8 = FiniteField(8,'z') @@ -1139,7 +1411,16 @@ def OA_7_60(): EXAMPLES:: - sage: _ = designs.orthogonal_array(7,60) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_7_60 + sage: OA = OA_7_60() + sage: print is_orthogonal_array(OA,7,60,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(7,60,availability=True) + True """ M60 = [[(0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)], [(1, 10), (1, 6), (0, 17), (0, 7), (1, 5), (0, 9), (0, 3), (1, 13), (1, 17), (0, 13)], @@ -1177,7 +1458,16 @@ def OA_7_62(): EXAMPLES:: - sage: _ = designs.orthogonal_array(7,62) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_7_62 + sage: OA = OA_7_62() + sage: print is_orthogonal_array(OA,7,62,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(7,62,availability=True) + True """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic G = AdditiveCyclic(54) @@ -1214,7 +1504,16 @@ def OA_9_75(): EXAMPLES:: - sage: _ = designs.orthogonal_array(9,75) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_9_75 + sage: OA = OA_9_75() + sage: print is_orthogonal_array(OA,9,75,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(9,75,availability=True) + True """ from sage.rings.finite_rings.constructor import FiniteField from sage.categories.cartesian_product import cartesian_product @@ -1260,7 +1559,16 @@ def OA_11_80(): EXAMPLES:: - sage: _ = designs.orthogonal_array(11,80) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_11_80 + sage: OA = OA_11_80() + sage: print is_orthogonal_array(OA,11,80,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(11,80,availability=True) + True """ from sage.rings.finite_rings.constructor import FiniteField F16 = FiniteField(2**4,'w') @@ -1321,7 +1629,16 @@ def OA_10_82(): EXAMPLES:: - sage: _ = designs.orthogonal_array(10,82) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_10_82 + sage: OA = OA_10_82() + sage: print is_orthogonal_array(OA,10,82,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(10,82,availability=True) + True """ M = OA_from_Vmt(8,9,[0,1,20,70,23,59,3,8,19]) return M @@ -1339,7 +1656,16 @@ def OA_10_100(): EXAMPLES:: - sage: _ = designs.orthogonal_array(10,100) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_10_100 + sage: OA = OA_10_100() + sage: print is_orthogonal_array(OA,10,100,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(10,100,availability=True) + True """ M = OA_from_Vmt(8,11,[0,1,6,56,22,35,47,23,60]) return M @@ -1357,7 +1683,16 @@ def OA_12_144(): EXAMPLES:: - sage: _ = designs.orthogonal_array(12,144) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_12_144 + sage: OA = OA_12_144() + sage: print is_orthogonal_array(OA,12,144,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(12,144,availability=True) + True """ M = OA_from_Vmt(10,13,[0, 1, 5, 10, 22, 6, 14, 9, 53, 129, 84]) return M @@ -1375,7 +1710,16 @@ def OA_12_210(): EXAMPLES:: - sage: _ = designs.orthogonal_array(12,210) # indirect doctest + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_12_210 + sage: OA = OA_12_210() + sage: print is_orthogonal_array(OA,12,210,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(12,210,availability=True) + True """ M = OA_from_Vmt(10,19,[0, 1, 3, 96, 143, 156, 182, 142, 4, 189, 25]) return M @@ -1421,3 +1765,4 @@ def OA_12_210(): 144 : (12 , OA_12_144), 210 : (12 , OA_12_210) } + diff --git a/src/sage/combinat/designs/orthogonal_arrays.py b/src/sage/combinat/designs/orthogonal_arrays.py index 0232436e082..2ee34e51d23 100644 --- a/src/sage/combinat/designs/orthogonal_arrays.py +++ b/src/sage/combinat/designs/orthogonal_arrays.py @@ -124,9 +124,16 @@ def transversal_design(k,n,check=True,availability=False, who_asked=tuple()): sage: designs.transversal_design(6,4,availability=True) Unknown + + `TD(6,12)` :: + + sage: _ = designs.transversal_design(6,12) """ if n == 12 and k <= 6: - TD = [l[:k] for l in TD6_12()] + if availability: + return True + from sage.combinat.designs.database import TD_6_12 + TD = [l[:k] for l in TD_6_12()] elif TD_find_product_decomposition(k,n): if availability: @@ -260,45 +267,6 @@ def find_wilson_decomposition(k,n): return False -def TD6_12(): - r""" - Returns a `TD(6,12)` as build in [Hanani75]_. - - This design is Lemma 3.21 from [Hanani75]_. - - EXAMPLE:: - - sage: from sage.combinat.designs.orthogonal_arrays import TD6_12 - sage: _ = TD6_12() - - REFERENCES: - - .. [Hanani75] Haim Hanani, - Balanced incomplete block designs and related designs, - http://dx.doi.org/10.1016/0012-365X(75)90040-0, - Discrete Mathematics, Volume 11, Issue 3, 1975, Pages 255-369. - """ - from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup - G = AdditiveAbelianGroup([2,6]) - d = [[(0,0),(0,0),(0,0),(0,0),(0,0),(0,0)], - [(0,0),(0,1),(1,0),(0,3),(1,2),(0,4)], - [(0,0),(0,2),(1,2),(1,0),(0,1),(1,5)], - [(0,0),(0,3),(0,2),(0,1),(1,5),(1,4)], - [(0,0),(0,4),(1,1),(1,3),(0,5),(0,2)], - [(0,0),(0,5),(0,1),(1,5),(1,3),(1,1)], - [(0,0),(1,0),(1,3),(0,2),(0,3),(1,2)], - [(0,0),(1,1),(1,5),(1,2),(1,4),(1,0)], - [(0,0),(1,2),(0,4),(0,5),(0,2),(1,3)], - [(0,0),(1,3),(1,4),(0,4),(1,1),(0,1)], - [(0,0),(1,4),(0,5),(1,1),(1,0),(0,3)], - [(0,0),(1,5),(0,3),(1,4),(0,4),(0,5)]] - - r = lambda x : int(x[0])*6+int(x[1]) - TD = [[i*12+r(G(x)+g) for i,x in enumerate(X)] for X in d for g in G] - for x in TD: x.sort() - - return TD - def wilson_construction(k,m,t,u, check = True): r""" Returns a `TD(k,mt+u)` by Wilson's construction. From 14420b6fa8b77896fa8f3911672979f25b3b333f Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sat, 3 May 2014 17:59:49 +0200 Subject: [PATCH 05/18] trac #16277: Yet another construction --- src/sage/combinat/designs/database.py | 38 +++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index 2dbab52411b..474253eb33b 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -39,6 +39,7 @@ :func:`OA(9,56) `, :func:`OA(7,60) `, :func:`OA(7,62) `, +:func:`OA(9,65) `, :func:`OA(9,75) `, :func:`OA(11,80) `, :func:`OA(10,82) `, @@ -1492,6 +1493,42 @@ def OA_7_62(): M = OA_from_quasi_difference_matrix(Mb,G,add_col = False) return M +def OA_9_65(): + r""" + Returns an OA(9,65) + + Construction shared by Julian R. Abel + + .. SEEALSO:: + + :func:`sage.combinat.designs.orthogonal_arrays.OA_from_quasi_difference_matrix` + + EXAMPLES:: + + sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array + sage: from sage.combinat.designs.database import OA_9_65 + sage: OA = OA_9_65() + sage: print is_orthogonal_array(OA,9,65,2) + True + + The design is available from the general constructor:: + + sage: designs.orthogonal_array(9,65,availability=True) + True + """ + from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as G + from orthogonal_arrays import orthogonal_array + + B = [None,1, 6, 7, 9, 19, 38, 42, 49] # Base block of a (57,8,1)-BIBD + OA = orthogonal_array(9,9,2) + M = [R for R in OA if any(R[0] != x for x in R)] + + M = [[B[x] for x in R] for R in M] # replacing [0,..,8] by the elements of B + M.append([0]*9) + + M = OA_from_quasi_difference_matrix(zip(*M), G(57),add_col=False) + return M + def OA_9_75(): r""" Returns an OA(9,75) @@ -1758,6 +1795,7 @@ def OA_12_210(): 56 : (9 , OA_9_56), 60 : (7 , OA_7_60), 62 : (7 , OA_7_62), + 65 : (9 , OA_9_65), 75 : (9 , OA_9_75), 80 : (11 , OA_11_80), 82 : (10 , OA_10_82), From 7570b39787b8e11f64317ed11f4d5c282752ac74 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 4 May 2014 09:27:55 +0200 Subject: [PATCH 06/18] trac #16277: From availability to existence and broken doctests --- src/sage/combinat/designs/database.py | 70 +++++++++---------- .../combinat/designs/orthogonal_arrays.py | 26 +++---- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index 474253eb33b..b67de39aa6e 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -89,7 +89,7 @@ def TD_6_12(): The design is available from the general constructor:: - sage: designs.transversal_design(6,12,availability=True) + sage: designs.transversal_design(6,12,existence=True) True REFERENCES: @@ -140,7 +140,7 @@ def OA_6_20(): The design is available from the general constructor:: - sage: designs.orthogonal_array(6,20,availability=True) + sage: designs.orthogonal_array(6,20,existence=True) True """ M=[[None, 7, 13, 1, 16, 9, 2], @@ -186,7 +186,7 @@ def OA_7_21(): The design is available from the general constructor:: - sage: designs.orthogonal_array(7,21,availability=True) + sage: designs.orthogonal_array(7,21,existence=True) True """ M = [[ 8, 17, 20, 2], @@ -228,7 +228,7 @@ def OA_5_22(): The design is available from the general constructor:: - sage: designs.orthogonal_array(5,22,availability=True) + sage: designs.orthogonal_array(5,22,existence=True) True """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic @@ -280,7 +280,7 @@ def OA_9_24(): The design is available from the general constructor:: - sage: designs.orthogonal_array(9,24,availability=True) + sage: designs.orthogonal_array(9,24,existence=True) True """ M = ("0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 "+ @@ -331,7 +331,7 @@ def OA_6_26(): The design is available from the general constructor:: - sage: designs.orthogonal_array(6,26,availability=True) + sage: designs.orthogonal_array(6,26,existence=True) True """ M = [ @@ -379,7 +379,7 @@ def OA_7_28(): The design is available from the general constructor:: - sage: designs.orthogonal_array(7,28,availability=True) + sage: designs.orthogonal_array(7,28,existence=True) True """ z=2 @@ -431,7 +431,7 @@ def OA_6_30(): The design is available from the general constructor:: - sage: designs.orthogonal_array(6,30,availability=True) + sage: designs.orthogonal_array(6,30,existence=True) True """ M = [ @@ -483,7 +483,7 @@ def OA_7_33(): The design is available from the general constructor:: - sage: designs.orthogonal_array(7,33,availability=True) + sage: designs.orthogonal_array(7,33,existence=True) True """ M = [ @@ -534,7 +534,7 @@ def OA_6_34(): The design is available from the general constructor:: - sage: designs.orthogonal_array(6,34,availability=True) + sage: designs.orthogonal_array(6,34,existence=True) True """ M = [ @@ -586,7 +586,7 @@ def OA_7_35(): The design is available from the general constructor:: - sage: designs.orthogonal_array(7,35,availability=True) + sage: designs.orthogonal_array(7,35,existence=True) True """ M = [ @@ -624,7 +624,7 @@ def OA_10_36(): The design is available from the general constructor:: - sage: designs.orthogonal_array(10,36,availability=True) + sage: designs.orthogonal_array(10,36,existence=True) True """ M = [ @@ -682,7 +682,7 @@ def OA_6_38(): The design is available from the general constructor:: - sage: designs.orthogonal_array(6,38,availability=True) + sage: designs.orthogonal_array(6,38,existence=True) True """ M = [ @@ -731,7 +731,7 @@ def OA_7_39(): The design is available from the general constructor:: - sage: designs.orthogonal_array(7,39,availability=True) + sage: designs.orthogonal_array(7,39,existence=True) True """ M = [ @@ -782,7 +782,7 @@ def OA_9_40(): The design is available from the general constructor:: - sage: designs.orthogonal_array(9,40,availability=True) + sage: designs.orthogonal_array(9,40,existence=True) True """ from sage.rings.finite_rings.constructor import FiniteField @@ -856,7 +856,7 @@ def OA_7_42(): The design is available from the general constructor:: - sage: designs.orthogonal_array(7,42,availability=True) + sage: designs.orthogonal_array(7,42,existence=True) True """ M = [ @@ -901,7 +901,7 @@ def OA_7_44(): The design is available from the general constructor:: - sage: designs.orthogonal_array(7,44,availability=True) + sage: designs.orthogonal_array(7,44,existence=True) True """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic @@ -970,7 +970,7 @@ def OA_8_45(): The design is available from the general constructor:: - sage: designs.orthogonal_array(8,45,availability=True) + sage: designs.orthogonal_array(8,45,existence=True) True """ from sage.rings.finite_rings.constructor import FiniteField @@ -1029,7 +1029,7 @@ def OA_6_46(): The design is available from the general constructor:: - sage: designs.orthogonal_array(6,46,availability=True) + sage: designs.orthogonal_array(6,46,existence=True) True """ M = OA_from_Vmt(4,9,[0, 1, 3, 2, 8]) @@ -1055,7 +1055,7 @@ def OA_10_48(): The design is available from the general constructor:: - sage: designs.orthogonal_array(10,48,availability=True) + sage: designs.orthogonal_array(10,48,existence=True) True """ from sage.rings.finite_rings.constructor import FiniteField @@ -1112,7 +1112,7 @@ def OA_8_50(): The design is available from the general constructor:: - sage: designs.orthogonal_array(8,50,availability=True) + sage: designs.orthogonal_array(8,50,existence=True) True """ M = OA_from_Vmt(6,7,[0, 1, 3, 16, 35, 26, 36]) @@ -1138,7 +1138,7 @@ def OA_7_51(): The design is available from the general constructor:: - sage: designs.orthogonal_array(7,51,availability=True) + sage: designs.orthogonal_array(7,51,existence=True) True """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic @@ -1184,7 +1184,7 @@ def OA_7_52(): The design is available from the general constructor:: - sage: designs.orthogonal_array(7,52,availability=True) + sage: designs.orthogonal_array(7,52,existence=True) True """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic @@ -1265,7 +1265,7 @@ def OA_7_54(): The design is available from the general constructor:: - sage: designs.orthogonal_array(7,54,availability=True) + sage: designs.orthogonal_array(7,54,existence=True) True """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic @@ -1311,7 +1311,7 @@ def OA_8_55(): The design is available from the general constructor:: - sage: designs.orthogonal_array(8,55,availability=True) + sage: designs.orthogonal_array(8,55,existence=True) True """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic @@ -1357,7 +1357,7 @@ def OA_9_56(): The design is available from the general constructor:: - sage: designs.orthogonal_array(9,56,availability=True) + sage: designs.orthogonal_array(9,56,existence=True) True """ from sage.rings.finite_rings.constructor import FiniteField @@ -1420,7 +1420,7 @@ def OA_7_60(): The design is available from the general constructor:: - sage: designs.orthogonal_array(7,60,availability=True) + sage: designs.orthogonal_array(7,60,existence=True) True """ M60 = [[(0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)], @@ -1467,7 +1467,7 @@ def OA_7_62(): The design is available from the general constructor:: - sage: designs.orthogonal_array(7,62,availability=True) + sage: designs.orthogonal_array(7,62,existence=True) True """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic @@ -1513,7 +1513,7 @@ def OA_9_65(): The design is available from the general constructor:: - sage: designs.orthogonal_array(9,65,availability=True) + sage: designs.orthogonal_array(9,65,existence=True) True """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as G @@ -1549,7 +1549,7 @@ def OA_9_75(): The design is available from the general constructor:: - sage: designs.orthogonal_array(9,75,availability=True) + sage: designs.orthogonal_array(9,75,existence=True) True """ from sage.rings.finite_rings.constructor import FiniteField @@ -1604,7 +1604,7 @@ def OA_11_80(): The design is available from the general constructor:: - sage: designs.orthogonal_array(11,80,availability=True) + sage: designs.orthogonal_array(11,80,existence=True) True """ from sage.rings.finite_rings.constructor import FiniteField @@ -1674,7 +1674,7 @@ def OA_10_82(): The design is available from the general constructor:: - sage: designs.orthogonal_array(10,82,availability=True) + sage: designs.orthogonal_array(10,82,existence=True) True """ M = OA_from_Vmt(8,9,[0,1,20,70,23,59,3,8,19]) @@ -1701,7 +1701,7 @@ def OA_10_100(): The design is available from the general constructor:: - sage: designs.orthogonal_array(10,100,availability=True) + sage: designs.orthogonal_array(10,100,existence=True) True """ M = OA_from_Vmt(8,11,[0,1,6,56,22,35,47,23,60]) @@ -1728,7 +1728,7 @@ def OA_12_144(): The design is available from the general constructor:: - sage: designs.orthogonal_array(12,144,availability=True) + sage: designs.orthogonal_array(12,144,existence=True) True """ M = OA_from_Vmt(10,13,[0, 1, 5, 10, 22, 6, 14, 9, 53, 129, 84]) @@ -1755,7 +1755,7 @@ def OA_12_210(): The design is available from the general constructor:: - sage: designs.orthogonal_array(12,210,availability=True) + sage: designs.orthogonal_array(12,210,existence=True) True """ M = OA_from_Vmt(10,19,[0, 1, 3, 96, 143, 156, 182, 142, 4, 189, 25]) diff --git a/src/sage/combinat/designs/orthogonal_arrays.py b/src/sage/combinat/designs/orthogonal_arrays.py index 1453cc00fdf..d3e391bbfca 100644 --- a/src/sage/combinat/designs/orthogonal_arrays.py +++ b/src/sage/combinat/designs/orthogonal_arrays.py @@ -162,14 +162,14 @@ def transversal_design(k,n,check=True,existence=False, who_asked=tuple()): ....: pass ....: k += 1 ....: print "%2d: (%2d, %2d)"%(n,i,j) - 2: ( 4, 4) - 3: ( 5, 5) - 4: ( 6, 6) - 5: ( 7, 7) - 6: ( 4, 7) - 7: ( 9, 9) - 8: (10, 10) - 9: (11, 11) + 2: ( 4, 4) + 3: ( 5, 5) + 4: ( 6, 6) + 5: ( 7, 7) + 6: ( 4, 7) + 7: ( 9, 9) + 8: (10, 10) + 9: (11, 11) 10: ( 4, 11) 11: (13, 13) 12: ( 7, 14) @@ -180,11 +180,11 @@ def transversal_design(k,n,check=True,existence=False, who_asked=tuple()): 17: (19, 19) 18: ( 5, 20) 19: (21, 21) - 20: ( 6, 22) - 21: ( 5, 22) - 22: ( 4, 23) + 20: ( 7, 22) + 21: ( 8, 22) + 22: ( 6, 23) 23: (25, 25) - 24: ( 6, 26) + 24: (10, 26) `TD(6,12)` :: @@ -650,7 +650,7 @@ def orthogonal_array(k,n,t=2,check=True,existence=False,who_asked=tuple()): # Constructions from the database elif n in OA_constructions and k <= OA_constructions[n][0]: - if availability: + if existence: return True _, construction = OA_constructions[n] From 5cab81cab862fd60c4a17fdd039ff22bb34b5629 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 4 May 2014 11:29:25 +0200 Subject: [PATCH 07/18] trac #16286: Allow k=None in MOLS/TD/OA --- src/sage/combinat/designs/latin_squares.py | 55 ++++++++++++++++++- .../combinat/designs/orthogonal_arrays.py | 38 ++++++++++--- 2 files changed, 84 insertions(+), 9 deletions(-) diff --git a/src/sage/combinat/designs/latin_squares.py b/src/sage/combinat/designs/latin_squares.py index 8e7080bd43c..4d1bdd52296 100644 --- a/src/sage/combinat/designs/latin_squares.py +++ b/src/sage/combinat/designs/latin_squares.py @@ -13,9 +13,42 @@ For more information on MOLS, see the :wikipedia:`Wikipedia entry on MOLS `. +The following table prints the maximum number of MOLS that Sage can build for +every order `n<300`, similarly to the `table of MOLS +`_ +from the Handbook of Combinatorial Designs. + +:: + + sage: def MOLS_table(number_of_lines): + ....: print " "+join(['%3s'%str(i) for i in range(20)]) + ....: print " "+"_"*80 + ....: for i in range(20*15): + ....: if i%20==0: + ....: print "\n"+'%3s'%str(i)+"|", + ....: print '%3s'%str(designs.mutually_orthogonal_latin_squares(i,None,existence=True) if i>1 else "+oo"), + sage: MOLS_table(15) # long time + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 + ________________________________________________________________________________ + + 0| +oo +oo 1 2 3 4 1 6 7 8 1 10 4 12 1 2 15 16 2 18 + 20| 3 2 1 22 3 24 2 26 3 28 2 30 31 3 2 4 3 36 2 3 + 40| 4 40 2 42 3 4 2 46 3 48 2 3 3 52 4 4 6 3 2 58 + 60| 4 60 2 6 63 4 2 66 4 4 6 70 7 72 2 3 3 6 2 78 + 80| 7 80 4 82 6 6 6 3 7 88 2 6 3 4 2 6 7 96 6 8 + 100| 6 100 6 102 7 3 4 106 4 108 2 6 7 112 2 7 4 8 2 6 + 120| 6 120 2 6 4 124 6 126 127 4 6 130 6 6 2 6 7 136 4 138 + 140| 6 7 6 10 8 7 6 7 4 148 6 150 7 8 4 4 4 156 2 6 + 160| 7 7 2 162 4 7 4 166 7 168 6 8 6 172 6 6 10 6 6 178 + 180| 6 180 6 6 7 8 6 10 6 6 2 190 7 192 6 7 6 196 6 198 + 200| 7 7 6 7 4 6 6 8 12 10 6 210 6 7 6 6 7 8 4 10 + 220| 6 12 6 222 7 8 6 226 6 228 6 6 7 232 6 7 6 6 2 238 + 240| 7 240 6 242 6 7 6 12 7 7 3 250 3 10 3 7 255 256 4 7 + 260| 4 8 4 262 7 8 6 10 6 268 6 270 15 7 3 10 6 276 6 8 + 280| 7 280 6 282 6 12 6 7 15 288 6 6 4 292 6 6 7 10 6 12 + TODO: -* Implement Wilson's construction (page 146 of [Stinson2004]_) * Look at [ColDin01]_. REFERENCES: @@ -29,6 +62,9 @@ Volume 95, Issues 1-2, Pages 9-48, Journal of Statistical Planning and Inference, Springer, 1 May 2001. + +Functions +--------- """ from sage.misc.unknown import Unknown @@ -105,7 +141,8 @@ def mutually_orthogonal_latin_squares(n,k, partitions = False, check = True, exi - ``n`` (integer) -- size of the latin square. - - ``k`` (integer) -- number of MOLS. + - ``k`` (integer) -- number of MOLS. If ``k=None`` it is set to the largest + value available. - ``partition`` (boolean) -- a Latin Square can be seen as 3 partitions of the `n^2` cells of the array into `n` sets of size `n`, respectively : @@ -131,6 +168,12 @@ def mutually_orthogonal_latin_squares(n,k, partitions = False, check = True, exi - ``False`` -- meaning that the design does not exist. + .. NOTE:: + + When ``k=None`` and ``existence=True`` the function returns an + integer, i.e. the largest `k` such that we can build a `k` MOLS of + order `n`. + - ``check`` -- (boolean) Whether to check that output is correct before returning it. As this is expected to be useless (but we are cautious guys), you may want to disable it whenever you want speed. Set to @@ -193,10 +236,18 @@ def mutually_orthogonal_latin_squares(n,k, partitions = False, check = True, exi ValueError: There exist at most n-1 MOLS of size n. sage: designs.mutually_orthogonal_latin_squares(6,3,existence=True) Unknown + sage: designs.mutually_orthogonal_latin_squares(8,None,existence=True) + 7 """ from sage.combinat.designs.orthogonal_arrays import orthogonal_array from sage.matrix.constructor import Matrix + # Is k is None we find the largest available + if k is None: + k = orthogonal_array(None,n,existence=True) - 2 + if existence: + return k + if k >= n: if existence: return False diff --git a/src/sage/combinat/designs/orthogonal_arrays.py b/src/sage/combinat/designs/orthogonal_arrays.py index bcea37ec6a1..9cf1c43cada 100644 --- a/src/sage/combinat/designs/orthogonal_arrays.py +++ b/src/sage/combinat/designs/orthogonal_arrays.py @@ -45,7 +45,8 @@ def transversal_design(k,n,check=True,existence=False, who_asked=tuple()): INPUT: - - `n,k` -- integers. + - `n,k` -- integers. If ``k is None`` it is set to the largest value + available. - ``check`` -- (boolean) Whether to check that output is correct before returning it. As this is expected to be useless (but we are cautious @@ -61,6 +62,11 @@ def transversal_design(k,n,check=True,existence=False, who_asked=tuple()): - ``False`` -- meaning that the design does not exist. + .. NOTE:: + + When ``k=None`` and ``existence=True`` the function returns an + integer, i.e. the largest `k` such that we can build a `TD(k,n)`. + - ``who_asked`` (internal use only) -- because of the equivalence between OA/TD/MOLS, each of the three constructors calls the others. We must keep track of who calls who in order to avoid infinite loops. ``who_asked`` is @@ -134,10 +140,7 @@ def transversal_design(k,n,check=True,existence=False, who_asked=tuple()): sage: designs.transversal_design = designs.transversal_design sage: for n in xrange(2,25): # long time -- 15 secs - ....: i = 2 - ....: while designs.transversal_design(i, n, existence=True) is True: - ....: i += 1 - ....: _ = designs.transversal_design(i-1, n) + ....: i = designs.transversal_design(None, n, existence=True) + 1 ....: j = i ....: while designs.transversal_design(j, n, existence=True) is Unknown: ....: try: @@ -180,6 +183,12 @@ def transversal_design(k,n,check=True,existence=False, who_asked=tuple()): 23: (25, 25) 24: ( 6, 26) """ + # Is k is None we find the largest available + if k is None: + k = orthogonal_array(None,n,existence=True) + if existence: + return k + if k >= n+2: if existence: return False @@ -567,7 +576,8 @@ def orthogonal_array(k,n,t=2,check=True,existence=False,who_asked=tuple()): INPUT: - - ``k`` -- (integer) number of columns + - ``k`` -- (integer) number of columns. If ``k=None`` it is set to the + largest value available. - ``n`` -- (integer) number of symbols @@ -587,6 +597,11 @@ def orthogonal_array(k,n,t=2,check=True,existence=False,who_asked=tuple()): - ``False`` -- meaning that the design does not exist. + .. NOTE:: + + When ``k=None`` and ``existence=True`` the function returns an + integer, i.e. the largest `k` such that we can build a `OA(k,n)`. + - ``who_asked`` (internal use only) -- because of the equivalence between OA/TD/MOLS, each of the three constructors calls the others. We must keep track of who calls who in order to avoid infinite loops. ``who_asked`` is @@ -629,12 +644,21 @@ def orthogonal_array(k,n,t=2,check=True,existence=False,who_asked=tuple()): Traceback (most recent call last): ... EmptySetError: No Orthogonal Array exists when k>=n+t + sage: designs.orthogonal_array(None,14,existence=True) + 3 """ - from sage.rings.arith import is_prime_power from sage.rings.finite_rings.constructor import FiniteField from latin_squares import mutually_orthogonal_latin_squares from block_design import projective_plane, projective_plane_to_OA + # If k is set to None we find the largest value available + if k is None: + for k in range(1,n+2): + if not orthogonal_array(k+1,n,existence=True): + break + if existence: + return k + if k < 2: raise ValueError("undefined for k less than 2") From 5e8b2af4ac6d3ab639d3ab08957459e7453447b6 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 4 May 2014 16:33:54 +0200 Subject: [PATCH 08/18] trac #16277: removes a doctests that appears several times already --- src/sage/combinat/designs/orthogonal_arrays.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/sage/combinat/designs/orthogonal_arrays.py b/src/sage/combinat/designs/orthogonal_arrays.py index d3e391bbfca..5793a6b233f 100644 --- a/src/sage/combinat/designs/orthogonal_arrays.py +++ b/src/sage/combinat/designs/orthogonal_arrays.py @@ -185,10 +185,6 @@ def transversal_design(k,n,check=True,existence=False, who_asked=tuple()): 22: ( 6, 23) 23: (25, 25) 24: (10, 26) - - `TD(6,12)` :: - - sage: _ = designs.transversal_design(6,12) """ if k >= n+2: if existence: From 1a13ff836476bb11969cdfe9f36ff21fd3c5a7b2 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 2 May 2014 17:46:42 +0200 Subject: [PATCH 09/18] trac #16241: New MOLS shared by Ian Wanless --- src/sage/combinat/designs/database.py | 319 ++++++++++++++++++++- src/sage/combinat/designs/latin_squares.py | 9 + 2 files changed, 326 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index d550e964f7a..3d73674da7b 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -53,9 +53,12 @@ The functions defined here are used by :func:`~sage.combinat.designs.orthogonal_arrays.orthogonal_array`. Thus, the -functions are indexed by a dictionary which associates to every integer ``n`` a +functions are indexed by dictionary which associates to every integer ``n`` a pair ``(k,f)`` where ``f`` is a function such that ``f()`` is a `OA(k,n)`. This -dictionary is defined in this module at the end of the file. +dictionary is defined right after the constructions of OA in the file. + +The same goes for the constructions of MOLS, used by +:func:`~sage.combinat.designs.latin_squares.mutually_orthogonal_latin_squares`. REFERENCES: @@ -75,6 +78,29 @@ # Cyclic shift of a list cyclic_shift = lambda l,i : l[-i:]+l[:-i] +def _MOLS_from_string(s,k): + r""" + Returns MOLS from a string + + INPUT: + + - ``s`` (string) -- represents the MOLS with entries in 0-z. To understand + how the string should be formatted, read the source code of a constructor + that uses it. + + - ``k`` (integer) -- the number of MOLS encoded by the string. + + EXAMPLES:: + + sage: _ = designs.mutually_orthogonal_latin_squares(10,2) # indirect doctest + """ + from sage.matrix.constructor import Matrix + matrices = [[] for _ in range(k)] + for i,l in enumerate(s.split()): + l = [ord(x) - 97 for x in l] + matrices[i%k].append(l) + return map(Matrix, matrices) + def MOLS_10_2(): r""" Returns a pair of MOLS of order 10 @@ -121,6 +147,295 @@ def MOLS_10_2(): [5,6,7,1,2,3,4,0,9,8], [7,1,2,3,4,5,6,9,8,0]])] +def MOLS_14_4(): + r""" + Returns four MOLS of order 14 + + These MOLS were shared by Ian Wanless. + + EXAMPLES:: + + sage: designs.mutually_orthogonal_latin_squares(14,4) + [ + [ 1 9 8 7 6 10 4 2 0 11 13 5 12 3] + [ 5 2 10 9 1 7 11 4 3 8 12 0 6 13] + [12 6 3 11 10 2 1 0 5 4 9 13 8 7] + [ 2 13 7 4 12 11 3 1 8 6 5 10 0 9] + [ 4 3 0 1 5 13 12 10 2 9 7 6 11 8] + [13 5 4 8 2 6 0 9 11 3 10 1 7 12] + [ 8 0 6 5 9 3 7 13 10 12 4 11 2 1] + [ 3 11 13 10 4 0 5 8 12 7 2 9 1 6] + [ 6 4 12 0 11 5 8 7 9 13 1 3 10 2] + [ 9 7 5 13 8 12 6 3 1 10 0 2 4 11] + [ 7 10 1 6 0 9 13 12 4 2 11 8 3 5] + [ 0 1 11 2 7 8 10 6 13 5 3 12 9 4] + [11 8 2 12 3 1 9 5 7 0 6 4 13 10] + [10 12 9 3 13 4 2 11 6 1 8 7 5 0], + + [ 1 5 12 2 4 13 8 3 6 9 7 0 11 10] + [ 9 2 6 13 3 5 0 11 4 7 10 1 8 12] + [ 8 10 3 7 0 4 6 13 12 5 1 11 2 9] + [ 7 9 11 4 1 8 5 10 0 13 6 2 12 3] + [ 6 1 10 12 5 2 9 4 11 8 0 7 3 13] + [10 7 2 11 13 6 3 0 5 12 9 8 1 4] + [ 4 11 1 3 12 0 7 5 8 6 13 10 9 2] + [ 2 4 0 1 10 9 13 8 7 3 12 6 5 11] + [ 0 3 5 8 2 11 10 12 9 1 4 13 7 6] + [11 8 4 6 9 3 12 7 13 10 2 5 0 1] + [13 12 9 5 7 10 4 2 1 0 11 3 6 8] + [ 5 0 13 10 6 1 11 9 3 2 8 12 4 7] + [12 6 8 0 11 7 2 1 10 4 3 9 13 5] + [ 3 13 7 9 8 12 1 6 2 11 5 4 10 0], + + [ 1 2 3 4 5 6 7 8 9 10 11 12 13 0] + [ 6 13 10 9 3 12 8 2 11 1 7 0 4 5] + [11 8 5 7 1 9 4 12 10 0 13 6 2 3] + [ 3 0 11 12 6 13 1 9 4 7 2 5 8 10] + [13 9 2 0 4 8 5 7 1 3 6 10 12 11] + [12 5 1 10 2 3 11 0 6 13 9 8 7 4] + [ 0 4 12 13 7 10 9 3 2 8 5 1 11 6] + [ 7 3 13 8 10 1 0 6 12 2 4 11 5 9] + [ 2 6 9 5 11 7 13 1 8 4 10 3 0 12] + [ 5 10 8 1 12 0 6 4 13 11 3 7 9 2] + [ 8 12 7 11 13 4 2 10 3 5 0 9 6 1] + [10 11 4 6 0 5 3 13 7 9 12 2 1 8] + [ 9 7 0 3 8 2 12 11 5 6 1 4 10 13] + [ 4 1 6 2 9 11 10 5 0 12 8 13 3 7], + + [ 1 2 3 4 5 6 7 8 9 10 11 12 13 0] + [ 9 5 11 7 13 10 0 4 2 12 6 3 8 1] + [ 4 12 10 3 9 1 6 5 13 11 8 0 7 2] + [ 0 13 8 6 7 12 5 11 10 1 3 2 4 9] + [10 4 1 2 0 9 8 12 3 6 5 7 11 13] + [ 2 6 13 5 11 4 12 1 8 7 0 10 9 3] + [ 8 11 0 1 10 3 13 7 5 2 9 4 6 12] + [11 9 6 13 8 7 4 2 1 0 12 5 3 10] + [13 3 12 0 1 2 9 6 11 5 4 8 10 7] + [12 1 7 8 4 5 11 9 0 3 10 13 2 6] + [ 3 8 5 9 2 13 10 0 12 4 7 6 1 11] + [ 6 7 2 10 12 11 1 3 4 8 13 9 0 5] + [ 5 0 9 11 6 8 3 10 7 13 2 1 12 4] + [ 7 10 4 12 3 0 2 13 6 9 1 11 5 8] + ] + """ + M = """ + bjihgkecalnfmd bfmcenidgjhalk bcdefghijklmna bcdefghijklmna + fckjbhledimagn jcgndfalehkbim gnkjdmiclbhaef jflhnkaecmgdib + mgdlkcbafejnih ikdhaegnmfblcj lifhbjemkangcd emkdjbgfnliahc + cnhemldbigfkaj hjlebifkangcmd dalmgnbjehcfik anighmflkbdcej + edabfnmkcjhgli gbkmfcjeliahdn njcaeifhbdgkml kebcajimdgfhln + nfeicgajldkbhm khclngdafmjibe mfbkcdlagnjihe cgnflembihakjd + iagfjdhnkmelcb elbdmahfignkjc aemnhkjdcifblg ilabkdnhfcjegm + dlnkeafimhcjbg ceabkjnihdmgfl hdnikbagmcelfj ljgnihecbamfdk + gemalfihjnbdkc adficlkmjbenhg cgjflhnbiekdam ndmabcjglfeikh + jhfnimgdbkacel liegjdmhnkcfab fkibmagenldhjc mbhiefljadkncg + hkbgajnmeclidf nmjfhkecbaldgi imhlneckdfajgb difjcnkamehgbl + ablchikgnfdmje fankgbljdcimeh klegafdnhjmcbi ghckmlbdeinjaf + licmdbjfhagenk mgialhcbkedjnf jhadicmlfgbekn fajlgidkhncbme + kmjdneclgbihfa dnhjimbgclfeka ebgcjlkfamindh hkemdacngjblfi + """ + + return _MOLS_from_string(M,4) + +def MOLS_15_4(): + r""" + Returns 4 MOLS of order 15. + + These MOLS were shared by Ian Wanless. + + EXAMPLES:: + + sage: designs.mutually_orthogonal_latin_squares(15,4) + [ + [ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 0] + [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14] + [14 0 1 2 3 4 5 6 7 8 9 10 11 12 13] + [13 14 0 1 2 3 4 5 6 7 8 9 10 11 12] + [12 13 14 0 1 2 3 4 5 6 7 8 9 10 11] + [11 12 13 14 0 1 2 3 4 5 6 7 8 9 10] + [10 11 12 13 14 0 1 2 3 4 5 6 7 8 9] + [ 9 10 11 12 13 14 0 1 2 3 4 5 6 7 8] + [ 8 9 10 11 12 13 14 0 1 2 3 4 5 6 7] + [ 7 8 9 10 11 12 13 14 0 1 2 3 4 5 6] + [ 6 7 8 9 10 11 12 13 14 0 1 2 3 4 5] + [ 5 6 7 8 9 10 11 12 13 14 0 1 2 3 4] + [ 4 5 6 7 8 9 10 11 12 13 14 0 1 2 3] + [ 3 4 5 6 7 8 9 10 11 12 13 14 0 1 2] + [ 2 3 4 5 6 7 8 9 10 11 12 13 14 0 1], + + [ 1 3 6 8 10 13 5 2 0 12 4 7 9 11 14] + [ 0 2 4 7 9 11 14 6 3 1 13 5 8 10 12] + [13 1 3 5 8 10 12 0 7 4 2 14 6 9 11] + [12 14 2 4 6 9 11 13 1 8 5 3 0 7 10] + [11 13 0 3 5 7 10 12 14 2 9 6 4 1 8] + [ 9 12 14 1 4 6 8 11 13 0 3 10 7 5 2] + [ 3 10 13 0 2 5 7 9 12 14 1 4 11 8 6] + [ 7 4 11 14 1 3 6 8 10 13 0 2 5 12 9] + [10 8 5 12 0 2 4 7 9 11 14 1 3 6 13] + [14 11 9 6 13 1 3 5 8 10 12 0 2 4 7] + [ 8 0 12 10 7 14 2 4 6 9 11 13 1 3 5] + [ 6 9 1 13 11 8 0 3 5 7 10 12 14 2 4] + [ 5 7 10 2 14 12 9 1 4 6 8 11 13 0 3] + [ 4 6 8 11 3 0 13 10 2 5 7 9 12 14 1] + [ 2 5 7 9 12 4 1 14 11 3 6 8 10 13 0], + + [ 1 7 4 0 11 8 14 5 12 3 9 6 2 13 10] + [11 2 8 5 1 12 9 0 6 13 4 10 7 3 14] + [ 0 12 3 9 6 2 13 10 1 7 14 5 11 8 4] + [ 5 1 13 4 10 7 3 14 11 2 8 0 6 12 9] + [10 6 2 14 5 11 8 4 0 12 3 9 1 7 13] + [14 11 7 3 0 6 12 9 5 1 13 4 10 2 8] + [ 9 0 12 8 4 1 7 13 10 6 2 14 5 11 3] + [ 4 10 1 13 9 5 2 8 14 11 7 3 0 6 12] + [13 5 11 2 14 10 6 3 9 0 12 8 4 1 7] + [ 8 14 6 12 3 0 11 7 4 10 1 13 9 5 2] + [ 3 9 0 7 13 4 1 12 8 5 11 2 14 10 6] + [ 7 4 10 1 8 14 5 2 13 9 6 12 3 0 11] + [12 8 5 11 2 9 0 6 3 14 10 7 13 4 1] + [ 2 13 9 6 12 3 10 1 7 4 0 11 8 14 5] + [ 6 3 14 10 7 13 4 11 2 8 5 1 12 9 0], + + [ 1 11 7 2 12 3 8 13 4 9 14 5 0 10 6] + [ 7 2 12 8 3 13 4 9 14 5 10 0 6 1 11] + [12 8 3 13 9 4 14 5 10 0 6 11 1 7 2] + [ 3 13 9 4 14 10 5 0 6 11 1 7 12 2 8] + [ 9 4 14 10 5 0 11 6 1 7 12 2 8 13 3] + [ 4 10 5 0 11 6 1 12 7 2 8 13 3 9 14] + [ 0 5 11 6 1 12 7 2 13 8 3 9 14 4 10] + [11 1 6 12 7 2 13 8 3 14 9 4 10 0 5] + [ 6 12 2 7 13 8 3 14 9 4 0 10 5 11 1] + [ 2 7 13 3 8 14 9 4 0 10 5 1 11 6 12] + [13 3 8 14 4 9 0 10 5 1 11 6 2 12 7] + [ 8 14 4 9 0 5 10 1 11 6 2 12 7 3 13] + [14 9 0 5 10 1 6 11 2 12 7 3 13 8 4] + [ 5 0 10 1 6 11 2 7 12 3 13 8 4 14 9] + [10 6 1 11 2 7 12 3 8 13 4 14 9 5 0] + ] + """ + M = """ + bcdefghijklmnoa bdgiknfcamehjlo bhealiofmdjgcnk blhcmdinejofakg + abcdefghijklmno acehjlogdbnfikm lcifbmjagnekhdo hcmidnejofkagbl + oabcdefghijklmn nbdfikmahecogjl amdjgcnkbhoflie midnjeofkaglbhc + noabcdefghijklm mocegjlnbifdahk fbnekhdolciagmj dnjeokfaglbhmci + mnoabcdefghijkl lnadfhkmocjgebi kgcoflieamdjbhn jeokfalgbhmcind + lmnoabcdefghijk jmobegilnadkhfc olhdagmjfbnekci ekfalgbmhcindjo + klmnoabcdefghij dknacfhjmobelig jamiebhnkgcofld aflgbmhcnidjoek + jklmnoabcdefghi helobdgiknacfmj ekbnjfciolhdagm lbgmhcnidojekaf + ijklmnoabcdefgh kifmacehjlobdgn nflcokgdjamiebh gmchnidojeakflb + hijklmnoabcdefg oljgnbdfikmaceh iogmdalhekbnjfc chndiojeakfblgm + ghijklmnoabcdef iamkhocegjlnbdf djahnebmiflcokg ndioejakfblgcmh + fghijklmnoabcde gjbnliadfhkmoce hekbiofcnjgmdal ioejafkblgcmhdn + efghijklmnoabcd fhkcomjbegilnad miflcjagdokhneb ojafkbglcmhdnie + defghijklmnoabc egildankcfhjmob cnjgmdkbhealiof fakbglchmdnieoj + cdefghijklmnoab cfhjmeboldgikna gdokhnelcifbmja kgblchmdineojfa + """ + + return _MOLS_from_string(M,4) + +def MOLS_18_3(): + r""" + Returns 3 MOLS of order 18. + + These MOLS were shared by Ian Wanless. + + EXAMPLES:: + + sage: designs.mutually_orthogonal_latin_squares(18,3) + [ + [ 1 6 4 9 7 10 12 14 3 2 13 0 17 8 11 15 5 16] + [ 4 2 7 5 1 8 11 13 15 17 3 14 10 0 9 12 16 6] + [16 5 3 8 6 2 9 12 14 7 0 4 15 11 10 1 13 17] + [15 17 6 4 9 7 3 1 13 0 8 10 5 16 12 11 2 14] + [14 16 0 7 5 1 8 4 2 15 10 9 11 6 17 13 12 3] + [ 3 15 17 10 8 6 2 9 5 4 16 11 1 12 7 0 14 13] + [ 6 4 16 0 11 9 7 3 1 14 5 17 12 2 13 8 10 15] + [ 2 7 5 17 10 12 1 8 4 16 15 6 0 13 3 14 9 11] + [ 5 3 8 6 0 11 13 2 9 12 17 16 7 10 14 4 15 1] + [11 13 1 16 2 14 6 15 0 10 12 7 3 17 8 5 4 9] + [10 12 14 2 17 3 15 7 16 1 11 13 8 4 0 9 6 5] + [17 11 13 15 3 0 4 16 8 6 2 12 14 9 5 10 1 7] + [ 9 0 12 14 16 4 10 5 17 8 7 3 13 15 1 6 11 2] + [ 0 1 10 13 15 17 5 11 6 3 9 8 4 14 16 2 7 12] + [ 7 10 2 11 14 16 0 6 12 13 4 1 9 5 15 17 3 8] + [13 8 11 3 12 15 17 10 7 9 14 5 2 1 6 16 0 4] + [ 8 14 9 12 4 13 16 0 11 5 1 15 6 3 2 7 17 10] + [12 9 15 1 13 5 14 17 10 11 6 2 16 7 4 3 8 0], + + [ 1 4 16 15 14 3 6 2 5 11 10 17 9 0 7 13 8 12] + [ 6 2 5 17 16 15 4 7 3 13 12 11 0 1 10 8 14 9] + [ 4 7 3 6 0 17 16 5 8 1 14 13 12 10 2 11 9 15] + [ 9 5 8 4 7 10 0 17 6 16 2 15 14 13 11 3 12 1] + [ 7 1 6 9 5 8 11 10 0 2 17 3 16 15 14 12 4 13] + [10 8 2 7 1 6 9 12 11 14 3 0 4 17 16 15 13 5] + [12 11 9 3 8 2 7 1 13 6 15 4 10 5 0 17 16 14] + [14 13 12 1 4 9 3 8 2 15 7 16 5 11 6 10 0 17] + [ 3 15 14 13 2 5 1 4 9 0 16 8 17 6 12 7 11 10] + [ 2 17 7 0 15 4 14 16 12 10 1 6 8 3 13 9 5 11] + [13 3 0 8 10 16 5 15 17 12 11 2 7 9 4 14 1 6] + [ 0 14 4 10 9 11 17 6 16 7 13 12 3 8 1 5 15 2] + [17 10 15 5 11 1 12 0 7 3 8 14 13 4 9 2 6 16] + [ 8 0 11 16 6 12 2 13 10 17 4 9 15 14 5 1 3 7] + [11 9 10 12 17 7 13 3 14 8 0 5 1 16 15 6 2 4] + [15 12 1 11 13 0 8 14 4 5 9 10 6 2 17 16 7 3] + [ 5 16 13 2 12 14 10 9 15 4 6 1 11 7 3 0 17 8] + [16 6 17 14 3 13 15 11 1 9 5 7 2 12 8 4 10 0], + + [ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 0] + [17 1 10 0 12 5 6 3 4 7 16 9 8 13 14 15 2 11] + [12 11 1 16 7 8 5 6 0 9 3 2 17 4 13 14 15 10] + [ 7 8 9 1 2 3 4 5 6 16 17 0 10 11 12 13 14 15] + [ 6 3 4 17 1 10 0 12 5 15 2 11 7 16 9 8 13 14] + [ 5 6 0 12 11 1 16 7 8 14 15 10 9 3 2 17 4 13] + [ 4 5 6 7 8 9 1 2 3 13 14 15 16 17 0 10 11 12] + [ 0 12 5 6 3 4 17 1 10 8 13 14 15 2 11 7 16 9] + [16 7 8 5 6 0 12 11 1 17 4 13 14 15 10 9 3 2] + [11 4 16 9 15 14 13 0 2 1 10 8 3 5 6 12 7 17] + [10 9 12 2 17 15 14 13 7 11 1 16 4 0 5 6 8 3] + [ 3 16 17 8 10 11 15 14 13 0 9 1 2 12 7 5 6 4] + [13 0 2 11 4 16 9 15 14 12 7 17 1 10 8 3 5 6] + [14 13 7 10 9 12 2 17 15 6 8 3 11 1 16 4 0 5] + [15 14 13 3 16 17 8 10 11 5 6 4 0 9 1 2 12 7] + [ 9 15 14 13 0 2 11 4 16 3 5 6 12 7 17 1 10 8] + [ 2 17 15 14 13 7 10 9 12 4 0 5 6 8 3 11 1 16] + [ 8 10 11 15 14 13 3 16 17 2 12 7 5 6 4 0 9 1] + ] + """ + M = """ + bgejhkmodcnarilpfq beqpodgcflkrjahnim bcdefghijklmnopqra + echfbilnprdokajmqg gcfrqpehdnmlabkioj rbkamfgdehqjinopcl + qfdigcjmohaeplkbnr ehdgarqfibonmkcljp mlbqhifgajdcrenopk + prgejhdbnaikfqmlco jfiehkargqcponldmb hijbcdefgqraklmnop + oqahfbiecpkjlgrnmd hbgjfilkacrdqpomen gderbkamfpclhqjino + dprkigcjfeqlbmhaon kichbgjmlodaerqpnf fgamlbqhiopkjdcren + geqaljhdbofrmcnikp mljdichbngpekfarqo efghijbcdnopqraklm + chfrkmbieqpgandojl onmbejdicphqflgkar amfgderbkinopclhqj + fdigalncjmrqhkoepb dponcfbejaqirgmhlk qhifgamlbrenopkjdc + lnbqcogpakmhdrifej crhapeoqmkbgidnjfl leqjponacbkidfgmhr + kmocrdphqblnieajgf ndaikqfprmlchjeobg kjmcrponhlbqeafgid + rlnpdaeqigcmojfkbh aoekjlrgqhnmdibfpc dqriklponajbcmhfge + jamoqekfrihdnpbglc rkpflbmahdionejcgq nacleqjpomhrbkidfg + abknprflgdjieoqchm ialqgmcnkrejpofbdh onhkjmcrpgidlbqeaf + hkcloqagmnebjfprdi ljkmrhndoiafbqpgce pondqriklfgeajbcmh + nildmprkhjofcbgqae pmblnaioefjkgcrqhd jponacleqdfgmhrbki + iojmenqalfbpgdchrk fqncmokjpegblhdari crponhkjmeafgidlbq + mjpbnforklgcqhedia qgrodnplbjfhcmieka iklpondqrcmhfgeajb + """ + + return _MOLS_from_string(M,3) + +# Index of the MOLS constructions +# +# Associates to n the pair (k,f) where f() is a function that returns k MOLS of order n +# +# This dictionary is used by designs.mutually_orthogonal_latin_squares(n,k). + +MOLS_constructions = { + 10 : (2, MOLS_10_2), + 14 : (4, MOLS_14_4), + 15 : (4, MOLS_15_4), + 18 : (3, MOLS_18_3) +} + def OA_6_20(): r""" Returns an OA(6,20) diff --git a/src/sage/combinat/designs/latin_squares.py b/src/sage/combinat/designs/latin_squares.py index 4a7d715ee3b..a74ac65429c 100644 --- a/src/sage/combinat/designs/latin_squares.py +++ b/src/sage/combinat/designs/latin_squares.py @@ -256,6 +256,8 @@ def mutually_orthogonal_latin_squares(n,k, partitions = False, check = True, exi """ from sage.combinat.designs.orthogonal_arrays import orthogonal_array from sage.matrix.constructor import Matrix + from sage.rings.arith import factor + from database import MOLS_constructions # Is k is None we find the largest available if k is None: @@ -275,6 +277,13 @@ def mutually_orthogonal_latin_squares(n,k, partitions = False, check = True, exi from database import MOLS_10_2 matrices = MOLS_10_2() + elif n in MOLS_constructions and k <= MOLS_constructions[n][0]: + if availability: + return True + _, construction = MOLS_constructions[n] + + matrices = construction()[:k] + elif (orthogonal_array not in who_asked and orthogonal_array(k+2,n,existence=True,who_asked = who_asked+(mutually_orthogonal_latin_squares,)) is not Unknown): From 2af2acfd8faeb597ac2f730a0e1d17eb1f6a597e Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sat, 3 May 2014 11:11:17 +0200 Subject: [PATCH 10/18] trac #16241: missing links and tests --- src/sage/combinat/designs/database.py | 247 +++++--------------------- 1 file changed, 45 insertions(+), 202 deletions(-) diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index 3d73674da7b..408e421d40b 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -47,7 +47,10 @@ :func:`OA(12,144) `, :func:`OA(12,210) ` -- :func:`two MOLS of order 10 ` +- :func:`two MOLS of order 10 `, + :func:`four MOLS of order 14 `, + :func:`four MOLS of order 15 `, + :func:`three MOLS of order 18 ` **Dictionaries** @@ -84,7 +87,7 @@ def _MOLS_from_string(s,k): INPUT: - - ``s`` (string) -- represents the MOLS with entries in 0-z. To understand + - ``s`` (string) -- represents the MOLS with entries in a-z. To understand how the string should be formatted, read the source code of a constructor that uses it. @@ -110,19 +113,16 @@ def MOLS_10_2(): EXAMPLES:: - sage: designs.mutually_orthogonal_latin_squares(10,2) # indirect doctest - [ - [1 8 9 0 2 4 6 3 5 7] [1 7 6 5 0 9 8 2 3 4] - [7 2 8 9 0 3 5 4 6 1] [8 2 1 7 6 0 9 3 4 5] - [6 1 3 8 9 0 4 5 7 2] [9 8 3 2 1 7 0 4 5 6] - [5 7 2 4 8 9 0 6 1 3] [0 9 8 4 3 2 1 5 6 7] - [0 6 1 3 5 8 9 7 2 4] [2 0 9 8 5 4 3 6 7 1] - [9 0 7 2 4 6 8 1 3 5] [4 3 0 9 8 6 5 7 1 2] - [8 9 0 1 3 5 7 2 4 6] [6 5 4 0 9 8 7 1 2 3] - [2 3 4 5 6 7 1 8 9 0] [3 4 5 6 7 1 2 8 0 9] - [3 4 5 6 7 1 2 0 8 9] [5 6 7 1 2 3 4 0 9 8] - [4 5 6 7 1 2 3 9 0 8], [7 1 2 3 4 5 6 9 8 0] - ] + sage: from sage.combinat.designs.latin_squares import are_mutually_orthogonal_latin_squares + sage: from sage.combinat.designs.database import MOLS_10_2 + sage: MOLS = MOLS_10_2() + sage: print are_mutually_orthogonal_latin_squares(MOLS) + True + + The design is available from the general constructor:: + + sage: designs.mutually_orthogonal_latin_squares(10,2,availability=True) + True """ from sage.matrix.constructor import Matrix return [Matrix([[1,8,9,0,2,4,6,3,5,7], @@ -155,68 +155,16 @@ def MOLS_14_4(): EXAMPLES:: - sage: designs.mutually_orthogonal_latin_squares(14,4) - [ - [ 1 9 8 7 6 10 4 2 0 11 13 5 12 3] - [ 5 2 10 9 1 7 11 4 3 8 12 0 6 13] - [12 6 3 11 10 2 1 0 5 4 9 13 8 7] - [ 2 13 7 4 12 11 3 1 8 6 5 10 0 9] - [ 4 3 0 1 5 13 12 10 2 9 7 6 11 8] - [13 5 4 8 2 6 0 9 11 3 10 1 7 12] - [ 8 0 6 5 9 3 7 13 10 12 4 11 2 1] - [ 3 11 13 10 4 0 5 8 12 7 2 9 1 6] - [ 6 4 12 0 11 5 8 7 9 13 1 3 10 2] - [ 9 7 5 13 8 12 6 3 1 10 0 2 4 11] - [ 7 10 1 6 0 9 13 12 4 2 11 8 3 5] - [ 0 1 11 2 7 8 10 6 13 5 3 12 9 4] - [11 8 2 12 3 1 9 5 7 0 6 4 13 10] - [10 12 9 3 13 4 2 11 6 1 8 7 5 0], - - [ 1 5 12 2 4 13 8 3 6 9 7 0 11 10] - [ 9 2 6 13 3 5 0 11 4 7 10 1 8 12] - [ 8 10 3 7 0 4 6 13 12 5 1 11 2 9] - [ 7 9 11 4 1 8 5 10 0 13 6 2 12 3] - [ 6 1 10 12 5 2 9 4 11 8 0 7 3 13] - [10 7 2 11 13 6 3 0 5 12 9 8 1 4] - [ 4 11 1 3 12 0 7 5 8 6 13 10 9 2] - [ 2 4 0 1 10 9 13 8 7 3 12 6 5 11] - [ 0 3 5 8 2 11 10 12 9 1 4 13 7 6] - [11 8 4 6 9 3 12 7 13 10 2 5 0 1] - [13 12 9 5 7 10 4 2 1 0 11 3 6 8] - [ 5 0 13 10 6 1 11 9 3 2 8 12 4 7] - [12 6 8 0 11 7 2 1 10 4 3 9 13 5] - [ 3 13 7 9 8 12 1 6 2 11 5 4 10 0], - - [ 1 2 3 4 5 6 7 8 9 10 11 12 13 0] - [ 6 13 10 9 3 12 8 2 11 1 7 0 4 5] - [11 8 5 7 1 9 4 12 10 0 13 6 2 3] - [ 3 0 11 12 6 13 1 9 4 7 2 5 8 10] - [13 9 2 0 4 8 5 7 1 3 6 10 12 11] - [12 5 1 10 2 3 11 0 6 13 9 8 7 4] - [ 0 4 12 13 7 10 9 3 2 8 5 1 11 6] - [ 7 3 13 8 10 1 0 6 12 2 4 11 5 9] - [ 2 6 9 5 11 7 13 1 8 4 10 3 0 12] - [ 5 10 8 1 12 0 6 4 13 11 3 7 9 2] - [ 8 12 7 11 13 4 2 10 3 5 0 9 6 1] - [10 11 4 6 0 5 3 13 7 9 12 2 1 8] - [ 9 7 0 3 8 2 12 11 5 6 1 4 10 13] - [ 4 1 6 2 9 11 10 5 0 12 8 13 3 7], - - [ 1 2 3 4 5 6 7 8 9 10 11 12 13 0] - [ 9 5 11 7 13 10 0 4 2 12 6 3 8 1] - [ 4 12 10 3 9 1 6 5 13 11 8 0 7 2] - [ 0 13 8 6 7 12 5 11 10 1 3 2 4 9] - [10 4 1 2 0 9 8 12 3 6 5 7 11 13] - [ 2 6 13 5 11 4 12 1 8 7 0 10 9 3] - [ 8 11 0 1 10 3 13 7 5 2 9 4 6 12] - [11 9 6 13 8 7 4 2 1 0 12 5 3 10] - [13 3 12 0 1 2 9 6 11 5 4 8 10 7] - [12 1 7 8 4 5 11 9 0 3 10 13 2 6] - [ 3 8 5 9 2 13 10 0 12 4 7 6 1 11] - [ 6 7 2 10 12 11 1 3 4 8 13 9 0 5] - [ 5 0 9 11 6 8 3 10 7 13 2 1 12 4] - [ 7 10 4 12 3 0 2 13 6 9 1 11 5 8] - ] + sage: from sage.combinat.designs.latin_squares import are_mutually_orthogonal_latin_squares + sage: from sage.combinat.designs.database import MOLS_14_4 + sage: MOLS = MOLS_14_4() + sage: print are_mutually_orthogonal_latin_squares(MOLS) + True + + The design is available from the general constructor:: + + sage: designs.mutually_orthogonal_latin_squares(14,4,availability=True) + True """ M = """ bjihgkecalnfmd bfmcenidgjhalk bcdefghijklmna bcdefghijklmna @@ -245,72 +193,16 @@ def MOLS_15_4(): EXAMPLES:: - sage: designs.mutually_orthogonal_latin_squares(15,4) - [ - [ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 0] - [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14] - [14 0 1 2 3 4 5 6 7 8 9 10 11 12 13] - [13 14 0 1 2 3 4 5 6 7 8 9 10 11 12] - [12 13 14 0 1 2 3 4 5 6 7 8 9 10 11] - [11 12 13 14 0 1 2 3 4 5 6 7 8 9 10] - [10 11 12 13 14 0 1 2 3 4 5 6 7 8 9] - [ 9 10 11 12 13 14 0 1 2 3 4 5 6 7 8] - [ 8 9 10 11 12 13 14 0 1 2 3 4 5 6 7] - [ 7 8 9 10 11 12 13 14 0 1 2 3 4 5 6] - [ 6 7 8 9 10 11 12 13 14 0 1 2 3 4 5] - [ 5 6 7 8 9 10 11 12 13 14 0 1 2 3 4] - [ 4 5 6 7 8 9 10 11 12 13 14 0 1 2 3] - [ 3 4 5 6 7 8 9 10 11 12 13 14 0 1 2] - [ 2 3 4 5 6 7 8 9 10 11 12 13 14 0 1], - - [ 1 3 6 8 10 13 5 2 0 12 4 7 9 11 14] - [ 0 2 4 7 9 11 14 6 3 1 13 5 8 10 12] - [13 1 3 5 8 10 12 0 7 4 2 14 6 9 11] - [12 14 2 4 6 9 11 13 1 8 5 3 0 7 10] - [11 13 0 3 5 7 10 12 14 2 9 6 4 1 8] - [ 9 12 14 1 4 6 8 11 13 0 3 10 7 5 2] - [ 3 10 13 0 2 5 7 9 12 14 1 4 11 8 6] - [ 7 4 11 14 1 3 6 8 10 13 0 2 5 12 9] - [10 8 5 12 0 2 4 7 9 11 14 1 3 6 13] - [14 11 9 6 13 1 3 5 8 10 12 0 2 4 7] - [ 8 0 12 10 7 14 2 4 6 9 11 13 1 3 5] - [ 6 9 1 13 11 8 0 3 5 7 10 12 14 2 4] - [ 5 7 10 2 14 12 9 1 4 6 8 11 13 0 3] - [ 4 6 8 11 3 0 13 10 2 5 7 9 12 14 1] - [ 2 5 7 9 12 4 1 14 11 3 6 8 10 13 0], - - [ 1 7 4 0 11 8 14 5 12 3 9 6 2 13 10] - [11 2 8 5 1 12 9 0 6 13 4 10 7 3 14] - [ 0 12 3 9 6 2 13 10 1 7 14 5 11 8 4] - [ 5 1 13 4 10 7 3 14 11 2 8 0 6 12 9] - [10 6 2 14 5 11 8 4 0 12 3 9 1 7 13] - [14 11 7 3 0 6 12 9 5 1 13 4 10 2 8] - [ 9 0 12 8 4 1 7 13 10 6 2 14 5 11 3] - [ 4 10 1 13 9 5 2 8 14 11 7 3 0 6 12] - [13 5 11 2 14 10 6 3 9 0 12 8 4 1 7] - [ 8 14 6 12 3 0 11 7 4 10 1 13 9 5 2] - [ 3 9 0 7 13 4 1 12 8 5 11 2 14 10 6] - [ 7 4 10 1 8 14 5 2 13 9 6 12 3 0 11] - [12 8 5 11 2 9 0 6 3 14 10 7 13 4 1] - [ 2 13 9 6 12 3 10 1 7 4 0 11 8 14 5] - [ 6 3 14 10 7 13 4 11 2 8 5 1 12 9 0], - - [ 1 11 7 2 12 3 8 13 4 9 14 5 0 10 6] - [ 7 2 12 8 3 13 4 9 14 5 10 0 6 1 11] - [12 8 3 13 9 4 14 5 10 0 6 11 1 7 2] - [ 3 13 9 4 14 10 5 0 6 11 1 7 12 2 8] - [ 9 4 14 10 5 0 11 6 1 7 12 2 8 13 3] - [ 4 10 5 0 11 6 1 12 7 2 8 13 3 9 14] - [ 0 5 11 6 1 12 7 2 13 8 3 9 14 4 10] - [11 1 6 12 7 2 13 8 3 14 9 4 10 0 5] - [ 6 12 2 7 13 8 3 14 9 4 0 10 5 11 1] - [ 2 7 13 3 8 14 9 4 0 10 5 1 11 6 12] - [13 3 8 14 4 9 0 10 5 1 11 6 2 12 7] - [ 8 14 4 9 0 5 10 1 11 6 2 12 7 3 13] - [14 9 0 5 10 1 6 11 2 12 7 3 13 8 4] - [ 5 0 10 1 6 11 2 7 12 3 13 8 4 14 9] - [10 6 1 11 2 7 12 3 8 13 4 14 9 5 0] - ] + sage: from sage.combinat.designs.latin_squares import are_mutually_orthogonal_latin_squares + sage: from sage.combinat.designs.database import MOLS_15_4 + sage: MOLS = MOLS_15_4() + sage: print are_mutually_orthogonal_latin_squares(MOLS) + True + + The design is available from the general constructor:: + + sage: designs.mutually_orthogonal_latin_squares(15,4,availability=True) + True """ M = """ bcdefghijklmnoa bdgiknfcamehjlo bhealiofmdjgcnk blhcmdinejofakg @@ -340,65 +232,16 @@ def MOLS_18_3(): EXAMPLES:: - sage: designs.mutually_orthogonal_latin_squares(18,3) - [ - [ 1 6 4 9 7 10 12 14 3 2 13 0 17 8 11 15 5 16] - [ 4 2 7 5 1 8 11 13 15 17 3 14 10 0 9 12 16 6] - [16 5 3 8 6 2 9 12 14 7 0 4 15 11 10 1 13 17] - [15 17 6 4 9 7 3 1 13 0 8 10 5 16 12 11 2 14] - [14 16 0 7 5 1 8 4 2 15 10 9 11 6 17 13 12 3] - [ 3 15 17 10 8 6 2 9 5 4 16 11 1 12 7 0 14 13] - [ 6 4 16 0 11 9 7 3 1 14 5 17 12 2 13 8 10 15] - [ 2 7 5 17 10 12 1 8 4 16 15 6 0 13 3 14 9 11] - [ 5 3 8 6 0 11 13 2 9 12 17 16 7 10 14 4 15 1] - [11 13 1 16 2 14 6 15 0 10 12 7 3 17 8 5 4 9] - [10 12 14 2 17 3 15 7 16 1 11 13 8 4 0 9 6 5] - [17 11 13 15 3 0 4 16 8 6 2 12 14 9 5 10 1 7] - [ 9 0 12 14 16 4 10 5 17 8 7 3 13 15 1 6 11 2] - [ 0 1 10 13 15 17 5 11 6 3 9 8 4 14 16 2 7 12] - [ 7 10 2 11 14 16 0 6 12 13 4 1 9 5 15 17 3 8] - [13 8 11 3 12 15 17 10 7 9 14 5 2 1 6 16 0 4] - [ 8 14 9 12 4 13 16 0 11 5 1 15 6 3 2 7 17 10] - [12 9 15 1 13 5 14 17 10 11 6 2 16 7 4 3 8 0], - - [ 1 4 16 15 14 3 6 2 5 11 10 17 9 0 7 13 8 12] - [ 6 2 5 17 16 15 4 7 3 13 12 11 0 1 10 8 14 9] - [ 4 7 3 6 0 17 16 5 8 1 14 13 12 10 2 11 9 15] - [ 9 5 8 4 7 10 0 17 6 16 2 15 14 13 11 3 12 1] - [ 7 1 6 9 5 8 11 10 0 2 17 3 16 15 14 12 4 13] - [10 8 2 7 1 6 9 12 11 14 3 0 4 17 16 15 13 5] - [12 11 9 3 8 2 7 1 13 6 15 4 10 5 0 17 16 14] - [14 13 12 1 4 9 3 8 2 15 7 16 5 11 6 10 0 17] - [ 3 15 14 13 2 5 1 4 9 0 16 8 17 6 12 7 11 10] - [ 2 17 7 0 15 4 14 16 12 10 1 6 8 3 13 9 5 11] - [13 3 0 8 10 16 5 15 17 12 11 2 7 9 4 14 1 6] - [ 0 14 4 10 9 11 17 6 16 7 13 12 3 8 1 5 15 2] - [17 10 15 5 11 1 12 0 7 3 8 14 13 4 9 2 6 16] - [ 8 0 11 16 6 12 2 13 10 17 4 9 15 14 5 1 3 7] - [11 9 10 12 17 7 13 3 14 8 0 5 1 16 15 6 2 4] - [15 12 1 11 13 0 8 14 4 5 9 10 6 2 17 16 7 3] - [ 5 16 13 2 12 14 10 9 15 4 6 1 11 7 3 0 17 8] - [16 6 17 14 3 13 15 11 1 9 5 7 2 12 8 4 10 0], - - [ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 0] - [17 1 10 0 12 5 6 3 4 7 16 9 8 13 14 15 2 11] - [12 11 1 16 7 8 5 6 0 9 3 2 17 4 13 14 15 10] - [ 7 8 9 1 2 3 4 5 6 16 17 0 10 11 12 13 14 15] - [ 6 3 4 17 1 10 0 12 5 15 2 11 7 16 9 8 13 14] - [ 5 6 0 12 11 1 16 7 8 14 15 10 9 3 2 17 4 13] - [ 4 5 6 7 8 9 1 2 3 13 14 15 16 17 0 10 11 12] - [ 0 12 5 6 3 4 17 1 10 8 13 14 15 2 11 7 16 9] - [16 7 8 5 6 0 12 11 1 17 4 13 14 15 10 9 3 2] - [11 4 16 9 15 14 13 0 2 1 10 8 3 5 6 12 7 17] - [10 9 12 2 17 15 14 13 7 11 1 16 4 0 5 6 8 3] - [ 3 16 17 8 10 11 15 14 13 0 9 1 2 12 7 5 6 4] - [13 0 2 11 4 16 9 15 14 12 7 17 1 10 8 3 5 6] - [14 13 7 10 9 12 2 17 15 6 8 3 11 1 16 4 0 5] - [15 14 13 3 16 17 8 10 11 5 6 4 0 9 1 2 12 7] - [ 9 15 14 13 0 2 11 4 16 3 5 6 12 7 17 1 10 8] - [ 2 17 15 14 13 7 10 9 12 4 0 5 6 8 3 11 1 16] - [ 8 10 11 15 14 13 3 16 17 2 12 7 5 6 4 0 9 1] - ] + sage: from sage.combinat.designs.latin_squares import are_mutually_orthogonal_latin_squares + sage: from sage.combinat.designs.database import MOLS_18_3 + sage: MOLS = MOLS_18_3() + sage: print are_mutually_orthogonal_latin_squares(MOLS) + True + + The design is available from the general constructor:: + + sage: designs.mutually_orthogonal_latin_squares(18,3,availability=True) + True """ M = """ bgejhkmodcnarilpfq beqpodgcflkrjahnim bcdefghijklmnopqra From 7e77f908d612ebd0049298fa1023e6345f8bbc5e Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 4 May 2014 20:38:56 +0200 Subject: [PATCH 11/18] trac #16241: Broken doctests --- src/sage/combinat/designs/database.py | 8 ++--- src/sage/combinat/designs/latin_squares.py | 36 +++++++++---------- .../combinat/designs/orthogonal_arrays.py | 24 ++++++------- 3 files changed, 33 insertions(+), 35 deletions(-) diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index 408e421d40b..aef6c63f63a 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -121,7 +121,7 @@ def MOLS_10_2(): The design is available from the general constructor:: - sage: designs.mutually_orthogonal_latin_squares(10,2,availability=True) + sage: designs.mutually_orthogonal_latin_squares(10,2,existence=True) True """ from sage.matrix.constructor import Matrix @@ -163,7 +163,7 @@ def MOLS_14_4(): The design is available from the general constructor:: - sage: designs.mutually_orthogonal_latin_squares(14,4,availability=True) + sage: designs.mutually_orthogonal_latin_squares(14,4,existence=True) True """ M = """ @@ -201,7 +201,7 @@ def MOLS_15_4(): The design is available from the general constructor:: - sage: designs.mutually_orthogonal_latin_squares(15,4,availability=True) + sage: designs.mutually_orthogonal_latin_squares(15,4,existence=True) True """ M = """ @@ -240,7 +240,7 @@ def MOLS_18_3(): The design is available from the general constructor:: - sage: designs.mutually_orthogonal_latin_squares(18,3,availability=True) + sage: designs.mutually_orthogonal_latin_squares(18,3,existence=True) True """ M = """ diff --git a/src/sage/combinat/designs/latin_squares.py b/src/sage/combinat/designs/latin_squares.py index a74ac65429c..2386026853d 100644 --- a/src/sage/combinat/designs/latin_squares.py +++ b/src/sage/combinat/designs/latin_squares.py @@ -31,21 +31,21 @@ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ________________________________________________________________________________ - 0| +oo +oo 1 2 3 4 1 6 7 8 1 10 4 12 1 2 15 16 2 18 - 20| 3 2 1 22 3 24 2 26 3 28 2 30 31 3 2 4 3 36 2 3 - 40| 4 40 2 42 3 4 2 46 3 48 2 3 3 52 4 4 6 3 2 58 - 60| 4 60 2 6 63 4 2 66 4 4 6 70 7 72 2 3 3 6 2 78 - 80| 7 80 4 82 6 6 6 3 7 88 2 6 3 4 2 6 7 96 6 8 - 100| 6 100 6 102 7 3 4 106 4 108 2 6 7 112 2 7 4 8 2 6 - 120| 6 120 2 6 4 124 6 126 127 4 6 130 6 6 2 6 7 136 4 138 - 140| 6 7 6 10 8 7 6 7 4 148 6 150 7 8 4 4 4 156 2 6 - 160| 7 7 2 162 4 7 4 166 7 168 6 8 6 172 6 6 10 6 6 178 - 180| 6 180 6 6 7 8 6 10 6 6 2 190 7 192 6 7 6 196 6 198 - 200| 7 7 6 7 4 6 6 8 12 10 6 210 6 7 6 6 7 8 4 10 - 220| 6 12 6 222 7 8 6 226 6 228 6 6 7 232 6 7 6 6 2 238 - 240| 7 240 6 242 6 7 6 12 7 7 3 250 3 10 3 7 255 256 4 7 - 260| 4 8 4 262 7 8 6 10 6 268 6 270 15 7 3 10 6 276 6 8 - 280| 7 280 6 282 6 12 6 7 15 288 6 6 4 292 6 6 7 10 6 12 + 0| +oo +oo 1 2 3 4 1 6 7 8 2 10 4 12 4 4 15 16 3 18 + 20| 4 5 3 22 7 24 4 26 5 28 4 30 31 5 4 5 8 36 4 5 + 40| 7 40 5 42 5 6 4 46 8 48 6 5 5 52 5 6 7 3 2 58 + 60| 5 60 5 6 63 4 2 66 4 4 6 70 7 72 3 7 3 6 3 78 + 80| 9 80 8 82 6 6 6 3 7 88 3 6 3 4 3 6 7 96 6 8 + 100| 8 100 6 102 7 4 4 106 4 108 4 6 7 112 3 7 4 8 3 6 + 120| 6 120 4 6 4 124 6 126 127 4 6 130 6 6 4 6 7 136 4 138 + 140| 6 7 6 10 10 7 6 7 4 148 6 150 7 8 4 4 4 156 4 6 + 160| 7 7 4 162 4 7 4 166 7 168 6 8 6 172 6 6 10 6 6 178 + 180| 6 180 6 6 7 8 6 10 6 6 4 190 7 192 6 7 6 196 6 198 + 200| 7 7 6 7 4 6 6 8 12 10 10 210 6 7 6 7 7 8 4 10 + 220| 6 12 6 222 7 8 6 226 6 228 6 6 7 232 6 7 6 6 5 238 + 240| 7 240 6 242 6 7 6 12 7 7 5 250 6 10 4 7 255 256 4 7 + 260| 6 8 7 262 7 8 6 10 6 268 6 270 15 7 4 10 6 276 6 8 + 280| 7 280 6 282 6 12 6 7 15 288 6 6 5 292 6 6 7 10 6 12 TODO: @@ -238,7 +238,7 @@ def mutually_orthogonal_latin_squares(n,k, partitions = False, check = True, exi 7 sage: designs.mutually_orthogonal_latin_squares(6,3,existence=True) Unknown - sage: designs.mutually_orthogonal_latin_squares(10,2,availability=True) + sage: designs.mutually_orthogonal_latin_squares(10,2,existence=True) True sage: designs.mutually_orthogonal_latin_squares(10,2) [ @@ -271,14 +271,14 @@ def mutually_orthogonal_latin_squares(n,k, partitions = False, check = True, exi raise ValueError("There exist at most n-1 MOLS of size n.") elif n == 10 and k == 2: - if availability: + if existence: return True from database import MOLS_10_2 matrices = MOLS_10_2() elif n in MOLS_constructions and k <= MOLS_constructions[n][0]: - if availability: + if existence: return True _, construction = MOLS_constructions[n] diff --git a/src/sage/combinat/designs/orthogonal_arrays.py b/src/sage/combinat/designs/orthogonal_arrays.py index 09e77d94c8c..462c8c452ed 100644 --- a/src/sage/combinat/designs/orthogonal_arrays.py +++ b/src/sage/combinat/designs/orthogonal_arrays.py @@ -99,7 +99,7 @@ def transversal_design(k,n,check=True,existence=False, who_asked=tuple()): Some examples of the maximal number of transversal Sage is able to build:: sage: TD_4_10 = designs.transversal_design(4,10) - sage: designs.transversal_design(5,10,availability=True) + sage: designs.transversal_design(5,10,existence=True) Unknown For prime powers, there is an explicit construction which gives a @@ -121,8 +121,6 @@ def transversal_design(k,n,check=True,existence=False, who_asked=tuple()): sage: designs.transversal_design(11, 10, existence=True) False sage: designs.transversal_design(4, 10, existence=True) - Unknown - sage: designs.transversal_design(3, 10, existence=True) True sage: TD_6_20 = designs.transversal_design(6, 20) @@ -177,21 +175,21 @@ def transversal_design(k,n,check=True,existence=False, who_asked=tuple()): 7: ( 9, 9) 8: (10, 10) 9: (11, 11) - 10: ( 4, 11) + 10: ( 5, 11) 11: (13, 13) 12: ( 7, 14) 13: (15, 15) - 14: ( 4, 15) - 15: ( 5, 17) + 14: ( 7, 15) + 15: ( 7, 17) 16: (18, 18) 17: (19, 19) - 18: ( 5, 20) + 18: ( 6, 20) 19: (21, 21) - 20: ( 6, 22) - 21: ( 5, 22) - 22: ( 4, 23) + 20: ( 7, 22) + 21: ( 8, 22) + 22: ( 6, 23) 23: (25, 25) - 24: ( 6, 26) + 24: (10, 26) """ # Is k is None we find the largest available if k is None: @@ -655,7 +653,7 @@ def orthogonal_array(k,n,t=2,check=True,existence=False,who_asked=tuple()): ... EmptySetError: No Orthogonal Array exists when k>=n+t sage: designs.orthogonal_array(None,14,existence=True) - 3 + 6 sage: designs.orthogonal_array(16,1) [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] """ @@ -695,7 +693,7 @@ def orthogonal_array(k,n,t=2,check=True,existence=False,who_asked=tuple()): OA = map(list, product(range(n), repeat=k)) elif n in OA_constructions and k <= OA_constructions[n][0]: - if availability: + if existence: return True _, construction = OA_constructions[n] From e655b363ae30694fa5f36e6b0edbdddcfb95f0cf Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 4 May 2014 19:23:16 +0200 Subject: [PATCH 12/18] trac #16236: Five mutually orthogonal latin squares of order 12 --- src/sage/combinat/designs/database.py | 34 +++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index aef6c63f63a..b7df4a4cfba 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -48,10 +48,12 @@ :func:`OA(12,210) ` - :func:`two MOLS of order 10 `, + :func:`five MOLS of order 12 `, :func:`four MOLS of order 14 `, :func:`four MOLS of order 15 `, :func:`three MOLS of order 18 ` + **Dictionaries** The functions defined here are used by @@ -147,6 +149,37 @@ def MOLS_10_2(): [5,6,7,1,2,3,4,0,9,8], [7,1,2,3,4,5,6,9,8,0]])] +def MOLS_12_5(): + r""" + Returns 5 MOLS of order 12 + + These MOLS have been found by Brendan McKay. + + EXAMPLES:: + + sage: from sage.combinat.designs.latin_squares import are_mutually_orthogonal_latin_squares + sage: from sage.combinat.designs.latin_squares import MOLS_12_5 + sage: MOLS = MOLS_12_5() + sage: print are_mutually_orthogonal_latin_squares(MOLS) + True + """ + M = """ + abcdefghijkl abcdefghijkl abcdefghijkl abcdefghijkl abcdefghijkl + badcfehgjilk ghefklijcdab dcbahgfelkji jilkbadcfehg klijcdabghef + cdabghefklij efghijklabcd lkjidcbahgfe ijklabcdefgh fehgjilkbadc + dcbahgfelkji cdabghefklij ghefklijcdab badcfehgjilk hgfelkjidcba + ijklabcdefgh klijcdabghef efghijklabcd fehgjilkbadc jilkbadcfehg + jilkbadcfehg fehgjilkbadc hgfelkjidcba dcbahgfelkji lkjidcbahgfe + klijcdabghef hgfelkjidcba jilkbadcfehg cdabghefklij dcbahgfelkji + lkjidcbahgfe ijklabcdefgh badcfehgjilk efghijklabcd ghefklijcdab + efghijklabcd jilkbadcfehg fehgjilkbadc lkjidcbahgfe cdabghefklij + fehgjilkbadc dcbahgfelkji cdabghefklij ghefklijcdab badcfehgjilk + ghefklijcdab badcfehgjilk klijcdabghef hgfelkjidcba ijklabcdefgh + hgfelkjidcba lkjidcbahgfe ijklabcdefgh klijcdabghef efghijklabcd + """ + + return _MOLS_from_string(M,5) + def MOLS_14_4(): r""" Returns four MOLS of order 14 @@ -274,6 +307,7 @@ def MOLS_18_3(): MOLS_constructions = { 10 : (2, MOLS_10_2), + 12 : (5, MOLS_12_5), 14 : (4, MOLS_14_4), 15 : (4, MOLS_15_4), 18 : (3, MOLS_18_3) From a97434f3264d183056a50ac54fcb7a9912d31efc Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sun, 4 May 2014 20:55:02 +0200 Subject: [PATCH 13/18] trac #16286: more doc, more tests --- src/sage/combinat/designs/latin_squares.py | 33 ++++-- .../combinat/designs/orthogonal_arrays.py | 112 +++++++++++++++--- 2 files changed, 118 insertions(+), 27 deletions(-) diff --git a/src/sage/combinat/designs/latin_squares.py b/src/sage/combinat/designs/latin_squares.py index 4d1bdd52296..34509054f65 100644 --- a/src/sage/combinat/designs/latin_squares.py +++ b/src/sage/combinat/designs/latin_squares.py @@ -66,6 +66,7 @@ Functions --------- """ +from sage.categories.sets_cat import EmptySetError from sage.misc.unknown import Unknown def are_mutually_orthogonal_latin_squares(l, verbose=False): @@ -228,16 +229,30 @@ def mutually_orthogonal_latin_squares(n,k, partitions = False, check = True, exi [1, 5, 14, 18, 22], [3, 7, 11, 15, 24]]] - TESTS:: + What is the maximum number of MOLS of size 8 that Sage knows how to build?:: - sage: designs.mutually_orthogonal_latin_squares(5,5) - Traceback (most recent call last): - ... - ValueError: There exist at most n-1 MOLS of size n. - sage: designs.mutually_orthogonal_latin_squares(6,3,existence=True) - Unknown sage: designs.mutually_orthogonal_latin_squares(8,None,existence=True) 7 + + If you only want to know if Sage is able to build a given set of MOLS, just + set the argument ``existence`` to ``True``:: + + sage: designs.mutually_orthogonal_latin_squares(5, 5, existence=True) + False + sage: designs.mutually_orthogonal_latin_squares(6, 4, existence=True) + Unknown + + If you ask for such a MOLS then you will respecively get an informative + ``EmptySetError`` or ``NotImplementedError``:: + + sage: designs.mutually_orthogonal_latin_squares(5, 5) + Traceback (most recent call last): + ... + EmptySetError: There exist at most n-1 MOLS of size n. + sage: designs.mutually_orthogonal_latin_squares(6, 3) + Traceback (most recent call last): + ... + NotImplementedError: I don't know how to build these MOLS! """ from sage.combinat.designs.orthogonal_arrays import orthogonal_array from sage.matrix.constructor import Matrix @@ -251,7 +266,7 @@ def mutually_orthogonal_latin_squares(n,k, partitions = False, check = True, exi if k >= n: if existence: return False - raise ValueError("There exist at most n-1 MOLS of size n.") + raise EmptySetError("There exist at most n-1 MOLS of size n.") elif (orthogonal_array not in who_asked and orthogonal_array(k+2,n,existence=True,who_asked = who_asked+(mutually_orthogonal_latin_squares,)) is not Unknown): @@ -263,7 +278,7 @@ def mutually_orthogonal_latin_squares(n,k, partitions = False, check = True, exi else: if existence: return False - raise ValueError("These MOLS do not exist!") + raise EmptySetError("These MOLS do not exist!") OA = orthogonal_array(k+2,n,check=False, who_asked = who_asked+(mutually_orthogonal_latin_squares,)) OA.sort() # make sure that the first two columns are "11, 12, ..., 1n, 21, 22, ..." diff --git a/src/sage/combinat/designs/orthogonal_arrays.py b/src/sage/combinat/designs/orthogonal_arrays.py index 9cf1c43cada..bb24a77ebd5 100644 --- a/src/sage/combinat/designs/orthogonal_arrays.py +++ b/src/sage/combinat/designs/orthogonal_arrays.py @@ -73,15 +73,24 @@ def transversal_design(k,n,check=True,existence=False, who_asked=tuple()): the tuple of the other functions that were called before this one on the same input `k,n`. - .. NOTE:: + OUTPUT: + + The kind of output depends on the input: - This function returns transversal designs with - `V_1=\{0,\dots,n-1\},\dots,V_k=\{(k-1)n,\dots,kn-1\}`. + - if ``existence=False`` (the default) then the output is a list of lists + that represent a `TD(k,n)` with + `V_1=\{0,\dots,n-1\},\dots,V_k=\{(k-1)n,\dots,kn-1\}` + + - if ``existence=True`` and ``k`` is an integer, then the function returns a + troolean: either ``True``, ``Unknown`` or ``False`` + + - if ``existence=True`` and ``k=None`` then the output is the largest value + of ``k`` for which Sage knows how to compute a `TD(k,n)`. .. SEEALSO:: - :func:`orthogonal_array` -- a tranversal design is an orthogonal array - with `t=2`. + :func:`orthogonal_array` -- a tranversal design `TD(k,n)` is equivalent to an + orthogonal array `OA(k,n,2)`. EXAMPLES:: @@ -99,9 +108,10 @@ def transversal_design(k,n,check=True,existence=False, who_asked=tuple()): For prime powers, there is an explicit construction which gives a `TD(n+1,n)`:: - sage: for n in [2,3,5,7,9,11,13,16,17,19]: - ....: for k in xrange(2, n+2): - ....: assert designs.transversal_design(k,n,existence=True) is True + sage: designs.transversal_design(4, 3, existence=True) + True + sage: designs.transversal_design(674, 673, existence=True) + True For other values of ``n`` it depends:: @@ -124,6 +134,40 @@ def transversal_design(k,n,check=True,existence=False, who_asked=tuple()): sage: designs.transversal_design(6, 12, existence=True) True + If you ask for a transversal design that Sage is not able to build then an + ``EmptySetError`` or a ``NotImplementedError`` is raised:: + + sage: designs.transversal_design(47, 100) + Traceback (most recent call last): + ... + NotImplementedError: I don't know how to build this Transversal Design! + sage: designs.transversal_design(55, 54) + Traceback (most recent call last): + ... + EmptySetError: There exists no TD(55, 54)! + + Those two errors correspond respectively to the cases where Sage answer + ``Unknown`` or ``False`` when the parameter ``existence`` is set to + ``True``: + + sage: designs.transversal_design(47, 100, existence=True) + Unknown + sage: designs.transversal_design(55, 54, existence=True) + False + + If for a given `n` you want to know the largest `k` for which Sage is able + to build a `TD(k,n)` just call the function with `k` set to `None` and + `existence` set to `True` as follows:: + + sage: designs.transversal_design(None, 6, existence=True) + 3 + sage: designs.transversal_design(None, 20, existence=True) + 5 + sage: designs.transversal_design(None, 30, existence=True) + 4 + sage: designs.transversal_design(None, 120, existence=True) + 8 + TESTS: Obtained through Wilson's decomposition:: @@ -138,9 +182,12 @@ def transversal_design(k,n,check=True,existence=False, who_asked=tuple()): For small values of the parameter ``n`` we check the coherence of the function :func:`transversal_design`:: - sage: designs.transversal_design = designs.transversal_design sage: for n in xrange(2,25): # long time -- 15 secs - ....: i = designs.transversal_design(None, n, existence=True) + 1 + ....: i = 2 + ....: while designs.transversal_design(i, n, existence=True) is True: + ....: i += 1 + ....: _ = designs.transversal_design(i-1, n) + ....: assert designs.transversal_design(None, n, existence=True) == i - 1 ....: j = i ....: while designs.transversal_design(j, n, existence=True) is Unknown: ....: try: @@ -600,7 +647,7 @@ def orthogonal_array(k,n,t=2,check=True,existence=False,who_asked=tuple()): .. NOTE:: When ``k=None`` and ``existence=True`` the function returns an - integer, i.e. the largest `k` such that we can build a `OA(k,n)`. + integer, i.e. the largest `k` such that we can build a `TD(k,n)`. - ``who_asked`` (internal use only) -- because of the equivalence between OA/TD/MOLS, each of the three constructors calls the others. We must keep @@ -608,8 +655,18 @@ def orthogonal_array(k,n,t=2,check=True,existence=False,who_asked=tuple()): the tuple of the other functions that were called before this one on the same input `k,n`. - For more information on orthogonal arrays, see - :wikipedia:`Orthogonal_array`. + OUTPUT: + + The kind of output depends on the input: + + - if ``existence=False`` (the default) then the output is a list of lists + that represent an orthogonal array with parameters ``k`` and ``n`` + + - if ``existence=True`` and ``k`` is an integer, then the function returns a + troolean: either ``True``, ``Unknown`` or ``False`` + + - if ``existence=True`` and ``k=None`` then the output is the largest value + of ``k`` for which Sage knows how to compute a `TD(k,n)`. .. NOTE:: @@ -625,6 +682,9 @@ def orthogonal_array(k,n,t=2,check=True,existence=False,who_asked=tuple()): EXAMPLES:: + sage: designs.orthogonal_array(3,2) + [[0, 0, 0], [0, 1, 1], [1, 0, 1], [1, 1, 0]] + sage: designs.orthogonal_array(5,5) [[0, 0, 0, 0, 0], [0, 1, 2, 3, 4], [0, 2, 4, 1, 3], [0, 3, 1, 4, 2], [0, 4, 3, 2, 1], [1, 0, 4, 3, 2], @@ -636,16 +696,32 @@ def orthogonal_array(k,n,t=2,check=True,existence=False,who_asked=tuple()): [4, 1, 3, 0, 2], [4, 2, 0, 3, 1], [4, 3, 2, 1, 0], [4, 4, 4, 4, 4]] - TESTS:: + What is the largest value of `k` for which Sage knows how to compute a + `OA(k,14,2)`?:: + + sage: designs.orthogonal_array(None,14,existence=True) + 3 + + If you ask for an orthogonal array that does not exist, then the function + either raise an `EmptySetError` (if it knows that such an orthogonal array + does not exist) or a `NotImplementedError`:: - sage: designs.orthogonal_array(3,2) - [[0, 0, 0], [0, 1, 1], [1, 0, 1], [1, 1, 0]] sage: designs.orthogonal_array(4,2) Traceback (most recent call last): ... EmptySetError: No Orthogonal Array exists when k>=n+t - sage: designs.orthogonal_array(None,14,existence=True) - 3 + sage: designs.orthogonal_array(12,20) + Traceback (most recent call last): + ... + NotImplementedError: I don't know how to build this orthogonal array! + + Note that these errors correspond respectively to the answers ``False`` and + ``Unknown`` when the parameter ``existence`` is set to ``True``:: + + sage: designs.orthogonal_array(4,2,existence=True) + False + sage: designs.orthogonal_array(12,20,existence=True) + Unknown """ from sage.rings.finite_rings.constructor import FiniteField from latin_squares import mutually_orthogonal_latin_squares From daa3835d28a5c0c48c1f0874db85757c8923be48 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sun, 4 May 2014 22:36:19 +0200 Subject: [PATCH 14/18] trac #16235: case n=1 + doc The case of n=1 in TD/OA/MOLS was not handled properly. So I changed the thing and do the appropriate doctests. Consequence: we have a TD(4,10). --- src/sage/combinat/designs/latin_squares.py | 32 +++++++- .../combinat/designs/orthogonal_arrays.py | 78 ++++++++++++++----- 2 files changed, 87 insertions(+), 23 deletions(-) diff --git a/src/sage/combinat/designs/latin_squares.py b/src/sage/combinat/designs/latin_squares.py index 69f9d33d66c..900bf524cc2 100644 --- a/src/sage/combinat/designs/latin_squares.py +++ b/src/sage/combinat/designs/latin_squares.py @@ -248,28 +248,52 @@ def mutually_orthogonal_latin_squares(n,k, partitions = False, check = True, exi sage: designs.mutually_orthogonal_latin_squares(5, 5) Traceback (most recent call last): ... - EmptySetError: There exist at most n-1 MOLS of size n. + EmptySetError: There exist at most n-1 MOLS of size n if n>=2. sage: designs.mutually_orthogonal_latin_squares(6, 3) Traceback (most recent call last): ... NotImplementedError: I don't know how to build these MOLS! + + TESTS: + + The special case `n=1`:: + + sage: designs.mutually_orthogonal_latin_squares(1, 3) + [[0], [0], [0]] + sage: designs.mutually_orthogonal_latin_squares(1, None, existence=True) + +Infinity + sage: designs.mutually_orthogonal_latin_squares(1, None) + Traceback (most recent call last): + ... + ValueError: there are no bound on k when n=1. """ from sage.combinat.designs.orthogonal_arrays import orthogonal_array from sage.matrix.constructor import Matrix # Is k is None we find the largest available if k is None: + if n == 1: + if existence: + from sage.rings.infinity import Infinity + return Infinity + raise ValueError("there are no bound on k when n=1.") + k = orthogonal_array(None,n,existence=True) - 2 if existence: return k - if k >= n: + if n == 1: + if existence: + return True + matrices = [Matrix([[0]])]*k + + elif k >= n: if existence: return False - raise EmptySetError("There exist at most n-1 MOLS of size n.") + raise EmptySetError("There exist at most n-1 MOLS of size n if n>=2.") elif n == 10 and k == 2: - if availability: + if existence: return True from database import MOLS_10_2 diff --git a/src/sage/combinat/designs/orthogonal_arrays.py b/src/sage/combinat/designs/orthogonal_arrays.py index 601ee16f087..433cb43c953 100644 --- a/src/sage/combinat/designs/orthogonal_arrays.py +++ b/src/sage/combinat/designs/orthogonal_arrays.py @@ -105,12 +105,6 @@ def transversal_design(k,n,check=True,existence=False, who_asked=tuple()): [4, 6, 13, 15, 22], [4, 7, 10, 18, 21], [4, 8, 12, 16, 20], [4, 9, 14, 19, 24]] - Some examples of the maximal number of transversal Sage is able to build:: - - sage: TD_4_10 = designs.transversal_design(4,10) - sage: designs.transversal_design(5,10,availability=True) - Unknown - For prime powers, there is an explicit construction which gives a `TD(n+1,n)`:: @@ -130,9 +124,9 @@ def transversal_design(k,n,check=True,existence=False, who_asked=tuple()): sage: designs.transversal_design(11, 10, existence=True) False - sage: designs.transversal_design(4, 10, existence=True) + sage: designs.transversal_design(5, 10, existence=True) Unknown - sage: designs.transversal_design(3, 10, existence=True) + sage: designs.transversal_design(4, 10, existence=True) True sage: designs.transversal_design(7, 20, existence=True) @@ -171,14 +165,19 @@ def transversal_design(k,n,check=True,existence=False, who_asked=tuple()): sage: designs.transversal_design(None, 6, existence=True) 3 sage: designs.transversal_design(None, 20, existence=True) - 5 + 6 sage: designs.transversal_design(None, 30, existence=True) - 4 + 6 sage: designs.transversal_design(None, 120, existence=True) 8 TESTS: + The case when `n=1`:: + + sage: designs.transversal_design(5,1) + [[0, 1, 2, 3, 4]] + Obtained through Wilson's decomposition:: sage: _ = designs.transversal_design(4,38) @@ -223,7 +222,7 @@ def transversal_design(k,n,check=True,existence=False, who_asked=tuple()): 7: ( 9, 9) 8: (10, 10) 9: (11, 11) - 10: ( 4, 11) + 10: ( 5, 11) 11: (13, 13) 12: ( 7, 14) 13: (15, 15) @@ -233,24 +232,46 @@ def transversal_design(k,n,check=True,existence=False, who_asked=tuple()): 17: (19, 19) 18: ( 5, 20) 19: (21, 21) - 20: ( 6, 22) - 21: ( 5, 22) - 22: ( 4, 23) + 20: ( 7, 22) + 21: ( 8, 22) + 22: ( 6, 23) 23: (25, 25) - 24: ( 6, 26) + 24: (10, 26) + + The special case `n=1`:: + + sage: designs.transversal_design(3, 1) + [[0, 1, 2]] + sage: designs.transversal_design(None, 1, existence=True) + +Infinity + sage: designs.transversal_design(None, 1) + Traceback (most recent call last): + ... + ValueError: there are no bound on k when n=1. """ # Is k is None we find the largest available if k is None: + if n == 1: + if existence: + from sage.rings.infinity import Infinity + return Infinity + raise ValueError("there are no bound on k when n=1.") + k = orthogonal_array(None,n,existence=True) if existence: return k - if k >= n+2: + if n == 1: + if existence: + return True + TD = [range(k)] + + elif k >= n+2: if existence: return False - raise EmptySetError("No Transversal Design exists when k>=n+2") + raise EmptySetError("No Transversal Design exists when k>=n+2 if n>=2") - if n == 12 and k <= 6: + elif n == 12 and k <= 6: if existence: return True TD = [l[:k] for l in TD6_12()] @@ -731,6 +752,19 @@ def orthogonal_array(k,n,t=2,check=True,existence=False,who_asked=tuple()): False sage: designs.orthogonal_array(12,20,existence=True) Unknown + + TESTS: + + The special case `n=1`:: + + sage: designs.orthogonal_array(3,1) + [[0, 0, 0]] + sage: designs.orthogonal_array(None,1,existence=True) + +Infinity + sage: designs.orthogonal_array(None,1) + Traceback (most recent call last): + ... + ValueError: there are no bound on k when n=1. """ from sage.rings.finite_rings.constructor import FiniteField from latin_squares import mutually_orthogonal_latin_squares @@ -739,6 +773,12 @@ def orthogonal_array(k,n,t=2,check=True,existence=False,who_asked=tuple()): # If k is set to None we find the largest value available if k is None: + if n == 1: + if existence: + from sage.rings.infinity import Infinity + return Infinity + raise ValueError("there are no bound on k when n=1.") + for k in range(1,n+2): if not orthogonal_array(k+1,n,existence=True): break @@ -768,7 +808,7 @@ def orthogonal_array(k,n,t=2,check=True,existence=False,who_asked=tuple()): OA = map(list, product(range(n), repeat=k)) elif n in OA_constructions and k <= OA_constructions[n][0]: - if availability: + if existence: return True _, construction = OA_constructions[n] From 31a53f25033170db44455633cb03a812ae68e625 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sun, 4 May 2014 22:41:46 +0200 Subject: [PATCH 15/18] trac #16235: update the MOLS table --- src/sage/combinat/designs/latin_squares.py | 30 +++++++++++----------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/sage/combinat/designs/latin_squares.py b/src/sage/combinat/designs/latin_squares.py index 900bf524cc2..8b929a774f7 100644 --- a/src/sage/combinat/designs/latin_squares.py +++ b/src/sage/combinat/designs/latin_squares.py @@ -31,21 +31,21 @@ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ________________________________________________________________________________ - 0| +oo +oo 1 2 3 4 1 6 7 8 1 10 4 12 1 2 15 16 2 18 - 20| 3 2 1 22 3 24 2 26 3 28 2 30 31 3 2 4 3 36 2 3 - 40| 4 40 2 42 3 4 2 46 3 48 2 3 3 52 4 4 6 3 2 58 - 60| 4 60 2 6 63 4 2 66 4 4 6 70 7 72 2 3 3 6 2 78 - 80| 7 80 4 82 6 6 6 3 7 88 2 6 3 4 2 6 7 96 6 8 - 100| 6 100 6 102 7 3 4 106 4 108 2 6 7 112 2 7 4 8 2 6 - 120| 6 120 2 6 4 124 6 126 127 4 6 130 6 6 2 6 7 136 4 138 - 140| 6 7 6 10 8 7 6 7 4 148 6 150 7 8 4 4 4 156 2 6 - 160| 7 7 2 162 4 7 4 166 7 168 6 8 6 172 6 6 10 6 6 178 - 180| 6 180 6 6 7 8 6 10 6 6 2 190 7 192 6 7 6 196 6 198 - 200| 7 7 6 7 4 6 6 8 12 10 6 210 6 7 6 6 7 8 4 10 - 220| 6 12 6 222 7 8 6 226 6 228 6 6 7 232 6 7 6 6 2 238 - 240| 7 240 6 242 6 7 6 12 7 7 3 250 3 10 3 7 255 256 4 7 - 260| 4 8 4 262 7 8 6 10 6 268 6 270 15 7 3 10 6 276 6 8 - 280| 7 280 6 282 6 12 6 7 15 288 6 6 4 292 6 6 7 10 6 12 + 0| +oo +oo 1 2 3 4 1 6 7 8 2 10 4 12 1 2 15 16 2 18 + 20| 4 5 3 22 7 24 4 26 5 28 4 30 31 5 4 5 8 36 4 5 + 40| 7 40 5 42 5 6 4 46 8 48 6 5 5 52 5 6 7 3 2 58 + 60| 5 60 5 6 63 4 2 66 4 4 6 70 7 72 2 7 3 6 2 78 + 80| 9 80 8 82 6 6 6 3 7 88 2 6 3 4 2 6 7 96 6 8 + 100| 8 100 6 102 7 4 4 106 4 108 3 6 7 112 3 7 4 8 3 6 + 120| 6 120 3 6 4 124 6 126 127 4 6 130 6 6 3 6 7 136 4 138 + 140| 6 7 6 10 10 7 6 7 4 148 6 150 7 8 4 4 4 156 4 6 + 160| 7 7 3 162 4 7 4 166 7 168 6 8 6 172 6 6 10 6 6 178 + 180| 6 180 6 6 7 8 6 10 6 6 4 190 7 192 6 7 6 196 6 198 + 200| 7 7 6 7 4 6 6 8 12 10 10 210 6 7 6 7 7 8 4 10 + 220| 6 12 6 222 7 8 6 226 6 228 6 6 7 232 6 7 6 6 5 238 + 240| 7 240 6 242 6 7 6 12 7 7 5 250 6 10 4 7 255 256 4 7 + 260| 6 8 7 262 7 8 6 10 6 268 6 270 15 7 4 10 6 276 6 8 + 280| 7 280 6 282 6 12 6 7 15 288 6 6 5 292 6 6 7 10 6 12 TODO: From c212bf9ebd406d65b3417b7cc9d20022c0dd8b3e Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 5 May 2014 14:25:08 +0200 Subject: [PATCH 16/18] trac #16241: Broken doctests --- src/sage/combinat/designs/latin_squares.py | 19 +++++++++++++++++++ .../combinat/designs/orthogonal_arrays.py | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/designs/latin_squares.py b/src/sage/combinat/designs/latin_squares.py index 3e8669e3ec5..43c3a390974 100644 --- a/src/sage/combinat/designs/latin_squares.py +++ b/src/sage/combinat/designs/latin_squares.py @@ -28,6 +28,25 @@ ....: print "\n"+'%3s'%str(i)+"|", ....: print '%3s'%str(designs.mutually_orthogonal_latin_squares(i,None,existence=True) if i>1 else "+oo"), sage: MOLS_table(15) # long time + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 + ________________________________________________________________________________ + + 0| +oo +oo 1 2 3 4 1 6 7 8 2 10 4 12 4 4 15 16 3 18 + 20| 4 5 3 22 7 24 4 26 5 28 4 30 31 5 4 5 8 36 4 5 + 40| 7 40 5 42 5 6 4 46 8 48 6 5 5 52 5 6 7 3 2 58 + 60| 5 60 5 6 63 4 2 66 4 4 6 70 7 72 3 7 3 6 3 78 + 80| 9 80 8 82 6 6 6 3 7 88 3 6 3 4 3 6 7 96 6 8 + 100| 8 100 6 102 7 4 4 106 4 108 4 6 7 112 3 7 4 8 3 6 + 120| 6 120 4 6 4 124 6 126 127 4 6 130 6 6 4 6 7 136 4 138 + 140| 6 7 6 10 10 7 6 7 4 148 6 150 7 8 4 4 4 156 4 6 + 160| 7 7 4 162 4 7 4 166 7 168 6 8 6 172 6 6 10 6 6 178 + 180| 6 180 6 6 7 8 6 10 6 6 4 190 7 192 6 7 6 196 6 198 + 200| 7 7 6 7 4 6 6 8 12 10 10 210 6 7 6 7 7 8 4 10 + 220| 6 12 6 222 7 8 6 226 6 228 6 6 7 232 6 7 6 6 5 238 + 240| 7 240 6 242 6 7 6 12 7 7 5 250 6 10 4 7 255 256 4 7 + 260| 6 8 7 262 7 8 6 10 6 268 6 270 15 7 4 10 6 276 6 8 + 280| 7 280 6 282 6 12 6 7 15 288 6 6 5 292 6 6 7 10 6 12 + TODO: diff --git a/src/sage/combinat/designs/orthogonal_arrays.py b/src/sage/combinat/designs/orthogonal_arrays.py index 7f9a3e91e9e..1c4b7f33a71 100644 --- a/src/sage/combinat/designs/orthogonal_arrays.py +++ b/src/sage/combinat/designs/orthogonal_arrays.py @@ -736,7 +736,7 @@ def orthogonal_array(k,n,t=2,check=True,existence=False,who_asked=tuple()): `OA(k,14,2)`?:: sage: designs.orthogonal_array(None,14,existence=True) - 3 + 6 If you ask for an orthogonal array that does not exist, then the function either raise an `EmptySetError` (if it knows that such an orthogonal array From f5339fabafd4d2b3ffe56b1e68bb68d75ec19902 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 5 May 2014 14:30:51 +0200 Subject: [PATCH 17/18] trac #16236: Broken doctests --- src/sage/combinat/designs/database.py | 2 +- src/sage/combinat/designs/latin_squares.py | 17 ++++++++--------- src/sage/combinat/designs/orthogonal_arrays.py | 6 +++--- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index b7df4a4cfba..e79e3086280 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -158,7 +158,7 @@ def MOLS_12_5(): EXAMPLES:: sage: from sage.combinat.designs.latin_squares import are_mutually_orthogonal_latin_squares - sage: from sage.combinat.designs.latin_squares import MOLS_12_5 + sage: from sage.combinat.designs.database import MOLS_12_5 sage: MOLS = MOLS_12_5() sage: print are_mutually_orthogonal_latin_squares(MOLS) True diff --git a/src/sage/combinat/designs/latin_squares.py b/src/sage/combinat/designs/latin_squares.py index 43c3a390974..00f0109a52e 100644 --- a/src/sage/combinat/designs/latin_squares.py +++ b/src/sage/combinat/designs/latin_squares.py @@ -31,23 +31,22 @@ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ________________________________________________________________________________ - 0| +oo +oo 1 2 3 4 1 6 7 8 2 10 4 12 4 4 15 16 3 18 + 0| +oo +oo 1 2 3 4 1 6 7 8 2 10 5 12 4 4 15 16 3 18 20| 4 5 3 22 7 24 4 26 5 28 4 30 31 5 4 5 8 36 4 5 40| 7 40 5 42 5 6 4 46 8 48 6 5 5 52 5 6 7 3 2 58 60| 5 60 5 6 63 4 2 66 4 4 6 70 7 72 3 7 3 6 3 78 - 80| 9 80 8 82 6 6 6 3 7 88 3 6 3 4 3 6 7 96 6 8 - 100| 8 100 6 102 7 4 4 106 4 108 4 6 7 112 3 7 4 8 3 6 - 120| 6 120 4 6 4 124 6 126 127 4 6 130 6 6 4 6 7 136 4 138 - 140| 6 7 6 10 10 7 6 7 4 148 6 150 7 8 4 4 4 156 4 6 - 160| 7 7 4 162 4 7 4 166 7 168 6 8 6 172 6 6 10 6 6 178 + 80| 9 80 8 82 6 6 6 3 7 88 3 6 4 4 3 6 7 96 6 8 + 100| 8 100 6 102 7 4 5 106 5 108 4 6 7 112 3 7 5 8 3 6 + 120| 6 120 4 6 5 124 6 126 127 5 6 130 6 6 4 6 7 136 4 138 + 140| 6 7 6 10 10 7 6 7 5 148 6 150 7 8 5 5 5 156 4 6 + 160| 7 7 4 162 5 7 4 166 7 168 6 8 6 172 6 6 10 6 6 178 180| 6 180 6 6 7 8 6 10 6 6 4 190 7 192 6 7 6 196 6 198 - 200| 7 7 6 7 4 6 6 8 12 10 10 210 6 7 6 7 7 8 4 10 + 200| 7 7 6 7 5 6 6 8 12 10 10 210 6 7 6 7 7 8 5 10 220| 6 12 6 222 7 8 6 226 6 228 6 6 7 232 6 7 6 6 5 238 240| 7 240 6 242 6 7 6 12 7 7 5 250 6 10 4 7 255 256 4 7 - 260| 6 8 7 262 7 8 6 10 6 268 6 270 15 7 4 10 6 276 6 8 + 260| 6 8 7 262 7 8 6 10 6 268 6 270 15 7 5 10 6 276 6 8 280| 7 280 6 282 6 12 6 7 15 288 6 6 5 292 6 6 7 10 6 12 - TODO: * Look at [ColDin01]_. diff --git a/src/sage/combinat/designs/orthogonal_arrays.py b/src/sage/combinat/designs/orthogonal_arrays.py index 1c4b7f33a71..8410a197db0 100644 --- a/src/sage/combinat/designs/orthogonal_arrays.py +++ b/src/sage/combinat/designs/orthogonal_arrays.py @@ -137,9 +137,9 @@ def transversal_design(k,n,check=True,existence=False, who_asked=tuple()): sage: designs.transversal_design(7, 20, existence=True) Unknown - sage: designs.transversal_design(6, 12, existence=True) - True sage: designs.transversal_design(7, 12, existence=True) + True + sage: designs.transversal_design(8, 12, existence=True) Unknown @@ -230,7 +230,7 @@ def transversal_design(k,n,check=True,existence=False, who_asked=tuple()): 9: (11, 11) 10: ( 5, 11) 11: (13, 13) - 12: ( 7, 14) + 12: ( 8, 14) 13: (15, 15) 14: ( 7, 15) 15: ( 7, 17) From 9fb0f625c1b2dd63c11cc1e44beb61e69c832acf Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 5 May 2014 18:47:02 +0200 Subject: [PATCH 18/18] trac #16241: useless if condition in MOLS constructor --- src/sage/combinat/designs/latin_squares.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/sage/combinat/designs/latin_squares.py b/src/sage/combinat/designs/latin_squares.py index 43c3a390974..041108fda62 100644 --- a/src/sage/combinat/designs/latin_squares.py +++ b/src/sage/combinat/designs/latin_squares.py @@ -310,13 +310,6 @@ def mutually_orthogonal_latin_squares(n,k, partitions = False, check = True, exi return False raise EmptySetError("There exist at most n-1 MOLS of size n if n>=2.") - elif n == 10 and k == 2: - if existence: - return True - - from database import MOLS_10_2 - matrices = MOLS_10_2() - elif n in MOLS_constructions and k <= MOLS_constructions[n][0]: if existence: return True