コード例 #1
0
ファイル: bibd.py プロジェクト: TaraFife/sage
def BIBD_5q_5_for_q_prime_power(q):
    r"""
    Return a `(5q,5,1)`-BIBD with `q\equiv 1\pmod 4` a prime power.

    See Theorem 24 [ClaytonSmith]_.

    INPUT:

    - ``q`` (integer) -- a prime power such that `q\equiv 1\pmod 4`.

    EXAMPLES::

        sage: from sage.combinat.designs.bibd import BIBD_5q_5_for_q_prime_power
        sage: for q in [25, 45, 65, 85, 125, 145, 185, 205, 305, 405, 605]: # long time
        ....:     _ = BIBD_5q_5_for_q_prime_power(q/5)                      # long time
    """
    from sage.rings.finite_rings.finite_field_constructor import FiniteField

    if q%4 != 1 or not is_prime_power(q):
        raise ValueError("q is not a prime power or q%4!=1.")

    d = (q-1)/4
    B = []
    F = FiniteField(q,'x')
    a = F.primitive_element()
    L = {b:i for i,b in enumerate(F)}
    for b in L:
        B.append([i*q + L[b] for i in range(5)])
        for i in range(5):
            for j in range(d):
                B.append([        i*q + L[b          ],
                          ((i+1)%5)*q + L[ a**j+b    ],
                          ((i+1)%5)*q + L[-a**j+b    ],
                          ((i+4)%5)*q + L[ a**(j+d)+b],
                          ((i+4)%5)*q + L[-a**(j+d)+b],
                          ])

    return B
