diff --git a/src/sage/combinat/designs/bibd.py b/src/sage/combinat/designs/bibd.py index 238254209e1..4bf9450280f 100644 --- a/src/sage/combinat/designs/bibd.py +++ b/src/sage/combinat/designs/bibd.py @@ -141,9 +141,9 @@ def balanced_incomplete_block_design(v,k,existence=False,use_LJCR=False): For `k > 5` there are currently very few constructions:: sage: [v for v in xrange(150) if designs.balanced_incomplete_block_design(v,6,existence=True) is True] - [1, 6, 31, 91] + [1, 6, 31, 81, 91, 121] sage: [v for v in xrange(150) if designs.balanced_incomplete_block_design(v,6,existence=True) is Unknown] - [51, 61, 66, 76, 81, 96, 106, 111, 121, 126, 136, 141] + [51, 61, 66, 76, 96, 106, 111, 126, 136, 141] But we know some inexistence results:: @@ -466,6 +466,8 @@ def BIBD_from_TD(v,k,existence=False): return BIBD + + def BIBD_from_difference_family(G, D, check=True): r""" Return the BIBD associated to the difference family ``D`` on the group ``G``. @@ -484,7 +486,7 @@ def BIBD_from_difference_family(G, D, check=True): - ``G`` - a finite additive Abelian group - - ``D`` - a difference family on ``G``. + - ``D`` - a difference family on ``G`` (short blocks are allowed). - ``check`` - whether or not we check the output (default: ``True``) @@ -519,14 +521,18 @@ def BIBD_from_difference_family(G, D, check=True): [19, 20, 2, 12, 14], [20, 0, 3, 13, 15]] """ - r = {e:i for i,e in enumerate(G)} - bibd = [[r[G(x)+g] for x in d] for d in D for g in r] + from difference_family import orbit_representatives, block_stabilizer + bibd = [] + p_to_i = {g:i for i,g in enumerate(G)} + for b in D: + b = map(G,b) + for g in orbit_representatives(block_stabilizer(G,b),G): + bibd.append([p_to_i[G(i)+g] for i in b]) if check: assert _check_pbd(bibd, G.cardinality(), [len(D[0])]) return bibd - ################ # (v,4,1)-BIBD # ################ diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index 00be99bd24b..0cc9294b2bb 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -3344,254 +3344,297 @@ def _test_Vmt_constructions(): """ pass -def CDF_21_5_1(): - r""" - A cyclic `(21,5,1)`-difference family. - - From the examples VI.16.16 of [DesignHandbook]_. - - EXAMPLES:: - - sage: from sage.combinat.designs.database import CDF_21_5_1 - sage: from sage.combinat.designs.difference_family import is_difference_family - sage: G, D = CDF_21_5_1() - sage: is_difference_family(G,D,21,5,1) - True - - The difference family is available from the constructor:: - - sage: _ = designs.difference_family(21,5,1) - """ - D = [[0,1,4,14,16]] - from sage.rings.finite_rings.integer_mod_ring import Zmod - return Zmod(21), D - -def ADF_5x5_4_1(): - r""" - An Abelian difference family on `(\ZZ / 5 \ZZ)^2`. - - This is the example 7.26 of [Stinson2004]_. - - EXAMPLES:: - - sage: from sage.combinat.designs.database import ADF_5x5_4_1 - sage: from sage.combinat.designs.difference_family import is_difference_family - sage: G,D = ADF_5x5_4_1() - sage: is_difference_family(G,D,25,4,1) - True - """ - D = [[(0,0),(0,1),(1,0),(2,2)],[(0,0),(0,2),(2,0),(4,4)]] - from sage.rings.finite_rings.integer_mod_ring import Zmod - from sage.categories.cartesian_product import cartesian_product - return cartesian_product([Zmod(5),Zmod(5)]), D - -def CDF_37_4_1(): - r""" - A cyclic `(37,4,1)`-difference family. - - It appears as example 7.28 in [Stinson2004]_ and in the examples VI.16.14 of [DesignHandbook]_. - - EXAMPLES:: - - sage: from sage.combinat.designs.database import CDF_37_4_1 - sage: from sage.combinat.designs.difference_family import is_difference_family - sage: G, D = CDF_37_4_1() - sage: is_difference_family(G,D,37,4,1) - True - - The difference family is available from the constructor:: - - sage: _ = designs.difference_family(37,4,1) - - """ - D = [[0,1,3,24],[0,4,26,32],[0,10,18,30]] - from sage.rings.finite_rings.integer_mod_ring import Zmod - return Zmod(37), D - -def CDF_81_5_1(): - r""" - A cyclic `(81,5,1)`-difference family. - - From the examples VI.16.16 of [DesignHandbook]_. - - EXAMPLES:: - - sage: from sage.combinat.designs.database import CDF_81_5_1 - sage: from sage.combinat.designs.difference_family import is_difference_family - sage: G, D = CDF_81_5_1() - sage: is_difference_family(G,D,81,5,1) - True - - The difference family is available from the constructor:: - - sage: _ = designs.difference_family(81,5,1) - """ - D = [[0,1,5,12,26],[0,2,10,40,64],[0,3,18,47,53],[0,9,32,48,68]] - from sage.rings.finite_rings.integer_mod_ring import Zmod - return Zmod(81), D - -def CDF_91_6_1(): - r""" - A cyclic `(91,6,1)`-difference family. - - From the examples VI.16.18 of [DesignHandbook]_. - - EXAMPLES:: - - sage: from sage.combinat.designs.database import CDF_91_6_1 - sage: from sage.combinat.designs.difference_family import is_difference_family - sage: G, D = CDF_91_6_1() - sage: is_difference_family(G,D,91,6,1) - True - - The difference family is available from the constructor:: - sage: _ = designs.difference_family(91,6,1) - """ - D = [[0,1,3,7,25,38], [0,16,21,36,48,62], [0,30,40,63,74,82]] - from sage.rings.finite_rings.integer_mod_ring import Zmod - return Zmod(91), D - -def CDF_121_5_1(): - r""" - A cyclic `(121,5,1)`-difference family. - - From the examples VI.16.16 of [DesignHandbook]_. - - EXAMPLES:: - - sage: from sage.combinat.designs.database import CDF_121_5_1 - sage: from sage.combinat.designs.difference_family import is_difference_family - sage: G, D = CDF_121_5_1() - sage: is_difference_family(G,D,121,5,1) - True - - The difference family is available from the constructor:: - - sage: _ = designs.difference_family(121,5,1) - """ - D = [[0,14,26,51,60],[0,15,31,55,59],[0,10,23,52,58],[0,3,36,56,57], - [0,7,18,45,50],[0,8,30,47,49]] - from sage.rings.finite_rings.integer_mod_ring import Zmod - return Zmod(121), D - -def CDF_141_5_1(): - r""" - A cyclic `(141,5,1)`-difference family. - - From the examples VI.16.16 of [DesignHandbook]_. - - EXAMPLES:: - - sage: from sage.combinat.designs.database import CDF_141_5_1 - sage: from sage.combinat.designs.difference_family import is_difference_family - sage: G, D = CDF_141_5_1() - sage: is_difference_family(G,D,141,5,1) - True - - The difference family is available from the constructor:: - - sage: _ = designs.difference_family(141,5,1) - """ - D = [[0,33,60,92,97], [0,3,45,88,110], [0,18,39,68,139], - [0,12,67,75,113], [0,1,15,84,94], [0,7,11,24,30], - [0,36,90,116,125]] - from sage.rings.finite_rings.integer_mod_ring import Zmod - return Zmod(141), D +DF = { +############## +# lambda = 1 # +############## +((15,),3,1):[[0,1,4],[0,2,9],['S',0,5,10]], +((21,),3,1):[[0,1,3],[0,4,12],[0,5,11],['S',0,7,14]], +((21,),5,1):[[0,1,4,14,16]], +((25,),3,1):[[0,1,3],[0,4,11],[0,5,13],[0,6,15]], +((5,5),4,1):[[(0,0),(0,1),(1,0),(2,2)],[(0,0),(0,2),(2,0),(4,4)]], +((27,),3,1):[[0,1,3],[0,4,11],[0,5,15],[0,6,14],['S',0,9,18]], +((33,),3,1):[[0,1,3],[0,4,10],[0,5,18],[0,7,19],[0,8,17],['S',0,11,22]], +((37,),4,1):[[0,1,3,24],[0,4,26,32],[0,10,18,30]], +((39,),3,1):[[0,1,3],[0,4,18],[0,5,27],[0,6,16],[0,7,15],[0,9,20],['S',0,13,26]], +((45,),3,1):[[0,1,3],[0,4,10],[0,5,28],[0,7,34],[0,8,32],[0,9,29],[0,12,26],['S',0,15,30]], +((49,),3,1):[[0,1,3],[0,4,9],[0,6,17],[0,7,23],[0,8,30],[0,10,31],[0,12,36],[0,14,34]], +((51,),3,1):[[0,1,3],[0,4,9],[0,6,25],[0,7,35],[0,8,22],[0,10,21],[0,12,27],[0,13,31],['S',0,17,34]], +((55,),3,1):[[0,1,3],[0,4,9],[0,6,16],[0,7,32],[0,8,29],[0,11,42],[0,12,27],[0,14,36],[0,17,37]], +((57,),3,1):[[0,1,3],[0,4,9],[0,6,13],[0,8,26],[0,10,33],[0,11,32],[0,12,40],[0,14,41],[0,15,35],['S',0,19,38]], +((63,),3,1):[[0,1,3],[0,4,9],[0,6,13],[0,8,25],[0,10,41],[0,11,44],[0,12,36],[0,14,37],[0,15,43],[0,16,34],['S',0,21,42]], +((69,),3,1):[[0,1,3],[0,4,9],[0,6,13],[0,8,24],[0,10,38],[0,11,47],[0,12,32],[0,14,40],[0,15,50],[0,17,42],[0,18,39],['S',0,23,46]], +((75,),3,1):[[0,1,67],[0,2,47],[0,3,41],[0,4,69],[0,5,68],[0,11,55],[0,13,61],[0,15,33],[0,16,52],[0,17,43],[0,19,40],[0,22,51],['S',0,25,50]], +((81,),3,1): + [[0,1,39],[0,2,58],[0,3,34],[0,4,21],[0,5,67],[0,6,15],[0,7,36], + [0,8,59],[0,10,63],[0,11,37],[0,12,61],[0,13,48],[0,16,40],['S',0,27,54]], +((40,),4,1):[[0,1,4,13],[0,2,7,24],[0,6,14,25],['S',0,10,20,30]], +((49,),4,1):[[0,1,3,8,],[0,4,18,29],[0,6,21,33],[0,9,19,32]], +((52,),4,1):[[0,1,3,7,],[0,5,19,35],[0,8,20,31],[0,9,24,34],['S',0,13,26,39]], +((64,),4,1):[[0,1,3,7,],[0,5,18,47],[0,8,33,44],[0,9,19,43],[0,12,26,49],['S',0,16,32,48]], +((76,),4,1):[[0,1,7,22],[0,2,11,45],[0,3,59,71],[0,4,32,50],[0,10,37,51],[0,13,36,60],['S',0,19,38,57]], +((81,),5,1):[[0,1,5,12,26],[0,2,10,40,64],[0,3,18,47,53],[0,9,32,48,68]], +((85,),4,1):[[0,2,41,42],[0,17,32,38],[0,18,27,37],[0,13,29,36],[0,11,31,35],[0,12,26,34,],[0,5,30,33]], +((65,),5,1):[[0,1,3,31,45],[0,4,10,19,57],[0,5,16,41,48],['S',0,13,26,39,52]], +((91,),6,1):[[0,1,3,7,25,38], [0,16,21,36,48,62], [0,30,40,63,74,82]], +((121,),5,1):[[0,14,26,51,60],[0,15,31,55,59],[0,10,23,52,58],[0,3,36,56,57],[0,7,18,45,50],[0,8,30,47,49]], +((141,),5,1):[[0,33,60,92,97],[0,3,45,88,110],[0,18,39,68,139],[0,12,67,75,113],[0,1,15,84,94],[0,7,11,24,30],[0,36,90,116,125]], +((161,),5,1):[[0,19,34,73,80],[0,16,44,71,79],[0,12,33,74,78],[0,13,30,72,77],[0,11,36,67,76],[0,18,32,69,75],[0,10,48,68,70],[0,3,29,52,53]], +((201,),5,1): + [[0,1,45,98,100],[0,3,32,65,89],[0,4,54,70,75],[0,6,49,69,91],[0,7,58,81,95], + [0,8,34,72,90],[0,9,36,77,96],[0,10,35,83,94],[0,12,40,79,92],[0,15,46,76,93]], +((217,),7,1): + [[0,1,37,67,88,92,149],[0,15,18,65,78,121,137],[0,8,53,79,85,102,107], + [0,11,86,100,120,144,190],[0,29,64,165,198,205,207],['S',0,31,62,93,124,155,186]], +((221,),5,1): + [[0,1,24,61,116],[0,3,46,65,113],[0,4,73,89,130],[0,5,77,122,124],[0,6,39,50,118], + [0,7,66,81,94],[0,8,38,64,139],[0,9,29,80,107],[0,10,35,93,135],[0,12,34,52,88],[0,14,31,63,84]], +((3,3,5),5,1): + [[(0,1,0),(0,2,0),(1,0,2),(2,0,2),(0,0,1)], + [(2,1,0),(1,2,0),(2,2,2),(1,1,2),(0,0,1)], + ['S', (0,0,0),(0,0,1),(0,0,2),(0,0,3),(0,0,4)]], +((11,11),6,1): + [[(0,0),(0,3),(0,4),(1,1),(1,7),(4,6)], + [(0,0),(0,2),(2,5),(4,7),(6,4),(8,0)], + [(0,0),(1,5),(2,0),(4,1),(6,0),(7,2)], + [(0,0),(1,0),(3,9),(4,8),(6,1),(9,5)]], +# the following one is lemma 2.2 in Abel "Some new BIBDs with block size 7" +((7,37),7,1): + [['S',(0,0),(1,0),(2,0),(3,0),(4,0),(5,0),(6,0)], + [(0,0),(0,1),(0,6),(1,4),(2,19),(3,25),(6,26)], + [(0,0),(0,10),(0,23),(2,3),(4,5),(5,1),(6,28)], + [(0,0),(0,8),(0,26),(1,13),(3,10),(4,30),(5,21)], + [(0,0),(0,4),(1,25),(1,34),(2,33),(2,35),(4,10)], + [(0,0),(0,3),(1,26),(2,7),(2,28),(4,17),(4,34)], + [(0,0),(0,30),(1,7),(1,22),(2,1),(4,21),(4,33)]], +((7,5,5),7,1): + [['S',(0,0,0),(1,0,0),(2,0,0),(3,0,0),(4,0,0),(5,0,0),(6,0,0)], + [(0,0,0),(1,1,3),(1,4,2),(2,2,2),(2,3,3),(4,2,0),(4,3,0)], + [(0,0,0),(1,3,4),(1,2,1),(2,2,3),(2,3,2),(4,0,2),(4,0,3)], + [(0,0,0),(1,1,2),(1,4,3),(2,1,1),(2,4,4),(4,0,1),(4,0,4)], + [(0,0,0),(1,3,1),(1,2,4),(2,4,1),(2,1,4),(4,1,0),(4,4,0)]], + +############## +# lambda = 2 # +############## +((16,),3,2):[[0,1,2],[0,2,8],[0,3,7],[0,4,7],[0,5,10]], +((28,),3,2):[[0,1,12],[0,2,11],[0,2,12],[0,3,7],[0,3,13],[0,4,9],[0,5,13],[0,6,7],[0,6,14]], +((40,),3,2):[[0,1,4],[0,1,16],[0,2,7],[0,2,9],[0,3,17],[0,4,17],[0,5,19],[0,6,16],[0,6,18],[0,8,18],[0,8,19],[0,9,20],[0,12,25]], +((19,),4,2):[[0,1,3,12],[0,1,5,13],[0,4,6,9]], +((21,),4,3):[[0,2,3,7],[0,3,5,9],[0,1,7,11],[0,2,8,11],[0,1,9,14]], +((22,),4,2):[[0,4,16,17],[0,12,14,21],[0,14,16,19],['S',0,4,11,15]], +((31,),4,2):[[0,1,8,11],[0,1,13,17],[0,2,11,14],[0,5,7,13],[0,5,9,15]], +((34,),4,2):[[0,1,22,24],[0,1,19,25],[0,2,6,29],[0,4,7,20],[0,5,8,20],['S',0,8,17,25]], +((43,),4,2):[[0,1,6,36],[0,3,18,22],[0,9,11,23],[0,10,12,26],[0,26,27,33],[0,13,35,38],[0,19,28,39,]], +((46,),4,2):[[0,2,7,10],[0,4,19,32],[0,10,34,35],[0,5,8,24],[0,26,30,39],[0,17,26,32],[0,28,34,45],['S',0,2,23,25]], +((31,),5,2):[[0,1,3,7,15],[0,3,9,14,21],[0,4,5,13,15,]], +((35,),5,2):[[0,2,8,12,13],[0,3,18,22,27],[0,17,23,32,33],['S',0,7,14,21,28],['S',0,7,14,21,28]], +((51,),5,2):[[0,1,14,31,35],[0,1,9,23,33],[0,11,16,18,42],[0,7,13,36,39],[0,4,10,12,15]], +((71,),5,2):[[1,5,25,54,57],[3,4,15,20,29],[9,12,16,45,60],[27,36,38,48,64],[2,10,37,43,50],[6,8,30,40,58],[18,19,24,32,49]], +((46,),6,2):[[0,1,3,11,31,35],[0,1,4,10,23,29],[0,2,7,15,32,41]], +((61,),6,2):[[12,15,28,34,35,59],[1,13,18,47,51,53],[8,10,11,21,29,43],[16,20,25,32,40,50]], +((43,),7,2):[[0,1,11,19,31,38,40],[0,2,10,16,25,38,42]], +((3,3,17),9,2): + [['S', (0,0,0),(0,1,0),(0,2,0),(1,0,0),(1,1,0),(1,2,0),(2,0,0),(2,1,0),(2,2,0)], + ['S', (0,0,0),(0,1,0),(0,2,0),(1,0,0),(1,1,0),(1,2,0),(2,0,0),(2,1,0),(2,2,0)], + [(0,0,0),(0,1,1),(0,1,16),(0,2,4),(0,2,13),(1,0,3),(1,0,14),(2,0,5),(2,0,12)], + [(0,0,0),(0,1,2),(0,1,15),(0,2,8),(0,2,9),(1,0,6),(1,0,11),(2,0,10),(2,0,7)], + [(0,0,0),(0,1,3),(0,1,14),(0,2,12),(0,2,5),(1,0,9),(1,0,8),(2,0,15),(2,0,2)], + [(0,0,0),(0,1,6),(0,1,11),(0,2,7),(0,2,10),(1,0,1),(1,0,16),(2,0,13),(2,0,4)]], +((85,),7,2):[[0,1,11,20,32,35,39],[0,2,6,16,29,50,65],[0,3,9,27,55,72,80],[0,5,7,30,47,48,59]], +((85,),8,2):[[24,31,39,50,67,68,70,82],[20,49,51,55,56,60,72,81],[9,19,29,37,43,56,59,81]], +((181,),10, 2): + [[1,7,40,42,51,59,113,125,135,151], + [19,22,31,35,36,64,74,133,154,156], + [10,15,34,47,58,65,83,87,161,164], + [12,18,32,52,77,78,142,157,165,172]], +((64,),7,2):[[0,1,2,4,7,28,52],[0,4,9,21,31,39,53],[0,6,15,23,34,41,54]], +((5,15),5,2): + [[(0,0),(1,10),(1,8),(4,1),(4,2)], + [(0,0),(2,5),(2,10),(3,7),(3,13)], + [(0,0),(1,10),(1,2),(4,4),(4,8)], + [(0,0),(2,5),(2,10),(3,14),(3,11)], + [(0,0),(1,4),(1,5),(4,1),(4,8)], + [(0,0),(1,1),(1,5),(4,4),(4,2)], + [(0,0),(2,7),(2,13),(3,1),(3,4)], + ['S',(0,0),(1,0),(2,0),(3,0),(4,0)], + ['S',(0,0),(1,0),(2,0),(3,0),(4,0)]], + +############## +# lambda = 3 # +############## + +((21,),6,3):[[0,2,10,15,19,20],[0,3,7,9,10,16]], +((41,),6,3):[[0,1,10,16,18,37],[0,6,14,17,19,26],[0,2,20,32,33,36],[0,11,12,28,34,38]], +((51,),6,3):[[15,17,18,27,34,48],[3,17,30,34,42,45],[9,17,24,33,34,39],[3,25,41,43,44,48],[3,5,25,29,43,48]], +((61,),6,3):[[0,1,9,20,58,34],[0,2,7,18,40,55],[0,4,14,19,36,49],[0,8,11,28,37,38],[0,13,15,16,22,56],[0,26,30,32,44,51]], +((29,),7,3):[[1,7,16,20,23,24,25],[2,3,11,14,17,19,21]], +((43,),7,3):[[1,4,11,16,21,35,41],[3,5,12,19,20,33,37],[9,13,14,15,17,25,36]], +((57,),7,3):[[0,1,11,12,15,35,53],[0,7,17,20,27,29,48],[0,5,18,26,32,49,51],[0,2,6,9,14,41,42]], +((61,),10,3):[[1,4,18,20,32,35,36,41,42,54],[11,13,14,21,23,28,34,39,43,47]], +((71,),7,3):[[1,20,30,32,37,45,48],[2,3,19,25,40,60,64],[4,6,9,38,49,50,57],[5,8,12,18,27,29,43],[10,15,16,24,36,54,58]], +((85,),7,3): + [[0,7,23,27,28,31,71], + [0,12,22,41,61,74,79], + [0,6,11,13,38,42,77], + [0,1,7,16,19,27,49], + [0,9,26,39,54,56,71], + [0,2,3,12,37,53,63]], +((97,),9,3):[[1,2,25,35,46,58,61,70,90],[3,4,8,38,43,50,69,86,87],[6,12,16,32,53,55,57,75,82],[9,18,24,26,31,34,37,48,64]], +((49,),9,3):[[0,1,3,5,9,14,19,25,37],[0,2,12,13,16,19,34,41,42]], +((11,11),10,3): + [[(0,1),(0,3),(0,4),(0,5),(0,9),(1,8),(3,2),(4,10),(5,7),(9,6)], + [(1,2),(3,6),(4,8),(5,10),(9,7),(10,2),(8,6),(7,8),(6,10),(2,7)], + [(1,7),(3,10),(4,6),(5,2),(9,8),(1,4),(3,1),(4,5),(5,9),(9,3)], + [(10,10),(8,8),(7,7),(6,6),(2,2),(1,0),(3,0),(4,0),(5,0),(9,0)]], + +############### +# lambda = 4 # +############### + +((22,),7,4):[[0,2,6,8,9,10,13],[0,3,5,6,12,13,17]], +((29,),8,4):[[0,1,7,16,20,23,24,25],[0,2,3,11,14,17,19,21]], +((71,),8,4):[[0,1,20,30,32,37,45,48],[0,2,3,19,25,40,60,64],[0,4,6,9,38,49,50,57],[0,5,8,12,18,27,29,43],[0,10,15,16,24,36,54,58]], +((43,),8,4):[[0,1,4,11,16,21,35,41],[0,3,5,12,19,20,33,37],[0,9,13,14,15,17,25,36]], +((46,),10,4):[[3,7,13,16,23,24,25,28,30,42],[2,10,12,18,25,34,40,43,44,45]], +((55,),9,4):[[0,4,21,25,26,42,45,53,54],[0,6,8,25,37,39,45,48,52],[2,5,6,13,15,20,25,39,45]], +((67,),12,4):[[1,8,23,25,28,29,31,37,47,54,55,64],[3,20,25,32,36,39,44,45,54,55,57,59]], + +############## +# lambda = 5 # +############## + +((13,),5,5):[[0,1,2,4,8],[0,1,3,6,12],[0,2,5,6,10]], +((17,),5,5):[[0,1,4,13,16],[0,3,5,12,14],[0,2,8,9,15],[0,6,7,10,11]], +((21,),6,5):[[0,2,6,12,15,16],[0,3,6,7,11,19],[0,7,15,16,17,18],['S',0,2,7,9,14,16]], +((22,),6,5):[[0,1,2,5,10,13],[0,1,5,6,8,15],[0,2,3,6,16,18],['S',0,2,6,11,13,17]], +((28,),6,5):[[0,4,7,8,16,21],[5,7,8,9,14,20],[7,12,14,16,17,25],[1,4,7,13,14,24],['S',2,4,8,16,18,22]], +((33,),5,5):[[0,2,3,7,25],[0,3,13,14,29],[0,4,5,12,13],[0,2,12,16,26],[0,3,12,20,31],[3,9,12,15,27],[0,8,13,14,31],[0,2,7,13,29]], +((33,),6,5):[[0,3,12,17,18,28],[0,2,3,16,28,29],[0,16,20,26,28,30],[0,2,3,12,16,27],[0,6,20,21,28,30],['S',0,4,11,15,22,26]], +((37,),10, 5):[[0,1,7,9,10,12,16,26,33,34],[0,2,14,15,18,20,24,29,31,32]], +((39,),6,5):[[0,3,4,17,19,32],[0,1,5,12,30,36],[0,3,8,9,25,27],[0,7,10,12,17,21],[0,16,18,19,27,35],[0,2,18,27,28,33],['S',0,6,13,19,26,32]], +((45,),11, 5):[[1,3,7,10,22,25,30,35,37,38,44],[0,2,3,14,22,26,27,28,31,32,38]], +((46,),10, 5):[[0,4,6,11,12,15,24,25,28,42],[0,2,5,7,8,9,14,24,34,35],['S',0,2,12,32,40,23,25,35,9,17]], +((55,),10, 5):[[0,5,11,15,20,22,25,33,44,45],[3,7,8,10,31,37,39,45,46,49],[3,7,8,10,31,37,39,45,46,49]], +((67,),11, 5):[[1,9,14,15,22,24,25,40,59,62,64],[2,13,18,28,30,44,48,50,51,57,61],[4,21,26,29,33,35,36,47,55,56,60]], +((73,),10,5):[[0,1,2,4,8,16,32,37,55,64],[0,5,7,10,14,20,28,39,40,56],[0,25,27,35,49,50,54,61,67,70],[0,11,15,21,22,30,42,44,47,60]], + +############### +# lambda >= 6 # +############### + +((11,),4,6):[[0,1,8,9],[0,2,5,7],[0,1,4,5],[0,2,3,5],[0,4,5,9]], +((15,),4,6):[[0,1,2,3],[0,2,4,6],[0,4,8,12],[0,8,1,9],[3,6,9,12],[0,1,5,10],[0,2,5,10]], +((15,),5,6):[[0,1,2,3,6],[0,2,4,7,8],[0,2,4,9,10],[0,3,6,10,11],['S',0,3,6,9,12]], +((29,),8,6):[[0,5,10,11,12,13,16,20],[0,8,10,12,17,22,23,26],[0,4,5,11,13,23,25,26]], +((46,),10,6):[[0,2,11,13,21,22,30,33,34,40],[0,2,6,7,22,23,28,32,35,38],[0,2,4,7,8,9,12,23,26,41]], +((53,),13,6):[[1,10,13,15,16,24,28,36,42,44,46,47,49],[2,3,19,20,26,30,31,32,35,39,41,45,48]], +((67,),12,6):[[0,1,9,14,15,22,24,25,40,59,62,64],[0,2,13,18,28,30,44,48,50,51,57,61],[0,4,21,26,29,33,35,36,47,55,56,60]], + +((53,),14,7):[[0,1,10,13,15,16,24,28,36,42,44,46,47,49],[0,2,3,19,20,26,30,31,32,35,39,41,45,48]], +((61,),15,7):[[0,1,3,4,8,10,13,22,30,35,44,45,46,50,58],[0,1,3,5,13,18,29,34,35,37,41,43,44,51,55]], +((5,5),7,7): + [[(0,0),(0,1),(0,4),(1,1),(1,2),(4,3),(4,4)], + [(0,0),(1,0),(1,3),(2,3),(3,2),(4,0),(4,2)], + [(0,0),(0,2),(0,3),(2,2),(2,4),(3,1),(3,3)], + [(0,0),(1,4),(2,0),(2,1),(3,0),(3,4),(4,1)]], + +((22,),8,8):[[0,1,5,7,13,17,20,21],[0,2,7,11,13,14,16,17],[0,3,4,12,14,15,17,21]], +((34,),12,8):[[0,5,9,14,15,17,20,25,26,27,28,30],[0,6,7,10,13,17,18,20,22,24,25,26]], + +((21,),10,9):[[0,1,2,3,4,7,8,11,14,16],[0,6,7,9,11,12,15,16,17,19]], + +((34,),12,10):[[0,2,3,4,8,9,11,13,14,24,27,30],[0,2,6,7,8,11,13,14,22,25,26,32],['S',0,2,10,18,22,32,17,19,27,1,5,15]], +((43,),15,10):[[1,3,6,13,18,21,22,25,26,27,33,35,36,38,40],[9,10,11,13,16,17,19,23,26,27,28,33,35,38,39]], +((7,7),21,10): + [['S',(0,1),(0,2),(0,4),(1,1),(1,2),(1,4),(2,1),(2,2),(2,4),(3,1),(3,2), + (3,4),(4,1),(4,2),(4,4),(5,1),(5,2),(5,4),(6,1),(6,2),(6,4)], + [(1,0),(1,1),(1,2),(1,4),(2,0),(2,1),(2,2),(2,4),(4,0),(4,1),(4,2), + (4,4),(3,3),(3,5),(3,6),(5,3),(5,5),(5,6),(6,3),(6,5),(6,6)]], + +((22,),8,12): + [[1,2,3,5,6,9,15,18], + [1,2,3,5,8,9,10,15], + [1,3,4,9,13,18,19,21], + ['S',2,4,6,12,13,15,17,1], + ['S',2,4,8,12,13,15,19,1], + ['S',2,4,8,16,13,15,19,5]], + +((21,),8,14):[[0,9,10,13,14,15,18,19],[0,1,4,7,9,15,16,18],[0,1,2,4,6,14,15,16],[0,1,3,4,8,14,16,18],[0,1,4,9,11,12,14,16]], +} -def CDF_161_5_1(): +def DF_from_database(v, k, l, short_blocks=True, check=False): r""" - A cyclic `(161,5,1)`-difference family. - - From the examples VI.16.16 of [DesignHandbook]_. + Return a ``(v,k,l)``-difference family from the database or ``False`` if + there is none. - EXAMPLES:: + INPUT: - sage: from sage.combinat.designs.database import CDF_161_5_1 - sage: from sage.combinat.designs.difference_family import is_difference_family - sage: G, D = CDF_161_5_1() - sage: is_difference_family(G,D,161,5,1) - True + - ``v``, ``k``, ``l`` -- the parameters of the difference family - The difference family is available from the constructor:: + - ``short_blocks`` -- whether short blocks are allowed (default to ``True``) - sage: _ = designs.difference_family(161,5,1) - """ - D = [[0,19,34,73,80], [0,16,44,71,79], [0,12,33,74,78], - [0,13,30,72,77], [0,11,36,67,76], [0,18,32,69,75], - [0,10,48,68,70], [0,3,29,52,53]] - from sage.rings.finite_rings.integer_mod_ring import Zmod - return Zmod(161), D - -def CDF_201_5_1(): - r""" - A cyclic `(201,5,1)`-difference family. - - From the examples VI.16.16 of [DesignHandbook]_. + - ``check`` -- mainly for debug purpose (default to ``False``) EXAMPLES:: - sage: from sage.combinat.designs.database import CDF_201_5_1 - sage: from sage.combinat.designs.difference_family import is_difference_family - sage: G, D = CDF_201_5_1() - sage: is_difference_family(G,D,201,5,1) - True - - The difference family is available from the constructor:: + sage: from sage.combinat.designs.database import DF_from_database + sage: DF_from_database(15,3,1) + (Ring of integers modulo 15, [[0, 1, 4], [0, 2, 9], [0, 5, 10]]) + sage: DF_from_database(15,3,1,short_blocks=False) + False - sage: _ = designs.difference_family(201,5,1) + sage: from sage.combinat.designs.database import DF, DF_from_database + sage: for v,k,l in DF: + ....: df = DF_from_database(v,k,l,check=True) """ - D = [[0,1,45,98,100], [0,3,32,65,89], [0,4,54,70,75], - [0,6,49,69,91], [0,7,58,81,95], [0,8,34,72,90], - [0,9,36,77,96], [0,10,35,83,94], [0,12,40,79,92], - [0,15,46,76,93]] + from sage.misc.misc_c import prod + from sage.rings.integer import Integer + from difference_family import block_stabilizer, is_difference_family from sage.rings.finite_rings.integer_mod_ring import Zmod - return Zmod(201), D - -def CDF_221_5_1(): - r""" - A cyclic `(221,5,1)`-difference family. - - From the examples VI.16.16 of [DesignHandbook]_. + from sage.categories.cartesian_product import cartesian_product - EXAMPLES:: + if isinstance(v,(int,Integer)): + for (vv,kk,ll) in DF: + if kk == k and ll == l and prod(vv) == v: + if not short_blocks and any(b[0] == 'S' for b in DF[vv,k,l]): + continue + v = vv + break + else: + return False + elif (v,k,l) not in DF or (not short_blocks and any(b[0] == 'S' for b in DF[v,k,l])): + return False + + if len(v) == 1: + A = Zmod(v[0]) + else: + A = cartesian_product([Zmod(i) for i in v]) + + blocks = DF[v,k,l] + + df = [] + short_blocks = False + for b in blocks: + if b[0] == 'S': + short_blocks = True + b = [A(i) for i in b[1:]] + if check and len(block_stabilizer(A,b)) == 1: + print "short block expected but get full with ({},{},{})\n {}".format(v,k,l,b) + else: + b = [A(i) for i in b] + if check and len(block_stabilizer(A,b)) > 1: + print "full block expected but get short with ({},{},{})\n {}".format(v,k,l,b) - sage: from sage.combinat.designs.database import CDF_221_5_1 - sage: from sage.combinat.designs.difference_family import is_difference_family - sage: G, D = CDF_221_5_1() - sage: is_difference_family(G,D,221,5,1) - True + df.append(b) - The difference family is available from the constructor:: + if check and not is_difference_family(A, df, v=prod(v), k=k, l=l, short_blocks=short_blocks): + is_difference_family(A,df,v=prod(v),k=k,l=l,short_blocks=short_blocks,verbose=True) + raise ValueError("ERROR: pb with ({},{},{})".format(v,k,l)) - sage: _ = designs.difference_family(221,5,1) - """ - D = [[0,1,24,61,116], [0,3,46,65,113], [0,4,73,89,130], - [0,5,77,122,124], [0,6,39,50,118], [0,7,66,81,94], - [0,8,38,64,139], [0,9,29,80,107], [0,10,35,93,135], - [0,12,34,52,88], [0,14,31,63,84]] - from sage.rings.finite_rings.integer_mod_ring import Zmod - return Zmod(221), D + return A,df -# Index of the (right now cyclic or Abelian) difference families constructions -# -# Associates to triple (v,k,lambda) a function that return a -# (n,k,lambda)-difference family. -# -# This dictionary is used by designs.difference_family - -DF_constructions = { - (21,5,1): CDF_21_5_1, - (25,4,1): ADF_5x5_4_1, - (37,4,1): CDF_37_4_1, - (81,5,1): CDF_81_5_1, - (91,6,1): CDF_91_6_1, - (121,5,1): CDF_121_5_1, - (141,5,1): CDF_141_5_1, - (161,5,1): CDF_161_5_1, - (201,5,1): CDF_201_5_1, - (221,5,1): CDF_221_5_1, -} def RBIBD_120_8_1(): r""" diff --git a/src/sage/combinat/designs/difference_family.py b/src/sage/combinat/designs/difference_family.py index 17736d94a05..386ebcbbfe7 100644 --- a/src/sage/combinat/designs/difference_family.py +++ b/src/sage/combinat/designs/difference_family.py @@ -46,18 +46,115 @@ def group_law(G): else: raise ValueError("%s does not seem to be a group"%G) -def is_difference_family(G, D, v=None, k=None, l=None, verbose=False): +def block_stabilizer(G, B): r""" - Check wether ``D`` forms a difference family in ``G``. + Compute the stabilizer of the block ``B`` in the group additive group ``G``. + + EXAMPLES:: + + sage: from sage.combinat.designs.difference_family import block_stabilizer + + sage: Z8 = Zmod(8) + sage: block_stabilizer(Z8, [Z8(0),Z8(2),Z8(4),Z8(6)]) + [0, 2, 4, 6] + sage: block_stabilizer(Z8, [Z8(0),Z8(2)]) + [0] + + sage: C = cartesian_product([Zmod(4),Zmod(3)]) + sage: block_stabilizer(C, [C((0,0)),C((2,0)),C((0,1)),C((2,1))]) + [(0, 0), (2, 0)] + + sage: b = map(Zmod(45),[1, 3, 7, 10, 22, 25, 30, 35, 37, 38, 44]) + sage: block_stabilizer(Zmod(45),b) + [0] + """ + b0 = -B[0] + S = [] + for b in B: + # fun: if we replace +(-b) with -b it completely fails!! + if all(b + b0 + c in B for c in B): + S.append(b+b0) + return S + +def orbit_representatives(G,B): + r""" + Return the orbits of the additive group ``G`` that intersects the set ``B``. + + EXAMPLES:: + + sage: from sage.combinat.designs.difference_family import ( + ....: block_stabilizer, orbit_representatives) + + sage: Z8 = Zmod(8) + sage: b = map(Z8, [0,2,4,6]) + sage: S = block_stabilizer(Z8,b) + sage: orbit_representatives(S, b) + [0] + + sage: b = map(Z8, [0,1,4,5]) + sage: S = block_stabilizer(Z8,b) + sage: orbit_representatives(S, b) + [0, 1] + + sage: C = cartesian_product([Zmod(4),Zmod(3)]) + sage: b = [C((0,0)),C((2,0)),C((0,1)),C((2,1))] + sage: S = block_stabilizer(C,b) + sage: orbit_representatives(S, b) + [(0, 1), (2, 0)] + """ + if len(G) == 1: + return B + + o = [] + B = set(B) + while B: + b = B.pop() + o.append(b) + for g in G: + if not g.is_zero(): + B.remove(g+b) + return o + +def partial_differences(G, B): + r""" + Compute the partial differences of the block ``B``. + + EXAMPLES:: + + sage: from sage.combinat.designs.difference_family import partial_differences + + sage: b = map(Zmod(8),[0,2,4,6]) + sage: partial_differences(Zmod(8),b) + [2, 4, 6] + + sage: b = map(Zmod(8),[0,1,4,5]) + sage: partial_differences(Zmod(8),b) + [1, 3, 4, 4, 5, 7] + + sage: b = [1, 3, 7, 10, 22, 25, 30, 35, 37, 38, 44] + sage: b = map(Zmod(45),b) + sage: d = partial_differences(Zmod(45),b) + sage: len(d) + 110 + """ + stab = block_stabilizer(G,B) + o = orbit_representatives(stab,B) + return sorted(b + (-c) + g for b in o for c in o for g in stab if b+g != c) + +def is_difference_family(G, D, v=None, k=None, l=None, short_blocks=True, verbose=False): + r""" + Check wether ``D`` forms a difference family in the additive Abelian group ``G``. INPUT: - - ``G`` - Abelian group of cardinality ``v`` + - ``G`` - Additive Abelian group of cardinality ``v`` - ``D`` - a set of ``k``-subsets of ``G`` - ``v``, ``k`` and ``l`` - optional parameters of the difference family + - ``short_blocks`` - whether short blocks are allowed (default is ``True``) + - ``verbose`` - whether to print additional information .. SEEALSO:: @@ -75,7 +172,16 @@ def is_difference_family(G, D, v=None, k=None, l=None, verbose=False): sage: G = Zmod(41) sage: D = [[0,1,4,11,29],[0,2,8,17,21]] sage: is_difference_family(G, D, verbose=True) - the element 28 in G is obtained more than 1 times + Too less: + 5 is obtained 0 times in blocks [] + 14 is obtained 0 times in blocks [] + 27 is obtained 0 times in blocks [] + 36 is obtained 0 times in blocks [] + Too much: + 4 is obtained 2 times in blocks [0, 1] + 13 is obtained 2 times in blocks [0, 1] + 28 is obtained 2 times in blocks [0, 1] + 37 is obtained 2 times in blocks [0, 1] False sage: D = [[0,1,4,11,29],[0,2,8,17,22]] sage: is_difference_family(G, D) @@ -95,19 +201,45 @@ def is_difference_family(G, D, v=None, k=None, l=None, verbose=False): sage: is_difference_family(G, D) True - The function also supports multiplicative groups (non necessarily Abelian):: + An example with a short block (i.e. considering restricted difference when a + block has a non trivial stabilizer):: + + sage: G = Zmod(15) + sage: D = [[0,1,4],[0,2,9],[0,5,10]] + sage: is_difference_family(G,D,verbose=True) + It is a (15,3,1)-difference family + True + sage: is_difference_family(G,D,short_blocks=False,verbose=True) + bk(k-1) is not 0 mod (v-1) + False + + The function also supports multiplicative groups (non necessarily Abelian). + In that case, the argument ``short_blocks`` must be set to ``False``:: sage: G = DihedralGroup(8) sage: x,y = G.gens() sage: D1 = [[1,x,x^4], [1,x^2, y*x], [1,x^5,y], [1,x^6,y*x^2], [1,x^7,y*x^5]] - sage: is_difference_family(G, D1, 16, 3, 2) + sage: is_difference_family(G, D1, 16, 3, 2, short_blocks=False) True + sage: is_difference_family(G, D1, 16, 3, 2) + Traceback (most recent call last): + ... + ValueError: short blocks are meaningful only for Abelian group that we assume + to be additive """ + import operator + + identity, mul, inv = group_law(G) + if short_blocks and not (mul is operator.add or inv is operator.neg): + raise ValueError("short blocks are meaningful only for Abelian group that we assume to be additive") + + Glist = list(G) + if v is None: - v = G.cardinality() + v = len(Glist) else: v = int(v) - if G.cardinality() != v: + if len(Glist) != v: if verbose: print "G must have cardinality v (=%d)"%v return False @@ -119,52 +251,112 @@ def is_difference_family(G, D, v=None, k=None, l=None, verbose=False): b = len(D) - if any(len(d) != k for d in D): - if verbose: - print "each element of D must have cardinality k (=%d)"%k - return False - - if l is None: - if (b*k*(k-1)) % (v-1) != 0: - if verbose: - print "bk(k-1) is not 0 mod (v-1)" - return False - l = b*k*(k-1) // (v-1) - else: - l = int(l) - if b*k*(k-1) != l*(v-1): + for d in D: + if len(d) != k: if verbose: - print "the relation bk(k-1) == l(v-1) is not satisfied with b=%d, k=%d, l=%d, v=%d"%(b,k,l,v) + print "the block {} does not have length {}".format(d,k) return False - identity, op, inv = group_law(G) + if short_blocks: + nb_diff = 0 + stab_sizes = [] + for d in D: + s = len(block_stabilizer(G,map(G,d))) + stab_sizes.append(s) + nb_diff += k*(k-1) / s + if l is None: + if nb_diff % (v-1) != 0: + if verbose: + print "sum(1/s_i) k*(k-1) = {} is not a multiple of (v-1) = {} (stabilizer sizes {})".format( + nb_diff, v-1, stab_sizes) + return False + l = nb_diff // (v-1) + else: + if nb_diff != l*(v-1): + if verbose: + print ("the relation sum(1/s_i) *k*(k-1) == l*(v-1) is not " + "satisfied (where the s_i are the cardinality of the stabilizer " + "for each blocks)") + return False + + else: + if l is None: + if (b*k*(k-1)) % (v-1) != 0: + if verbose: + print "bk(k-1) is not 0 mod (v-1)" + return False + l = b*k*(k-1) // (v-1) + else: + l = int(l) + if b*k*(k-1) != l*(v-1): + if verbose: + print "the relation bk(k-1) == l(v-1) is not satisfied with b=%d, k=%d, l=%d, v=%d"%(b,k,l,v) + return False # now we check that every non-identity element of G occurs exactly l-time # as a difference - counter = {g: 0 for g in G} + counter = {g: 0 for g in Glist} + where = {g: [] for g in Glist} del counter[identity] - for d in D: - dd = map(G,d) - for i in xrange(k): - for j in xrange(k): - if i == j: - continue - g = op(dd[i], inv(dd[j])) - if g == identity: + if short_blocks: + for i,d in enumerate(D): + dd = map(G,d) + for g in partial_differences(G,dd): + if g.is_zero(): if verbose: - print "two identical elements in the same block" + print "two identical elements in block {}".format(dd) return False + where[g].append(i) counter[g] += 1 - if counter[g] > l: - if verbose: - print "the element %s in G is obtained more than %s times"%(g,l) - return False + else: + for i,d in enumerate(D): + dd = map(G,d) + for ix,x in enumerate(dd): + for iy,y in enumerate(dd): + if ix == iy: + continue + if x == y: + if verbose: + print "two identical elements in block {}".format(dd) + return False + g = mul(x,inv(y)) + where[g].append(i) + counter[g] += 1 + + too_less = [] + too_much = [] + for g in Glist: + if g == identity: + continue + if counter[g] < l: + if verbose: + too_less.append(g) + else: + return False + if counter[g] > l: + if verbose: + too_much.append(g) + else: + return False + + if too_less: + print "Too less:" + for g in too_less: + print " {} is obtained {} times in blocks {}".format( + g,counter[g],where[g]) + if too_much: + print "Too much:" + for g in too_much: + print " {} is obtained {} times in blocks {}".format( + g,counter[g],where[g]) + if too_less or too_much: + return False + if verbose: print "It is a ({},{},{})-difference family".format(v,k,l) return True - def singer_difference_set(q,d): r""" Return a difference set associated to the set of hyperplanes in a projective @@ -248,9 +440,9 @@ def singer_difference_set(q,d): return Zmod((q**(d+1)-1)//(q-1)), [powers] -def difference_family(v, k, l=1, existence=False, check=True): +def difference_family(v, k, l=1, short_blocks=True, existence=False, check=True): r""" - Return a (``k``, ``l``)-difference family on an Abelian group of size ``v``. + Return a (``k``, ``l``)-difference family on an Abelian group of cardinality ``v``. Let `G` be a finite Abelian group. For a given subset `D` of `G`, we define `\Delta D` to be the multi-set of differences `\Delta D = \{x - y; x \in D, @@ -304,9 +496,9 @@ def difference_family(v, k, l=1, existence=False, check=True): sage: for q in islice(prime_power_mod(1,30), 60): ....: l6[designs.difference_family(q,6,existence=True)].append(q) sage: l6[True] - [31, 151, 181, 211, ..., 3061, 3121, 3181] + [31, 121, 151, 181, 211, ..., 3061, 3121, 3181] sage: l6[Unknown] - [61, 121] + [61] sage: l6[False] [] @@ -331,34 +523,56 @@ def difference_family(v, k, l=1, existence=False, check=True): ....: _ = designs.difference_family(v,k,l) ....: if constructions: ....: print "%2d: %s"%(v, ', '.join('(%d,%d)'%(k,l) for k,l in constructions)) - 4: (3,2) - 5: (4,3) - 7: (3,2), (6,5) - 8: (7,6) - 9: (4,3), (8,7) - 11: (5,2), (5,4) - 13: (3,2), (4,3), (6,5) - 15: (7,3) - 16: (3,2), (5,4) - 17: (4,3), (8,7) - 19: (3,2), (6,5), (9,4), (9,8) - 25: (3,2), (4,3), (6,5), (8,7) - 29: (4,3), (7,6) - 31: (3,2), (5,4), (6,5) - 37: (3,2), (4,3), (6,5), (9,2), (9,8) - 41: (4,3), (5,4), (8,7) - 43: (3,2), (6,5), (7,6) - 49: (3,2), (4,3), (6,5), (8,7) - 53: (4,3) - 61: (3,2), (4,3), (5,4), (6,5) - 64: (3,2), (7,6), (9,8) - 67: (3,2), (6,5) - 71: (5,4), (7,6) - 73: (3,2), (4,3), (6,5), (8,7), (9,8) - 79: (3,2), (6,5) - 81: (4,3), (5,4), (8,7) - 89: (4,3), (8,7) - 97: (3,2), (4,3), (6,5), (8,7) + 2: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) + 3: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) + 4: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) + 5: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) + 7: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) + 8: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) + 9: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) + 11: (3,2), (4,3), (4,6), (5,2), (5,3), (5,4), (6,5), (7,6), (8,7), (9,8) + 13: (3,2), (4,3), (5,4), (5,5), (6,5), (7,6), (8,7), (9,8) + 15: (4,6), (5,6), (7,3) + 16: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) + 17: (3,2), (4,3), (5,4), (5,5), (6,5), (7,6), (8,7), (9,8) + 19: (3,2), (4,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,4), (9,5), (9,6), (9,7), (9,8) + 21: (4,3), (6,3), (6,5) + 22: (4,2), (6,5), (7,4), (8,8) + 23: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) + 25: (3,2), (4,3), (5,4), (6,5), (7,6), (7,7), (8,7), (9,8) + 27: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) + 28: (3,2), (6,5) + 29: (3,2), (4,3), (5,4), (6,5), (7,3), (7,6), (8,4), (8,6), (8,7), (9,8) + 31: (3,2), (4,2), (4,3), (5,2), (5,4), (6,5), (7,6), (8,7), (9,8) + 32: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) + 33: (5,5), (6,5) + 34: (4,2) + 35: (5,2), (8,4) + 37: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,2), (9,3), (9,8) + 39: (6,5) + 40: (3,2) + 41: (3,2), (4,3), (5,4), (6,3), (6,5), (7,6), (8,7), (9,8) + 43: (3,2), (4,2), (4,3), (5,4), (6,5), (7,2), (7,3), (7,6), (8,4), (8,7), (9,8) + 46: (4,2), (6,2) + 47: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) + 49: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,3), (9,8) + 51: (5,2), (6,3) + 53: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) + 55: (9,4) + 57: (7,3) + 59: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) + 61: (3,2), (4,3), (5,4), (6,2), (6,3), (6,5), (7,6), (8,7), (9,8) + 64: (3,2), (4,3), (5,4), (6,5), (7,2), (7,6), (8,7), (9,8) + 67: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) + 71: (3,2), (4,3), (5,2), (5,4), (6,5), (7,3), (7,6), (8,4), (8,7), (9,8) + 73: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) + 75: (5,2) + 79: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) + 81: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) + 83: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) + 85: (7,2), (7,3), (8,2) + 89: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8) + 97: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,3), (9,8) TESTS: @@ -387,28 +601,23 @@ def difference_family(v, k, l=1, existence=False, check=True): .. TODO:: - There is a slightly more general version of difference families where - the stabilizers of the blocks are taken into account. A block is *short* - if the stabilizer is not trivial. The more general version is called a - *partial difference family*. It is still possible to construct BIBD from - this more general version (see the chapter 16 in the Handbook - [DesignHandbook]_). - Implement recursive constructions from Buratti "Recursive for difference matrices and relative difference families" (1998) and Jungnickel "Composition theorems for difference families and regular planes" (1978) """ - if (l*(v-1)) % (k*(k-1)) != 0: + if not short_blocks and (l*(v-1)) % (k*(k-1)) != 0: if existence: return False raise EmptySetError("A (v,%d,%d)-difference family may exist only if %d*(v-1) = mod %d"%(k,l,l,k*(k-1))) from block_design import are_hyperplanes_in_projective_geometry_parameters - from database import DF_constructions - if (v,k,l) in DF_constructions: + from database import DF_from_database + + G_df = DF_from_database(v,k,l,short_blocks=short_blocks) + if G_df: if existence: return True - return DF_constructions[(v,k,l)]() + return G_df e = k*(k-1) t = l*(v-1) // e # number of blocks @@ -506,7 +715,7 @@ def difference_family(v, k, l=1, existence=False, check=True): return Unknown raise NotImplementedError("No constructions for these parameters") - if check and not is_difference_family(G,D,verbose=False): + if check and not is_difference_family(G,D,short_blocks=short_blocks,verbose=False): raise RuntimeError return G, D