def PBD_4_7(v,check=True, existence=False): r""" Return a `(v,\{4,7\})`-PBD For all `v` such that `n\equiv 1\pmod{3}` and `n\neq 10,19, 31` there exists a `(v,\{4,7\})`-PBD. This is proved in Proposition IX.4.5 from [BJL99]_, which this method implements. This construction of PBD is used by the construction of Kirkman Triple Systems. EXAMPLE:: sage: from sage.combinat.designs.resolvable_bibd import PBD_4_7 sage: PBD_4_7(22) Pairwise Balanced Design on 22 points with sets of sizes in set([4, 7]) TESTS: All values `\leq 300`:: sage: for i in range(1,300,3): ....: if i not in [10,19,31]: ....: assert PBD_4_7(i,existence=True) ....: _ = PBD_4_7(i,check=True) """ if v%3 != 1 or v in [10,19,31]: if existence: return Unknown raise NotImplementedError if existence: return True from group_divisible_designs import GroupDivisibleDesign from group_divisible_designs import GDD_4_2 from bibd import PairwiseBalancedDesign from bibd import balanced_incomplete_block_design if v == 22: # Beth/Jungnickel/Lenz: take KTS(15) and extend each of the 7 classes # with a new point. Make those new points a 7-set. KTS15 = kirkman_triple_system(15) blocks = [S+[i+15] for i,classs in enumerate(KTS15._classes) for S in classs]+[range(15,22)] elif v == 34: # [BJL99] (p527,vol1), but originally Brouwer A = [(0,0),(1,1),(2,0),(4,1)] B = [(0,0),(1,0),(4,2)] C = [(0,0),(2,2),(5,0)] D = [(0,0),(0,1),(0,2)] A = [[(x+i, y+j) for x,y in A] for i in range(9) for j in range(3)] B = [[(x+i, y+i+j) for x,y in B]+[27+j] for i in range(9) for j in range(3)] C = [[(x+i+j,y+2*i+j) for x,y in C]+[30+j] for i in range(9) for j in range(3)] D = [[(x+i, y+i) for x,y in D]+[33] for i in range(9)] blocks = [[int(x) if not isinstance(x,tuple) else (x[1]%3)*9+(x[0]%9) for x in S] for S in A+B+C+D+[range(27,34)]] elif v == 46: # [BJL99] (p527,vol1), but originally Brouwer A = [(1,0),(3,0),(9,0),(0,1)] B = [(2,0),(6,0),(5,0),(0,1)] C = [(0,0),(1,1),(4,2)] D = [(0,0),(2,1),(7,2)] E = [(0,0),(0,1),(0,2)] A = [[(x+i, y+j) for x,y in A] for i in range(13) for j in range(3)] B = [[(x+i, y+j) for x,y in B] for i in range(13) for j in range(3)] C = [[(x+i, y+j) for x,y in C]+[39+j] for i in range(13) for j in range(3)] D = [[(x+i, y+j) for x,y in D]+[42+j] for i in range(13) for j in range(3)] E = [[(x+i, y+i) for x,y in E]+[45] for i in range(13)] blocks = [[int(x) if not isinstance(x,tuple) else (x[1]%3)*13+(x[0]%13) for x in S] for S in A+B+C+D+E+[range(39,46)]] elif v == 58: # [BJL99] (p527,vol1), but originally Brouwer A = [(0,0),(1,0),(4,0),( 5,1)] B = [(0,0),(2,0),(8,0),(11,1)] C = [(0,0),(5,0),(2,1),(12,1)] D = [(0,0),(8,1),(7,2)] E = [(0,0),(6,1),(4,2)] F = [(0,0),(0,1),(0,2)] A = [[(x+i, y+j) for x,y in A] for i in range(17) for j in range(3)] B = [[(x+i, y+j) for x,y in B] for i in range(17) for j in range(3)] C = [[(x+i, y+j) for x,y in C] for i in range(17) for j in range(3)] D = [[(x+i, y+j) for x,y in D]+[51+j] for i in range(17) for j in range(3)] E = [[(x+i, y+j) for x,y in E]+[54+j] for i in range(17) for j in range(3)] F = [[(x+i, y+i) for x,y in F]+[57] for i in range(17)] blocks = [[int(x) if not isinstance(x,tuple) else (x[1]%3)*17+(x[0]%17) for x in S] for S in A+B+C+D+E+F+[range(51,58)]] elif v == 70: # [BJL99] (p527,vol1), but originally Brouwer A = [(0,0),(1,0),(5,1),(13,1)] B = [(0,0),(4,0),(20,1),(10,1)] C = [(0,0),(16,0),(17,1),(19,1)] D = [(0,0),(2,1),(8,1),(11,1)] E = [(0,0),(3,2),(9,1)] F = [(0,0),(7,0),(14,1)] H = [(0,0),(0,1),(0,2)] A = [[(x+i, y+j) for x,y in A] for i in range(21) for j in range(3)] B = [[(x+i, y+j) for x,y in B] for i in range(21) for j in range(3)] C = [[(x+i, y+j) for x,y in C] for i in range(21) for j in range(3)] D = [[(x+i, y+j) for x,y in D] for i in range(21) for j in range(3)] E = [[(x+i, y+j) for x,y in E]+[63+j] for i in range(21) for j in range(3)] F = [[(x+3*i+j, y+ii+j) for x,y in F]+[66+j] for i in range( 7) for j in range(3) for ii in range(3)] H = [[(x+i, y+i) for x,y in H]+[69] for i in range(21)] blocks = [[int(x) if not isinstance(x,tuple) else (x[1]%3)*21+(x[0]%21) for x in S] for S in A+B+C+D+E+F+H+[range(63,70)]] elif v == 82: # This construction is Theorem IX.3.16 from [BJL99] (p.627). # # A (15,{4},{3})-GDD from a (16,4)-BIBD from group_divisible_designs import group_divisible_design from orthogonal_arrays import transversal_design GDD = group_divisible_design(3*5,K=[4],G=[3],check=False) TD = transversal_design(5,5) # A (75,{4},{15})-GDD GDD2 = [[3*B[x//3]+x%3 for x in BB] for B in TD for BB in GDD] # We now complete the (75,{4},{15})-GDD into a (82,{4,7})-PBD. For this, # we add 7 new points that are added to all groups of size 15. # # On these groups a (15+7,{4,7})-PBD is pasted, in such a way that the 7 # new points are a set of the final PBD PBD22 = PBD_4_7(15+7) S = next(SS for SS in PBD22 if len(SS) == 7) # a set of size 7 PBD22.relabel({v:i for i,v in enumerate([i for i in range(15+7) if i not in S] + S)}) for B in PBD22: if B == S: continue for i in range(5): GDD2.append([x+i*15 if x<15 else x+60 for x in B]) GDD2.append(range(75,82)) blocks = GDD2 elif v == 94: # IX.4.5.l from [BJL99]. # # take 4 parallel lines from an affine plane of order 7, and a 5th # one. This is a (31,{4,5,7})-BIBD. And 94=3*31+1. from sage.combinat.designs.block_design import AffineGeometryDesign AF = AffineGeometryDesign(2,1,7) parall = [] plus_one = None for S in AF: if all(all(x not in SS for x in S) for SS in parall): parall.append(S) elif plus_one is None: plus_one = S if len(parall) == 4 and plus_one is not None: break X = set(sum(parall,plus_one)) S_4_5_7 = [X.intersection(S) for S in AF] S_4_5_7 = [S for S in S_4_5_7 if len(S)>1] S_4_5_7 = PairwiseBalancedDesign(X, blocks = S_4_5_7, K = [4,5,7], check=False) S_4_5_7.relabel() return PBD_4_7_from_Y(S_4_5_7,check=check) elif v == 127 or v == 142: # IX.4.5.o from [BJL99]. # # Attach two or seven infinite points to a (40,4)-RBIBD to get a # (42,{4,5},{1,2,7})-GDD or a (47,{4,5},{1,2,7})-GDD points_to_add = 2 if v == 127 else 7 rBIBD4 = v_4_1_rbibd(40) GDD = [S+[40+i] if i<points_to_add else S for i,classs in enumerate(rBIBD4._classes) for S in classs] if points_to_add == 7: GDD.append(range(40,40+points_to_add)) groups = [[x] for x in range(40+points_to_add)] else: groups = [[x] for x in range(40)] groups.append(range(40,40+points_to_add)) GDD = GroupDivisibleDesign(40+points_to_add, groups = groups, blocks = GDD, K = [2,4,5,7], check = False, copy = False) return PBD_4_7_from_Y(GDD,check=check) elif v%6 == 1 and GDD_4_2((v-1)/6,existence=True): # VII.5.17 from [BJL99] gdd = GDD_4_2((v-1)/6) return PBD_4_7_from_Y(gdd,check=check) elif v == 202: # IV.4.5.p from [BJL99] PBD = PBD_4_7(22,check=False) PBD = PBD_4_7_from_Y(PBD,check=False) return PBD_4_7_from_Y(PBD,check=check) elif balanced_incomplete_block_design(v,4,existence=True): return balanced_incomplete_block_design(v,4) elif balanced_incomplete_block_design(v,7,existence=True): return balanced_incomplete_block_design(v,7) else: from sage.combinat.designs.orthogonal_arrays import orthogonal_array # IX.4.5.m from [BJL99]. # # This construction takes a TD(5,g) and truncates its last column to # size u: it yields a (4g+u,{4,5},{g,u})-GDD. If there exists a # (3g+1,{4,7})-PBD and a (3u+1,{4,7})-PBD, then we can apply the x->3x+1 # construction on the truncated transversal design (which is a GDD). # # We write vv = 4g+u while satisfying the hypotheses. vv = (v-1)/3 for g in range((vv+5-1)//5,vv//4+1): u = vv-4*g if (orthogonal_array(5,g,existence=True) and PBD_4_7(3*g+1,existence=True) and PBD_4_7(3*u+1,existence=True)): from orthogonal_arrays import transversal_design domain = set(range(vv)) GDD = transversal_design(5,g) GDD = GroupDivisibleDesign(vv, groups = [[x for x in gr if x in domain] for gr in GDD.groups()], blocks = [[x for x in B if x in domain] for B in GDD], G = set([g,u]), K = [4,5], check=False) return PBD_4_7_from_Y(GDD,check=check) return PairwiseBalancedDesign(v, blocks = blocks, K = [4,7], check = check, copy = False)
def group_divisible_design(v, K, G, existence=False, check=False): r""" Return a `(v,K,G)`-Group Divisible Design. A `(v,K,G)`-GDD is a pair `(\mathcal G, \mathcal B)` where: - `\mathcal G` is a partition of `X=\bigcup \mathcal G` where `|X|=v` - `\forall S\in \mathcal G, |S| \in G` - `\forall S\in \mathcal B, |S| \in K` - `\mathcal G\cup \mathcal B` is a `(v,K\cup G)`-PBD For more information, see the documentation of :class:`~sage.combinat.designs.incidence_structures.GroupDivisibleDesign` or :class:`~sage.combinat.designs.bibd.PairwiseBalancedDesign`. INPUT: - ``v`` (integer) - ``K,G`` (sets of integers) - ``existence`` (boolean) -- instead of building the design, return: - ``True`` -- meaning that Sage knows how to build the design - ``Unknown`` -- meaning that Sage does not know how to build the design, but that the design may exist (see :mod:`sage.misc.unknown`). - ``False`` -- meaning that the design does not exist. - ``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 ``True`` by default. .. NOTE:: The GDD returned by this function are defined on ``range(v)``, and its groups are sets of consecutive integers. EXAMPLES:: sage: designs.group_divisible_design(14,{4},{2}) Group Divisible Design on 14 points of type 2^7 """ G = list(set(G)) K = list(set(K)) blocks = None # from a (v+1,k,1)-BIBD if (len(G) == 1 and len(K) == 1 and G[0] + 1 in K): from bibd import balanced_incomplete_block_design k = K[0] if existence: return balanced_incomplete_block_design(v + 1, k, existence=True) BIBD = balanced_incomplete_block_design(v + 1, k) groups = [[x for x in S if x != v] for S in BIBD if v in S] d = {p: i for i, p in enumerate(sum(groups, []))} d[v] = v BIBD.relabel(d) groups = [ range((k - 1) * i, (k - 1) * (i + 1)) for i in range(v // (k - 1)) ] blocks = [S for S in BIBD if v not in S] # (v,{4},{2})-GDD elif (v % 2 == 0 and K == [4] and G == [2] and GDD_4_2(v // 2, existence=True)): if existence: return True return GDD_4_2(v // 2, check=check) # From a TD(k,g) elif (len(G) == 1 and len(K) == 1 and K[0] * G[0] == v): from orthogonal_arrays import transversal_design return transversal_design(k=K[0], n=G[0], existence=existence) if blocks: return GroupDivisibleDesign(v, groups=groups, blocks=blocks, G=G, K=K, check=check, copy=True) if existence: return Unknown raise NotImplementedError
def PBD_4_7(v, check=True, existence=False): r""" Return a `(v,\{4,7\})`-PBD For all `v` such that `n\equiv 1\pmod{3}` and `n\neq 10,19, 31` there exists a `(v,\{4,7\})`-PBD. This is proved in Proposition IX.4.5 from [BJL99]_, which this method implements. This construction of PBD is used by the construction of Kirkman Triple Systems. EXAMPLE:: sage: from sage.combinat.designs.resolvable_bibd import PBD_4_7 sage: PBD_4_7(22) Pairwise Balanced Design on 22 points with sets of sizes in set([4, 7]) TESTS: All values `\leq 300`:: sage: for i in range(1,300,3): ....: if i not in [10,19,31]: ....: assert PBD_4_7(i,existence=True) ....: _ = PBD_4_7(i,check=True) """ if v % 3 != 1 or v in [10, 19, 31]: if existence: return Unknown raise NotImplementedError if existence: return True from group_divisible_designs import GroupDivisibleDesign from group_divisible_designs import GDD_4_2 from bibd import PairwiseBalancedDesign from bibd import balanced_incomplete_block_design if v == 22: # Beth/Jungnickel/Lenz: take KTS(15) and extend each of the 7 classes # with a new point. Make those new points a 7-set. KTS15 = kirkman_triple_system(15) blocks = [ S + [i + 15] for i, classs in enumerate(KTS15._classes) for S in classs ] + [range(15, 22)] elif v == 34: # [BJL99] (p527,vol1), but originally Brouwer A = [(0, 0), (1, 1), (2, 0), (4, 1)] B = [(0, 0), (1, 0), (4, 2)] C = [(0, 0), (2, 2), (5, 0)] D = [(0, 0), (0, 1), (0, 2)] A = [[(x + i, y + j) for x, y in A] for i in range(9) for j in range(3)] B = [[(x + i, y + i + j) for x, y in B] + [27 + j] for i in range(9) for j in range(3)] C = [[(x + i + j, y + 2 * i + j) for x, y in C] + [30 + j] for i in range(9) for j in range(3)] D = [[(x + i, y + i) for x, y in D] + [33] for i in range(9)] blocks = [[ int(x) if not isinstance(x, tuple) else (x[1] % 3) * 9 + (x[0] % 9) for x in S ] for S in A + B + C + D + [range(27, 34)]] elif v == 46: # [BJL99] (p527,vol1), but originally Brouwer A = [(1, 0), (3, 0), (9, 0), (0, 1)] B = [(2, 0), (6, 0), (5, 0), (0, 1)] C = [(0, 0), (1, 1), (4, 2)] D = [(0, 0), (2, 1), (7, 2)] E = [(0, 0), (0, 1), (0, 2)] A = [[(x + i, y + j) for x, y in A] for i in range(13) for j in range(3)] B = [[(x + i, y + j) for x, y in B] for i in range(13) for j in range(3)] C = [[(x + i, y + j) for x, y in C] + [39 + j] for i in range(13) for j in range(3)] D = [[(x + i, y + j) for x, y in D] + [42 + j] for i in range(13) for j in range(3)] E = [[(x + i, y + i) for x, y in E] + [45] for i in range(13)] blocks = [[ int(x) if not isinstance(x, tuple) else (x[1] % 3) * 13 + (x[0] % 13) for x in S ] for S in A + B + C + D + E + [range(39, 46)]] elif v == 58: # [BJL99] (p527,vol1), but originally Brouwer A = [(0, 0), (1, 0), (4, 0), (5, 1)] B = [(0, 0), (2, 0), (8, 0), (11, 1)] C = [(0, 0), (5, 0), (2, 1), (12, 1)] D = [(0, 0), (8, 1), (7, 2)] E = [(0, 0), (6, 1), (4, 2)] F = [(0, 0), (0, 1), (0, 2)] A = [[(x + i, y + j) for x, y in A] for i in range(17) for j in range(3)] B = [[(x + i, y + j) for x, y in B] for i in range(17) for j in range(3)] C = [[(x + i, y + j) for x, y in C] for i in range(17) for j in range(3)] D = [[(x + i, y + j) for x, y in D] + [51 + j] for i in range(17) for j in range(3)] E = [[(x + i, y + j) for x, y in E] + [54 + j] for i in range(17) for j in range(3)] F = [[(x + i, y + i) for x, y in F] + [57] for i in range(17)] blocks = [[ int(x) if not isinstance(x, tuple) else (x[1] % 3) * 17 + (x[0] % 17) for x in S ] for S in A + B + C + D + E + F + [range(51, 58)]] elif v == 70: # [BJL99] (p527,vol1), but originally Brouwer A = [(0, 0), (1, 0), (5, 1), (13, 1)] B = [(0, 0), (4, 0), (20, 1), (10, 1)] C = [(0, 0), (16, 0), (17, 1), (19, 1)] D = [(0, 0), (2, 1), (8, 1), (11, 1)] E = [(0, 0), (3, 2), (9, 1)] F = [(0, 0), (7, 0), (14, 1)] H = [(0, 0), (0, 1), (0, 2)] A = [[(x + i, y + j) for x, y in A] for i in range(21) for j in range(3)] B = [[(x + i, y + j) for x, y in B] for i in range(21) for j in range(3)] C = [[(x + i, y + j) for x, y in C] for i in range(21) for j in range(3)] D = [[(x + i, y + j) for x, y in D] for i in range(21) for j in range(3)] E = [[(x + i, y + j) for x, y in E] + [63 + j] for i in range(21) for j in range(3)] F = [[(x + 3 * i + j, y + ii + j) for x, y in F] + [66 + j] for i in range(7) for j in range(3) for ii in range(3)] H = [[(x + i, y + i) for x, y in H] + [69] for i in range(21)] blocks = [[ int(x) if not isinstance(x, tuple) else (x[1] % 3) * 21 + (x[0] % 21) for x in S ] for S in A + B + C + D + E + F + H + [range(63, 70)]] elif v == 82: # This construction is Theorem IX.3.16 from [BJL99] (p.627). # # A (15,{4},{3})-GDD from a (16,4)-BIBD from group_divisible_designs import group_divisible_design from orthogonal_arrays import transversal_design GDD = group_divisible_design(3 * 5, K=[4], G=[3], check=False) TD = transversal_design(5, 5) # A (75,{4},{15})-GDD GDD2 = [[3 * B[x // 3] + x % 3 for x in BB] for B in TD for BB in GDD] # We now complete the (75,{4},{15})-GDD into a (82,{4,7})-PBD. For this, # we add 7 new points that are added to all groups of size 15. # # On these groups a (15+7,{4,7})-PBD is pasted, in such a way that the 7 # new points are a set of the final PBD PBD22 = PBD_4_7(15 + 7) S = next(SS for SS in PBD22 if len(SS) == 7) # a set of size 7 PBD22.relabel({ v: i for i, v in enumerate([i for i in range(15 + 7) if i not in S] + S) }) for B in PBD22: if B == S: continue for i in range(5): GDD2.append([x + i * 15 if x < 15 else x + 60 for x in B]) GDD2.append(range(75, 82)) blocks = GDD2 elif v == 94: # IX.4.5.l from [BJL99]. # # take 4 parallel lines from an affine plane of order 7, and a 5th # one. This is a (31,{4,5,7})-BIBD. And 94=3*31+1. from sage.combinat.designs.block_design import AffineGeometryDesign AF = AffineGeometryDesign(2, 1, 7) parall = [] plus_one = None for S in AF: if all(all(x not in SS for x in S) for SS in parall): parall.append(S) elif plus_one is None: plus_one = S if len(parall) == 4 and plus_one is not None: break X = set(sum(parall, plus_one)) S_4_5_7 = [X.intersection(S) for S in AF] S_4_5_7 = [S for S in S_4_5_7 if len(S) > 1] S_4_5_7 = PairwiseBalancedDesign(X, blocks=S_4_5_7, K=[4, 5, 7], check=False) S_4_5_7.relabel() return PBD_4_7_from_Y(S_4_5_7, check=check) elif v == 127 or v == 142: # IX.4.5.o from [BJL99]. # # Attach two or seven infinite points to a (40,4)-RBIBD to get a # (42,{4,5},{1,2,7})-GDD or a (47,{4,5},{1,2,7})-GDD points_to_add = 2 if v == 127 else 7 rBIBD4 = v_4_1_rbibd(40) GDD = [ S + [40 + i] if i < points_to_add else S for i, classs in enumerate(rBIBD4._classes) for S in classs ] if points_to_add == 7: GDD.append(range(40, 40 + points_to_add)) groups = [[x] for x in range(40 + points_to_add)] else: groups = [[x] for x in range(40)] groups.append(range(40, 40 + points_to_add)) GDD = GroupDivisibleDesign(40 + points_to_add, groups=groups, blocks=GDD, K=[2, 4, 5, 7], check=False, copy=False) return PBD_4_7_from_Y(GDD, check=check) elif v % 6 == 1 and GDD_4_2((v - 1) / 6, existence=True): # VII.5.17 from [BJL99] gdd = GDD_4_2((v - 1) / 6) return PBD_4_7_from_Y(gdd, check=check) elif v == 202: # IV.4.5.p from [BJL99] PBD = PBD_4_7(22, check=False) PBD = PBD_4_7_from_Y(PBD, check=False) return PBD_4_7_from_Y(PBD, check=check) elif balanced_incomplete_block_design(v, 4, existence=True): return balanced_incomplete_block_design(v, 4) elif balanced_incomplete_block_design(v, 7, existence=True): return balanced_incomplete_block_design(v, 7) else: from sage.combinat.designs.orthogonal_arrays import orthogonal_array # IX.4.5.m from [BJL99]. # # This construction takes a TD(5,g) and truncates its last column to # size u: it yields a (4g+u,{4,5},{g,u})-GDD. If there exists a # (3g+1,{4,7})-PBD and a (3u+1,{4,7})-PBD, then we can apply the x->3x+1 # construction on the truncated transversal design (which is a GDD). # # We write vv = 4g+u while satisfying the hypotheses. vv = (v - 1) / 3 for g in range((vv + 5 - 1) // 5, vv // 4 + 1): u = vv - 4 * g if (orthogonal_array(5, g, existence=True) and PBD_4_7(3 * g + 1, existence=True) and PBD_4_7(3 * u + 1, existence=True)): from orthogonal_arrays import transversal_design domain = set(range(vv)) GDD = transversal_design(5, g) GDD = GroupDivisibleDesign( vv, groups=[[x for x in gr if x in domain] for gr in GDD.groups()], blocks=[[x for x in B if x in domain] for B in GDD], G=set([g, u]), K=[4, 5], check=False) return PBD_4_7_from_Y(GDD, check=check) return PairwiseBalancedDesign(v, blocks=blocks, K=[4, 7], check=check, copy=False)
def group_divisible_design(v,K,G,existence=False,check=False): r""" Return a `(v,K,G)`-Group Divisible Design. A `(v,K,G)`-GDD is a pair `(\mathcal G, \mathcal B)` where: - `\mathcal G` is a partition of `X=\bigcup \mathcal G` where `|X|=v` - `\forall S\in \mathcal G, |S| \in G` - `\forall S\in \mathcal B, |S| \in K` - `\mathcal G\cup \mathcal B` is a `(v,K\cup G)`-PBD For more information, see the documentation of :class:`~sage.combinat.designs.incidence_structures.GroupDivisibleDesign` or :class:`~sage.combinat.designs.bibd.PairwiseBalancedDesign`. INPUT: - ``v`` (integer) - ``K,G`` (sets of integers) - ``existence`` (boolean) -- instead of building the design, return: - ``True`` -- meaning that Sage knows how to build the design - ``Unknown`` -- meaning that Sage does not know how to build the design, but that the design may exist (see :mod:`sage.misc.unknown`). - ``False`` -- meaning that the design does not exist. - ``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 ``True`` by default. .. NOTE:: The GDD returned by this function are defined on ``range(v)``, and its groups are sets of consecutive integers. EXAMPLES:: sage: designs.group_divisible_design(14,{4},{2}) Group Divisible Design on 14 points of type 2^7 """ G = list(set(G)) K = list(set(K)) blocks = None # from a (v+1,k,1)-BIBD if (len(G) == 1 and len(K) == 1 and G[0]+1 in K): from bibd import balanced_incomplete_block_design k = K[0] if existence: return balanced_incomplete_block_design(v+1,k,existence=True) BIBD = balanced_incomplete_block_design(v+1,k) groups = [[x for x in S if x!=v] for S in BIBD if v in S] d = {p:i for i,p in enumerate(sum(groups,[]))} d[v]=v BIBD.relabel(d) groups = [range((k-1)*i,(k-1)*(i+1)) for i in range(v//(k-1))] blocks = [S for S in BIBD if v not in S] # (v,{4},{2})-GDD elif (v%2==0 and K == [4] and G == [2] and GDD_4_2(v//2,existence=True)): if existence: return True return GDD_4_2(v//2,check=check) # From a TD(k,g) elif (len(G) == 1 and len(K) == 1 and K[0]*G[0] == v): from orthogonal_arrays import transversal_design return transversal_design(k=K[0],n=G[0],existence=existence) if blocks: return GroupDivisibleDesign(v, groups = groups, blocks = blocks, G = G, K = K, check = check, copy = True) if existence: return Unknown raise NotImplementedError