コード例 #1
0
def PBD_4_7_from_Y(gdd,check=True):
    r"""
    Return a `(3v+1,\{4,7\})`-PBD from a `(v,\{4,5,7\},\NN-\{3,6,10\})`-GDD.

    This implements Lemma IX.3.11 from [BJL99]_ (p.625). All points of the GDD
    are tripled, and a `+\infty` point is added to the design.

    - A group of size `s\in Y=\NN-\{3,6,10\}` becomes a set of size `3s`. Adding
      `\infty` to it gives it size `3s+1`, and this set is then replaced by a
      `(3s+1,\{4,7\})`-PBD.

    - A block of size `s\in\{4,5,7\}` becomes a `(3s,\{4,7\},\{3\})`-GDD.

    This lemma is part of the existence proof of `(v,\{4,7\})`-PBD as explained
    in IX.4.5 from [BJL99]_).

    INPUT:

    - ``gdd`` -- a `(v,\{4,5,7\},Y)`-GDD where `Y=\NN-\{3,6,10\}`.

    - ``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.

    EXAMPLE::

        sage: from sage.combinat.designs.resolvable_bibd import PBD_4_7_from_Y
        sage: PBD_4_7_from_Y(designs.transversal_design(7,8))
        Pairwise Balanced Design on 169 points with sets of sizes in set([4, 7])

    TESTS::

        sage: PBD_4_7_from_Y(designs.balanced_incomplete_block_design(10,10))
        Traceback (most recent call last):
        ...
        ValueError: The GDD should only contain blocks of size {4,5,7} but there are other: set([10])
        sage: PBD_4_7_from_Y(designs.transversal_design(4,3))
        Traceback (most recent call last):
        ...
        RuntimeError: A group has size 3 but I do not know how to build a (10,[4,7])-PBD
    """
    from group_divisible_designs import group_divisible_design
    from bibd import PairwiseBalancedDesign
    block_sizes = set(map(len,gdd._blocks))
    group_sizes = set(map(len,gdd._groups))
    if not block_sizes.issubset([4,5,7]):
        raise ValueError("The GDD should only contain blocks of size {{4,5,7}} "
                         "but there are other: {}".format(block_sizes.difference([4,5,7])))

    for gs in group_sizes:
        if not PBD_4_7(3*gs+1,existence=True):
            raise RuntimeError("A group has size {} but I do not know how to "
                               "build a ({},[4,7])-PBD".format(gs,3*gs+1))

    GDD = {} # the GDD we will need
    if 4 in block_sizes:
        #GDD[4] = GDD_from_BIBD(3*4,4)
        GDD[4] = group_divisible_design(3*4,K=[4],G=[3])
    if 5 in block_sizes:
        #GDD[5] = GDD_from_BIBD(3*5,4)
        GDD[5] = group_divisible_design(3*5,K=[4],G=[3])
    if 7 in block_sizes:
        # It is obtained from a PBD_4_7(22) by removing a point only contained
        # in sets of size 4
        GDD[7] = PBD_4_7(22)
        x = set(range(22)).difference(*[S for S in GDD[7] if len(S) != 4]).pop()
        relabel = sum((S for S in GDD[7] if x in S),[]) # the groups must be 012,345,...
        relabel = [xx for xx in relabel if xx != x]+[x]
        GDD[7].relabel({v:i for i,v in enumerate(relabel)})
        GDD[7] = [S for S in GDD[7] if 21 not in S]

    PBD = []

    # The blocks
    for B in gdd:
        for B_GDD in GDD[len(B)]:
            PBD.append([3*B[x//3]+(x%3) for x in B_GDD])

    # The groups
    group_PBD = {gs:PBD_4_7(3*gs+1) for gs in group_sizes}
    for G in gdd.groups():
        gs = len(G)
        for B in group_PBD[gs]:
            PBD.append([3*G[x//3]+(x%3) if x < 3*gs else 3*gdd.num_points()
                        for x in B])

    return PairwiseBalancedDesign(3*gdd.num_points()+1,
                                  blocks = PBD,
                                  K = [4,7],
                                  check = check,
                                  copy = False)
コード例 #2
0
def PBD_4_7_from_Y(gdd, check=True):
    r"""
    Return a `(3v+1,\{4,7\})`-PBD from a `(v,\{4,5,7\},\NN-\{3,6,10\})`-GDD.

    This implements Lemma IX.3.11 from [BJL99]_ (p.625). All points of the GDD
    are tripled, and a `+\infty` point is added to the design.

    - A group of size `s\in Y=\NN-\{3,6,10\}` becomes a set of size `3s`. Adding
      `\infty` to it gives it size `3s+1`, and this set is then replaced by a
      `(3s+1,\{4,7\})`-PBD.

    - A block of size `s\in\{4,5,7\}` becomes a `(3s,\{4,7\},\{3\})`-GDD.

    This lemma is part of the existence proof of `(v,\{4,7\})`-PBD as explained
    in IX.4.5 from [BJL99]_).

    INPUT:

    - ``gdd`` -- a `(v,\{4,5,7\},Y)`-GDD where `Y=\NN-\{3,6,10\}`.

    - ``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.

    EXAMPLE::

        sage: from sage.combinat.designs.resolvable_bibd import PBD_4_7_from_Y
        sage: PBD_4_7_from_Y(designs.transversal_design(7,8))
        Pairwise Balanced Design on 169 points with sets of sizes in set([4, 7])

    TESTS::

        sage: PBD_4_7_from_Y(designs.balanced_incomplete_block_design(10,10))
        Traceback (most recent call last):
        ...
        ValueError: The GDD should only contain blocks of size {4,5,7} but there are other: set([10])
        sage: PBD_4_7_from_Y(designs.transversal_design(4,3))
        Traceback (most recent call last):
        ...
        RuntimeError: A group has size 3 but I do not know how to build a (10,[4,7])-PBD
    """
    from group_divisible_designs import group_divisible_design
    from bibd import PairwiseBalancedDesign
    block_sizes = set(map(len, gdd._blocks))
    group_sizes = set(map(len, gdd._groups))
    if not block_sizes.issubset([4, 5, 7]):
        raise ValueError(
            "The GDD should only contain blocks of size {{4,5,7}} "
            "but there are other: {}".format(block_sizes.difference([4, 5,
                                                                     7])))

    for gs in group_sizes:
        if not PBD_4_7(3 * gs + 1, existence=True):
            raise RuntimeError("A group has size {} but I do not know how to "
                               "build a ({},[4,7])-PBD".format(gs, 3 * gs + 1))

    GDD = {}  # the GDD we will need
    if 4 in block_sizes:
        #GDD[4] = GDD_from_BIBD(3*4,4)
        GDD[4] = group_divisible_design(3 * 4, K=[4], G=[3])
    if 5 in block_sizes:
        #GDD[5] = GDD_from_BIBD(3*5,4)
        GDD[5] = group_divisible_design(3 * 5, K=[4], G=[3])
    if 7 in block_sizes:
        # It is obtained from a PBD_4_7(22) by removing a point only contained
        # in sets of size 4
        GDD[7] = PBD_4_7(22)
        x = set(range(22)).difference(*[S for S in GDD[7]
                                        if len(S) != 4]).pop()
        relabel = sum((S for S in GDD[7] if x in S),
                      [])  # the groups must be 012,345,...
        relabel = [xx for xx in relabel if xx != x] + [x]
        GDD[7].relabel({v: i for i, v in enumerate(relabel)})
        GDD[7] = [S for S in GDD[7] if 21 not in S]

    PBD = []

    # The blocks
    for B in gdd:
        for B_GDD in GDD[len(B)]:
            PBD.append([3 * B[x // 3] + (x % 3) for x in B_GDD])

    # The groups
    group_PBD = {gs: PBD_4_7(3 * gs + 1) for gs in group_sizes}
    for G in gdd.groups():
        gs = len(G)
        for B in group_PBD[gs]:
            PBD.append([
                3 * G[x // 3] + (x % 3) if x < 3 * gs else 3 *
                gdd.num_points() for x in B
            ])

    return PairwiseBalancedDesign(3 * gdd.num_points() + 1,
                                  blocks=PBD,
                                  K=[4, 7],
                                  check=check,
                                  copy=False)
コード例 #3
0
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)
コード例 #4
0
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)