コード例 #2
0
ファイル: resolvable_bibd.py プロジェクト: yunboliu27/sage
def v_4_1_rbibd(v, existence=False):
    r"""
    Return a `(v,4,1)`-RBIBD.

    INPUT:

    - `n` (integer)

    - ``existence`` (boolean; ``False`` by default) -- whether to build the
      design or only answer whether it exists.

    .. SEEALSO::

        - :meth:`IncidenceStructure.is_resolvable`
        - :func:`resolvable_balanced_incomplete_block_design`

    .. NOTE::

        A resolvable `(v,4,1)`-BIBD exists whenever `1\equiv 4\pmod(12)`. This
        function, however, only implements a construction of `(v,4,1)`-BIBD such
        that `v=3q+1\equiv 1\pmod{3}` where `q` is a prime power (see VII.7.5.a
        from [BJL99]_).

    EXAMPLE::

        sage: rBIBD = designs.resolvable_balanced_incomplete_block_design(28,4)
        sage: rBIBD.is_resolvable()
        True
        sage: rBIBD.is_t_design(return_parameters=True)
        (True, (2, 28, 4, 1))

    TESTS::

        sage: for q in prime_powers(2,30):
        ....:     if (3*q+1)%12 == 4:
        ....:         _ = designs.resolvable_balanced_incomplete_block_design(3*q+1,4) # indirect doctest
    """
    # Volume 1, VII.7.5.a from [BJL99]_
    if v % 3 != 1 or not is_prime_power((v - 1) // 3):
        if existence:
            return Unknown
        raise NotImplementedError(
            "I don't know how to build a ({},{},1)-RBIBD!".format(v, 4))
    from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
    q = (v - 1) // 3
    nn = (q - 1) // 4
    G = GF(q, 'x')
    w = G.primitive_element()
    e = w**(nn)
    assert e**2 == -1

    first_class = [[(w**i, j), (-w**i, j), (e * w**i, j + 1),
                    (-e * w**i, j + 1)] for i in range(nn) for j in range(3)]

    first_class.append([(0, 0), (0, 1), (0, 2), 'inf'])

    label = {p: i for i, p in enumerate(G)}

    classes = [[[
        v - 1 if x == 'inf' else (x[1] % 3) * q + label[x[0] + g] for x in S
    ] for S in first_class] for g in G]

    BIBD = BalancedIncompleteBlockDesign(v,
                                         blocks=sum(classes, []),
                                         k=4,
                                         check=True,
                                         copy=False)
    BIBD._classes = classes
    assert BIBD.is_resolvable()
    return BIBD
コード例 #3
0
ファイル: resolvable_bibd.py プロジェクト: yunboliu27/sage
def kirkman_triple_system(v, existence=False):
    r"""
    Return a Kirkman Triple System on `v` points.

    A Kirkman Triple System `KTS(v)` is a resolvable Steiner Triple System. It
    exists if and only if `v\equiv 3\pmod{6}`.

    INPUT:

    - `n` (integer)

    - ``existence`` (boolean; ``False`` by default) -- whether to build the
      `KTS(n)` or only answer whether it exists.

    .. SEEALSO::

        :meth:`IncidenceStructure.is_resolvable`

    EXAMPLES:

    A solution to Kirkmman's original problem::

        sage: kts = designs.kirkman_triple_system(15)
        sage: classes = kts.is_resolvable(1)[1]
        sage: names = '0123456789abcde'
        sage: def to_name(r_s_t):
        ....:     r, s, t = r_s_t
        ....:     return ' ' + names[r] + names[s] + names[t] + ' '
        sage: rows = ['   '.join(('Day {}'.format(i) for i in range(1,8)))]
        sage: rows.extend('   '.join(map(to_name,row)) for row in zip(*classes))
        sage: print('\n'.join(rows))
        Day 1   Day 2   Day 3   Day 4   Day 5   Day 6   Day 7
         07e     18e     29e     3ae     4be     5ce     6de
         139     24a     35b     46c     05d     167     028
         26b     03c     14d     257     368     049     15a
         458     569     06a     01b     12c     23d     347
         acd     7bd     78c     89d     79a     8ab     9bc

    TESTS::

        sage: for i in range(3,300,6):
        ....:     _ = designs.kirkman_triple_system(i)
    """
    if v % 6 != 3:
        if existence:
            return False
        raise ValueError("There is no KTS({}) as v!=3 mod(6)".format(v))

    if existence:
        return False

    elif v == 3:
        return BalancedIncompleteBlockDesign(3, [[0, 1, 2]], k=3, lambd=1)

    elif v == 9:
        classes = [[[0, 1, 5], [2, 6, 7], [3, 4, 8]],
                   [[1, 6, 8], [3, 5, 7], [0, 2, 4]],
                   [[1, 4, 7], [0, 3, 6], [2, 5, 8]],
                   [[4, 5, 6], [0, 7, 8], [1, 2, 3]]]
        KTS = BalancedIncompleteBlockDesign(
            v, [tr for cl in classes for tr in cl], k=3, lambd=1, copy=False)
        KTS._classes = classes
        return KTS

    # Construction 1.1 from [Stinson91] (originally Theorem 6 from [RCW71])
    #
    # For all prime powers q=1 mod 6, there exists a KTS(2q+1)
    elif ((v - 1) // 2) % 6 == 1 and is_prime_power((v - 1) // 2):
        from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
        q = (v - 1) // 2
        K = GF(q, 'x')
        a = K.primitive_element()
        t = (q - 1) // 6

        # m is the solution of a^m=(a^t+1)/2
        from sage.groups.generic import discrete_log
        m = discrete_log((a**t + 1) / 2, a)
        assert 2 * a**m == a**t + 1

        # First parallel class
        first_class = [[(0, 1), (0, 2), 'inf']]
        b0 = K.one()
        b1 = a**t
        b2 = a**m
        first_class.extend([(b0 * a**i, 1), (b1 * a**i, 1), (b2 * a**i, 2)]
                           for i in list(range(t)) +
                           list(range(2 * t, 3 * t)) +
                           list(range(4 * t, 5 * t)))
        b0 = a**(m + t)
        b1 = a**(m + 3 * t)
        b2 = a**(m + 5 * t)
        first_class.extend([[(b0 * a**i, 2), (b1 * a**i, 2), (b2 * a**i, 2)]
                            for i in range(t)])

        # Action of K on the points
        action = lambda v, x: (v + x[0], x[1]) if len(x) == 2 else x

        # relabel to integer
        relabel = {(p, x): i + (x - 1) * q
                   for i, p in enumerate(K) for x in [1, 2]}
        relabel['inf'] = 2 * q

        classes = [[[relabel[action(p, x)] for x in tr] for tr in first_class]
                   for p in K]

        KTS = BalancedIncompleteBlockDesign(
            v, [tr for cl in classes for tr in cl], k=3, lambd=1, copy=False)

        KTS._classes = classes
        return KTS

    # Construction 1.2 from [Stinson91] (originally Theorem 5 from [RCW71])
    #
    # For all prime powers q=1 mod 6, there exists a KTS(3q)
    elif (v // 3) % 6 == 1 and is_prime_power(v // 3):
        from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
        q = v // 3
        K = GF(q, 'x')
        a = K.primitive_element()
        t = (q - 1) // 6
        A0 = [(0, 0), (0, 1), (0, 2)]
        B = [[(a**i, j), (a**(i + 2 * t), j), (a**(i + 4 * t), j)]
             for j in range(3) for i in range(t)]
        A = [[(a**i, 0), (a**(i + 2 * t), 1), (a**(i + 4 * t), 2)]
             for i in range(6 * t)]

        # Action of K on the points
        action = lambda v, x: (v + x[0], x[1])

        # relabel to integer
        relabel = {(p, j): i + j * q
                   for i, p in enumerate(K) for j in range(3)}

        B0 = [A0] + B + A[t:2 * t] + A[3 * t:4 * t] + A[5 * t:6 * t]

        # Classes
        classes = [[[relabel[action(p, x)] for x in tr] for tr in B0]
                   for p in K]

        for i in list(range(t)) + list(range(2 * t, 3 * t)) + list(
                range(4 * t, 5 * t)):
            classes.append([[relabel[action(p, x)] for x in A[i]] for p in K])

        KTS = BalancedIncompleteBlockDesign(
            v, [tr for cl in classes for tr in cl], k=3, lambd=1, copy=False)
        KTS._classes = classes
        return KTS

    else:
        # This is Lemma IX.6.4 from [BJL99].
        #
        # This construction takes a (v,{4,7})-PBD. All points are doubled (x has
        # a copy x'), and an infinite point \infty is added.
        #
        # On all blocks of 2*4 points we "paste" a KTS(2*4+1) using the infinite
        # point, in such a way that all {x,x',infty} are set of the design. We
        # do the same for blocks with 2*7 points using a KTS(2*7+1).
        #
        # Note that the triples of points equal to {x,x',\infty} will be added
        # several times.
        #
        # As all those subdesigns are resolvable, each class of the KTS(n) is
        # obtained by considering a set {x,x',\infty} and all sets of all
        # parallel classes of the subdesign which contain this set.

        # We create the small KTS(n') we need, and relabel them such that
        # 01(n'-1),23(n'-1),... are blocks of the design.
        gdd4 = kirkman_triple_system(9)
        gdd7 = kirkman_triple_system(15)

        X = [B for B in gdd4 if 8 in B]
        for b in X:
            b.remove(8)
        X = sum(X, []) + [8]
        gdd4.relabel({v: i for i, v in enumerate(X)})
        gdd4 = gdd4.is_resolvable(True)[1]  # the relabeled classes

        X = [B for B in gdd7 if 14 in B]
        for b in X:
            b.remove(14)
        X = sum(X, []) + [14]
        gdd7.relabel({v: i for i, v in enumerate(X)})
        gdd7 = gdd7.is_resolvable(True)[1]  # the relabeled classes

        # The first parallel class contains 01(n'-1), the second contains
        # 23(n'-1), etc..
        # Then remove the blocks containing (n'-1)
        for B in gdd4:
            for i, b in enumerate(B):
                if 8 in b:
                    j = min(b)
                    del B[i]
                    B.insert(0, j)
                    break
        gdd4.sort()
        for B in gdd4:
            B.pop(0)

        for B in gdd7:
            for i, b in enumerate(B):
                if 14 in b:
                    j = min(b)
                    del B[i]
                    B.insert(0, j)
                    break
        gdd7.sort()
        for B in gdd7:
            B.pop(0)

        # Pasting the KTS(n') without {x,x',\infty} blocks
        classes = [[] for i in range((v - 1) // 2)]
        gdd = {4: gdd4, 7: gdd7}
        for B in PBD_4_7((v - 1) // 2, check=False):
            for i, classs in enumerate(gdd[len(B)]):
                classes[B[i]].extend([[2 * B[x // 2] + x % 2 for x in BB]
                                      for BB in classs])

        # The {x,x',\infty} blocks
        for i, classs in enumerate(classes):
            classs.append([2 * i, 2 * i + 1, v - 1])

        KTS = BalancedIncompleteBlockDesign(
            v,
            blocks=[tr for cl in classes for tr in cl],
            k=3,
            lambd=1,
            check=True,
            copy=False)
        KTS._classes = classes
        assert KTS.is_resolvable()

        return KTS
コード例 #4
0
def GDD_4_2(q, existence=False, check=True):
    r"""
    Return a `(2q,\{4\},\{2\})`-GDD for `q` a prime power with `q\equiv 1\pmod{6}`.

    This method implements Lemma VII.5.17 from [BJL99] (p.495).

    INPUT:

    - ``q`` (integer)

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

    EXAMPLE::

        sage: from sage.combinat.designs.group_divisible_designs import GDD_4_2
        sage: GDD_4_2(7,existence=True)
        True
        sage: GDD_4_2(7)
        Group Divisible Design on 14 points of type 2^7
        sage: GDD_4_2(8,existence=True)
        Unknown
        sage: GDD_4_2(8)
        Traceback (most recent call last):
        ...
        NotImplementedError
    """
    if q <= 1 or q % 6 != 1 or not is_prime_power(q):
        if existence:
            return Unknown
        raise NotImplementedError
    if existence:
        return True

    from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF

    G = GF(q, "x")
    w = G.primitive_element()
    e = w ** ((q - 1) // 3)

    # A first parallel class is defined. G acts on it, which yields all others.
    first_class = [[(0, 0), (1, w ** i), (1, e * w ** i), (1, e * e * w ** i)] for i in range((q - 1) // 6)]

    label = {p: i for i, p in enumerate(G)}
    classes = [[[2 * label[x[1] + g] + (x[0] + j) % 2 for x in S] for S in first_class] for g in G for j in range(2)]

    return GroupDivisibleDesign(
        2 * q,
        groups=[[i, i + 1] for i in range(0, 2 * q, 2)],
        blocks=sum(classes, []),
        K=[4],
        G=[2],
        check=check,
        copy=False,
    )
コード例 #5
0
ファイル: resolvable_bibd.py プロジェクト: TaraFife/sage
def v_4_1_rbibd(v,existence=False):
    r"""
    Return a `(v,4,1)`-RBIBD.

    INPUT:

    - `n` (integer)

    - ``existence`` (boolean; ``False`` by default) -- whether to build the
      design or only answer whether it exists.

    .. SEEALSO::

        - :meth:`IncidenceStructure.is_resolvable`
        - :func:`resolvable_balanced_incomplete_block_design`

    .. NOTE::

        A resolvable `(v,4,1)`-BIBD exists whenever `1\equiv 4\pmod(12)`. This
        function, however, only implements a construction of `(v,4,1)`-BIBD such
        that `v=3q+1\equiv 1\pmod{3}` where `q` is a prime power (see VII.7.5.a
        from [BJL99]_).

    EXAMPLE::

        sage: rBIBD = designs.resolvable_balanced_incomplete_block_design(28,4)
        sage: rBIBD.is_resolvable()
        True
        sage: rBIBD.is_t_design(return_parameters=True)
        (True, (2, 28, 4, 1))

    TESTS::

        sage: for q in prime_powers(2,30):
        ....:     if (3*q+1)%12 == 4:
        ....:         _ = designs.resolvable_balanced_incomplete_block_design(3*q+1,4) # indirect doctest
    """
    # Volume 1, VII.7.5.a from [BJL99]_
    if v%3 != 1 or not is_prime_power((v-1)//3):
        if existence:
            return Unknown
        raise NotImplementedError("I don't know how to build a ({},{},1)-RBIBD!".format(v,4))
    from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
    q = (v-1)//3
    nn = (q-1)//4
    G = GF(q,'x')
    w = G.primitive_element()
    e = w**(nn)
    assert e**2 == -1

    first_class = [[(w**i,j),(-w**i,j),(e*w**i,j+1),(-e*w**i,j+1)]
                   for i in range(nn) for j in range(3)]

    first_class.append([(0,0),(0,1),(0,2),'inf'])

    label = {p:i for i,p in enumerate(G)}

    classes = [[[v-1 if x=='inf' else (x[1]%3)*q+label[x[0]+g] for x in S]
                for S in first_class]
               for g in G]

    BIBD = BalancedIncompleteBlockDesign(v,
                                         blocks = sum(classes,[]),
                                         k=4,
                                         check=True,
                                         copy=False)
    BIBD._classes = classes
    assert BIBD.is_resolvable()
    return BIBD
コード例 #6
0
ファイル: resolvable_bibd.py プロジェクト: TaraFife/sage
def kirkman_triple_system(v,existence=False):
    r"""
    Return a Kirkman Triple System on `v` points.

    A Kirkman Triple System `KTS(v)` is a resolvable Steiner Triple System. It
    exists if and only if `v\equiv 3\pmod{6}`.

    INPUT:

    - `n` (integer)

    - ``existence`` (boolean; ``False`` by default) -- whether to build the
      `KTS(n)` or only answer whether it exists.

    .. SEEALSO::

        :meth:`IncidenceStructure.is_resolvable`

    EXAMPLES:

    A solution to Kirkmman's original problem::

        sage: kts = designs.kirkman_triple_system(15)
        sage: classes = kts.is_resolvable(1)[1]
        sage: names = '0123456789abcde'
        sage: to_name = lambda (r,s,t): ' '+names[r]+names[s]+names[t]+' '
        sage: rows = ['   '.join(('Day {}'.format(i) for i in range(1,8)))]
        sage: rows.extend('   '.join(map(to_name,row)) for row in zip(*classes))
        sage: print '\n'.join(rows)
        Day 1   Day 2   Day 3   Day 4   Day 5   Day 6   Day 7
         07e     18e     29e     3ae     4be     5ce     6de
         139     24a     35b     46c     05d     167     028
         26b     03c     14d     257     368     049     15a
         458     569     06a     01b     12c     23d     347
         acd     7bd     78c     89d     79a     8ab     9bc

    TESTS::

        sage: for i in range(3,300,6):
        ....:     _ = designs.kirkman_triple_system(i)
    """
    if v%6 != 3:
        if existence:
            return False
        raise ValueError("There is no KTS({}) as v!=3 mod(6)".format(v))

    if existence:
        return False

    elif v == 3:
        return BalancedIncompleteBlockDesign(3,[[0,1,2]],k=3,lambd=1)

    elif v == 9:
        classes = [[[0, 1, 5], [2, 6, 7], [3, 4, 8]],
                   [[1, 6, 8], [3, 5, 7], [0, 2, 4]],
                   [[1, 4, 7], [0, 3, 6], [2, 5, 8]],
                   [[4, 5, 6], [0, 7, 8], [1, 2, 3]]]
        KTS = BalancedIncompleteBlockDesign(v,[tr for cl in classes for tr in cl],k=3,lambd=1,copy=False)
        KTS._classes = classes
        return KTS

    # Construction 1.1 from [Stinson91] (originally Theorem 6 from [RCW71])
    #
    # For all prime powers q=1 mod 6, there exists a KTS(2q+1)
    elif ((v-1)//2)%6 == 1 and is_prime_power((v-1)//2):
        from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
        q = (v-1)//2
        K = GF(q,'x')
        a = K.primitive_element()
        t = (q-1)/6

        # m is the solution of a^m=(a^t+1)/2
        from sage.groups.generic import discrete_log
        m = discrete_log((a**t+1)/2, a)
        assert 2*a**m == a**t+1

        # First parallel class
        first_class = [[(0,1),(0,2),'inf']]
        b0 = K.one(); b1 = a**t; b2 = a**m
        first_class.extend([(b0*a**i,1),(b1*a**i,1),(b2*a**i,2)]
                            for i in range(t)+range(2*t,3*t)+range(4*t,5*t))
        b0 = a**(m+t); b1=a**(m+3*t); b2=a**(m+5*t)
        first_class.extend([[(b0*a**i,2),(b1*a**i,2),(b2*a**i,2)]
                            for i in range(t)])

        # Action of K on the points
        action = lambda v,x : (v+x[0],x[1]) if len(x) == 2 else x

        # relabel to integer
        relabel = {(p,x): i+(x-1)*q
                   for i,p in enumerate(K)
                   for x in [1,2]}
        relabel['inf'] = 2*q

        classes = [[[relabel[action(p,x)] for x in tr] for tr in first_class]
                   for p in K]

        KTS = BalancedIncompleteBlockDesign(v,[tr for cl in classes for tr in cl],k=3,lambd=1,copy=False)

        KTS._classes = classes
        return KTS

    # Construction 1.2 from [Stinson91] (originally Theorem 5 from [RCW71])
    #
    # For all prime powers q=1 mod 6, there exists a KTS(3q)
    elif (v//3)%6 == 1 and is_prime_power(v//3):
        from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
        q = v//3
        K = GF(q,'x')
        a = K.primitive_element()
        t = (q-1)/6
        A0 = [(0,0),(0,1),(0,2)]
        B  = [[(a**i,j),(a**(i+2*t),j),(a**(i+4*t),j)] for j in range(3)
              for i in range(t)]
        A  = [[(a**i,0),(a**(i+2*t),1),(a**(i+4*t),2)] for i in range(6*t)]

        # Action of K on the points
        action = lambda v,x: (v+x[0],x[1])

        # relabel to integer
        relabel = {(p,j): i+j*q
                   for i,p in enumerate(K)
                   for j in range(3)}

        B0  = [A0] + B + A[t:2*t] + A[3*t:4*t] + A[5*t:6*t]

        # Classes
        classes = [[[relabel[action(p,x)] for x in tr] for tr in B0]
                   for p in K]

        for i in range(t)+range(2*t,3*t)+range(4*t,5*t):
            classes.append([[relabel[action(p,x)] for x in A[i]] for p in K])

        KTS = BalancedIncompleteBlockDesign(v,[tr for cl in classes for tr in cl],k=3,lambd=1,copy=False)
        KTS._classes = classes
        return KTS

    else:
        # This is Lemma IX.6.4 from [BJL99].
        #
        # This construction takes a (v,{4,7})-PBD. All points are doubled (x has
        # a copy x'), and an infinite point \infty is added.
        #
        # On all blocks of 2*4 points we "paste" a KTS(2*4+1) using the infinite
        # point, in such a way that all {x,x',infty} are set of the design. We
        # do the same for blocks with 2*7 points using a KTS(2*7+1).
        #
        # Note that the triples of points equal to {x,x',\infty} will be added
        # several times.
        #
        # As all those subdesigns are resolvable, each class of the KTS(n) is
        # obtained by considering a set {x,x',\infty} and all sets of all
        # parallel classes of the subdesign which contain this set.

        # We create the small KTS(n') we need, and relabel them such that
        # 01(n'-1),23(n'-1),... are blocks of the design.
        gdd4 = kirkman_triple_system(9)
        gdd7 = kirkman_triple_system(15)

        X = [B for B in gdd4 if 8 in B]
        for b in X:
            b.remove(8)
        X = sum(X, []) + [8]
        gdd4.relabel({v:i for i,v in enumerate(X)})
        gdd4 = gdd4.is_resolvable(True)[1] # the relabeled classes

        X = [B for B in gdd7 if 14 in B]
        for b in X:
            b.remove(14)
        X = sum(X, []) + [14]
        gdd7.relabel({v:i for i,v in enumerate(X)})
        gdd7 = gdd7.is_resolvable(True)[1] # the relabeled classes

        # The first parallel class contains 01(n'-1), the second contains
        # 23(n'-1), etc..
        # Then remove the blocks containing (n'-1)
        for B in gdd4:
            for i,b in enumerate(B):
                if 8 in b: j = min(b); del B[i]; B.insert(0,j); break
        gdd4.sort()
        for B in gdd4:
            B.pop(0)

        for B in gdd7:
            for i,b in enumerate(B):
                if 14 in b: j = min(b); del B[i]; B.insert(0,j); break
        gdd7.sort()
        for B in gdd7:
            B.pop(0)

        # Pasting the KTS(n') without {x,x',\infty} blocks
        classes = [[] for i in range((v-1)/2)]
        gdd = {4:gdd4, 7: gdd7}
        for B in PBD_4_7((v-1)//2,check=False):
            for i,classs in enumerate(gdd[len(B)]):
                classes[B[i]].extend([[2*B[x//2]+x%2 for x in BB] for BB in classs])

        # The {x,x',\infty} blocks
        for i,classs in enumerate(classes):
            classs.append([2*i,2*i+1,v-1])

        KTS = BalancedIncompleteBlockDesign(v,
                                            blocks = [tr for cl in classes for tr in cl],
                                            k=3,
                                            lambd=1,
                                            check=True,
                                            copy =False)
        KTS._classes = classes
        assert KTS.is_resolvable()

        return KTS
コード例 #7
0
def GDD_4_2(q,existence=False,check=True):
    r"""
    Return a `(2q,\{4\},\{2\})`-GDD for `q` a prime power with `q\equiv 1\pmod{6}`.

    This method implements Lemma VII.5.17 from [BJL99] (p.495).

    INPUT:

    - ``q`` (integer)

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

    EXAMPLE::

        sage: from sage.combinat.designs.group_divisible_designs import GDD_4_2
        sage: GDD_4_2(7,existence=True)
        True
        sage: GDD_4_2(7)
        Group Divisible Design on 14 points of type 2^7
        sage: GDD_4_2(8,existence=True)
        Unknown
        sage: GDD_4_2(8)
        Traceback (most recent call last):
        ...
        NotImplementedError
    """
    if q <=1 or q%6 != 1 or not is_prime_power(q):
        if existence:
            return Unknown
        raise NotImplementedError
    if existence:
        return True

    from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
    G = GF(q,'x')
    w = G.primitive_element()
    e = w**((q - 1) // 3)

    # A first parallel class is defined. G acts on it, which yields all others.
    first_class = [[(0,0),(1,w**i),(1,e*w**i),(1,e*e*w**i)]
                   for i in range((q - 1) // 6)]

    label = {p:i for i,p in enumerate(G)}
    classes = [[[2*label[x[1]+g]+(x[0]+j)%2 for x in S]
                for S in first_class]
               for g in G for j in range(2)]

    return GroupDivisibleDesign(2*q,
                                groups = [[i,i+1] for i in range(0,2*q,2)],
                                blocks = sum(classes,[]),
                                K      = [4],
                                G      = [2],
                                check  = check,
                                copy   = False)
コード例 #8
0
    def __init__(self,
                 q,
                 level,
                 info_magma=None,
                 grouptype=None,
                 magma=None,
                 compute_presentation=True):
        from sage.modular.arithgroup.congroup_gamma import Gamma_constructor
        assert grouptype in ['SL2', 'PSL2']
        self._grouptype = grouptype
        self._compute_presentation = compute_presentation
        self.magma = magma
        self.F = QQ
        self.q = ZZ(q)
        self.discriminant = ZZ(1)
        self.level = ZZ(level / self.q)
        if self.level != 1 and compute_presentation:
            raise NotImplementedError
        self._Gamma = Gamma_constructor(self.q)
        self._Gamma_farey = self._Gamma.farey_symbol()
        self.F_units = []
        self._prec_inf = -1

        self.B = MatrixSpace(QQ, 2, 2)

        # Here we initialize the non-split Cartan, properly
        self.GFq = FiniteField(self.q)
        if not self.GFq(-1).is_square():
            self.eps = ZZ(-1)
        else:
            self.eps = ZZ(2)
            while self.GFq(self.eps).is_square():
                self.eps += 1
        epsinv = (self.GFq(self.eps)**-1).lift()

        N = self.level
        q = self.q
        self.Obasis = [
            matrix(ZZ, 2, 2, v)
            for v in [[1, 0, 0, 1], [0, q, 0, 0], [0, N *
                                                   epsinv, N, 0], [0, 0, 0, q]]
        ]

        x = QQ['x'].gen()
        K = FiniteField(self.q**2, 'z', modulus=x * x - self.eps)
        x = K.primitive_element()
        x1 = x
        while x1.multiplicative_order() != self.q + 1 or x1.norm() != 1:
            x1 *= x
        a, b = x1.polynomial().list()  # represents a+b*sqrt(eps)
        a = a.lift()
        b = b.lift()
        self.extra_matrix = self.B(
            lift(matrix(ZZ, 2, 2, [a, b, b * self.eps, a]), self.q))
        self.extra_matrix_inverse = ~self.extra_matrix
        if compute_presentation:
            self.Ugens = []
            self._gens = []
            temp_relation_words = []
            I = SL2Z([1, 0, 0, 1])
            E = SL2Z([-1, 0, 0, -1])
            minus_one = []
            for i, g in enumerate(self._Gamma_farey.generators()):
                newg = self.B([g.a(), g.b(), g.c(), g.d()])
                if newg == I:
                    continue
                self.Ugens.append(newg)
                self._gens.append(
                    self.element_class(self,
                                       quaternion_rep=newg,
                                       word_rep=[i + 1],
                                       check=False))
                if g.matrix()**2 == I.matrix():
                    temp_relation_words.append([i + 1, i + 1])
                    if minus_one is not None:
                        temp_relation_words.append([-i - 1] + minus_one)
                    else:
                        minus_one = [i + 1]
                elif g.matrix()**2 == E.matrix():
                    temp_relation_words.append([i + 1, i + 1, i + 1, i + 1])
                    if minus_one is not None:
                        temp_relation_words.append([-i - 1, -i - 1] +
                                                   minus_one)
                    else:
                        minus_one = [i + 1, i + 1]
                elif g.matrix()**3 == I.matrix():
                    temp_relation_words.append([i + 1, i + 1, i + 1])
                elif g.matrix()**3 == E.matrix():
                    temp_relation_words.append(
                        [i + 1, i + 1, i + 1, i + 1, i + 1, i + 1])
                    if minus_one is not None:
                        temp_relation_words.append([-i - 1, -i - 1, -i - 1] +
                                                   minus_one)
                    else:
                        minus_one = [i + 1, i + 1, i + 1]
                else:
                    assert g.matrix()**24 != I.matrix()
            # The extra matrix is added
            i = len(self.Ugens)
            self.extra_matrix_index = i
            self.Ugens.append(self.extra_matrix)
            self._gens.append(
                self.element_class(self,
                                   quaternion_rep=self.Ugens[i],
                                   word_rep=[i + 1],
                                   check=False))

            # The new relations are also added
            w = self._get_word_rep_initial(self.extra_matrix**(self.q + 1))
            temp_relation_words.append(w + ([-i - 1] * (self.q + 1)))
            for j, g in enumerate(self.Ugens[:-1]):
                g1 = self.extra_matrix_inverse * g * self.extra_matrix
                w = self._get_word_rep_initial(g1)
                new_rel = w + [-i - 1, -j - 1, i + 1]
                temp_relation_words.append(new_rel)
            self.F_unit_offset = len(self.Ugens)
            if minus_one is not None:
                self.minus_one_long = syllables_to_tietze(minus_one)
            self._relation_words = []
            for rel in temp_relation_words:
                sign = multiply_out(rel, self.Ugens, self.B(1))
                if sign == self.B(1) or 'P' in grouptype:
                    self._relation_words.append(rel)
                else:
                    assert sign == self.B(-1)
                    newrel = rel + self.minus_one
                    sign = multiply_out(newrel, self.Ugens, self.B(1))
                    assert sign == self.B(1)
                    self._relation_words.append(newrel)

        ArithGroup_generic.__init__(self)
        Parent.__init__(self)
コード例 #9
0
    def __init__(self,q,level,info_magma = None,grouptype = None,magma = None, compute_presentation = True):
        from sage.modular.arithgroup.congroup_gamma import Gamma_constructor
        assert grouptype in ['SL2','PSL2']
        self._grouptype = grouptype
        self._compute_presentation = compute_presentation
        self.magma = magma
        self.F = QQ
        self.q = ZZ(q)
        self.discriminant = ZZ(1)
        self.level = ZZ(level/self.q)
        if self.level != 1 and compute_presentation:
            raise NotImplementedError
        self._Gamma = Gamma_constructor(self.q)
        self._Gamma_farey = self._Gamma.farey_symbol()
        self.F_units = []
        self._prec_inf = -1

        self.B = MatrixSpace(QQ,2,2)

        self._O_discriminant = ZZ.ideal(self.level * self.q)

        # Here we initialize the non-split Cartan, properly
        self.GFq = FiniteField(self.q)
        if not self.GFq(-1).is_square():
            self.eps = ZZ(-1)
        else:
            self.eps = ZZ(2)
            while self.GFq(self.eps).is_square():
                self.eps += 1
        epsinv = (self.GFq(self.eps)**-1).lift()

        N = self.level
        q = self.q
        self.Obasis = [matrix(ZZ,2,2,v) for v in [[1,0,0,1], [0,q,0,0], [0,N*epsinv,N,0], [0,0,0,q]]]

        x = QQ['x'].gen()
        K = FiniteField(self.q**2,'z',modulus = x*x - self.eps)
        x = K.primitive_element()
        x1 = x
        while x1.multiplicative_order() != self.q+1 or x1.norm() != 1:
            x1 *= x
        a, b = x1.polynomial().list() # represents a+b*sqrt(eps)
        a = a.lift()
        b = b.lift()
        self.extra_matrix = self.B(lift(matrix(ZZ,2,2,[a,b,b*self.eps,a]),self.q))
        self.extra_matrix_inverse = ~self.extra_matrix
        if compute_presentation:
            self.Ugens = []
            self._gens = []
            temp_relation_words = []
            I = SL2Z([1,0,0,1])
            E = SL2Z([-1,0,0,-1])
            minus_one = []
            for i,g in enumerate(self._Gamma_farey.generators()):
                newg = self.B([g.a(),g.b(),g.c(),g.d()])
                if newg == I:
                    continue
                self.Ugens.append(newg)
                self._gens.append(self.element_class(self,quaternion_rep = newg, word_rep = [i+1],check = False))
                if g.matrix()**2 == I.matrix():
                    temp_relation_words.append([i+1, i+1])
                    if minus_one is not None:
                        temp_relation_words.append([-i-1]+minus_one)
                    else:
                        minus_one = [i+1]
                elif g.matrix()**2 == E.matrix():
                    temp_relation_words.append([i+1,i+1,i+1,i+1])
                    if minus_one is not None:
                        temp_relation_words.append([-i-1,-i-1]+minus_one)
                    else:
                        minus_one = [i+1, i+1]
                elif g.matrix()**3 == I.matrix():
                    temp_relation_words.append([i+1, i+1, i+1])
                elif g.matrix()**3 == E.matrix():
                    temp_relation_words.append([i+1, i+1, i+1, i+1, i+1, i+1])
                    if minus_one is not None:
                        temp_relation_words.append([-i-1, -i-1, -i-1]+minus_one)
                    else:
                        minus_one = [i+1, i+1, i+1]
                else:
                    assert g.matrix()**24 != I.matrix()
            # The extra matrix is added
            i = len(self.Ugens)
            self.extra_matrix_index = i
            self.Ugens.append(self.extra_matrix)
            self._gens.append(self.element_class(self,quaternion_rep = self.Ugens[i], word_rep = [i+1],check = False))

            # The new relations are also added
            w = self._get_word_rep_initial(self.extra_matrix**(self.q+1))
            temp_relation_words.append( w + ([-i-1] * (self.q+1)))
            for j,g in enumerate(self.Ugens[:-1]):
                g1 = self.extra_matrix_inverse * g * self.extra_matrix
                w = self._get_word_rep_initial(g1)
                new_rel = w + [-i-1, -j-1, i+1]
                temp_relation_words.append(new_rel)
            self.F_unit_offset = len(self.Ugens)
            if minus_one is not None:
                self.minus_one_long = syllables_to_tietze(minus_one)
            self._relation_words = []
            for rel in temp_relation_words:
                sign = multiply_out(rel, self.Ugens, self.B(1))
                if sign == self.B(1) or 'P' in grouptype:
                    self._relation_words.append(rel)
                else:
                    assert sign == self.B(-1)
                    newrel = rel + self.minus_one
                    sign = multiply_out(newrel, self.Ugens, self.B(1))
                    assert sign == self.B(1)
                    self._relation_words.append(newrel)

        ArithGroup_generic.__init__(self)
        Parent.__init__(self)