コード例 #1
0
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 join(rows,'\n')
        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.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.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
コード例 #2
0
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 join(rows,'\n')
        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.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.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
コード例 #3
0
ファイル: bibd.py プロジェクト: aaditya-thakkar/sage
def BIBD_from_arc_in_desarguesian_projective_plane(n,k,existence=False):
    r"""
    Returns a `(n,k,1)`-BIBD from a maximal arc in a projective plane.

    This function implements a construction from Denniston [Denniston69]_, who
    describes a maximal :meth:`arc
    <sage.combinat.designs.bibd.BalancedIncompleteBlockDesign.arc>` in a
    :func:`Desarguesian Projective Plane
    <sage.combinat.designs.block_design.DesarguesianProjectivePlaneDesign>` of
    order `2^k`. From two powers of two `n,q` with `n<q`, it produces a
    `((n-1)(q+1)+1,n,1)`-BIBD.

    INPUT:

    - ``n,k`` (integers) -- must be powers of two (among other restrictions).

    - ``existence`` (boolean) -- whether to return the BIBD obtained through
      this construction (default), or to merely indicate with a boolean return
      value whether this method *can* build the requested BIBD.

    EXAMPLES:

    A `(232,8,1)`-BIBD::

        sage: from sage.combinat.designs.bibd import BIBD_from_arc_in_desarguesian_projective_plane
        sage: from sage.combinat.designs.bibd import BalancedIncompleteBlockDesign
        sage: D = BIBD_from_arc_in_desarguesian_projective_plane(232,8)
        sage: BalancedIncompleteBlockDesign(232,D)
        (232,8,1)-Balanced Incomplete Block Design

    A `(120,8,1)`-BIBD::

        sage: D = BIBD_from_arc_in_desarguesian_projective_plane(120,8)
        sage: BalancedIncompleteBlockDesign(120,D)
        (120,8,1)-Balanced Incomplete Block Design

    Other parameters::

        sage: all(BIBD_from_arc_in_desarguesian_projective_plane(n,k,existence=True)
        ....:     for n,k in
        ....:       [(120, 8), (232, 8), (456, 8), (904, 8), (496, 16),
        ....:        (976, 16), (1936, 16), (2016, 32), (4000, 32), (8128, 64)])
        True

    Of course, not all can be built this way::

        sage: BIBD_from_arc_in_desarguesian_projective_plane(7,3,existence=True)
        False
        sage: BIBD_from_arc_in_desarguesian_projective_plane(7,3)
        Traceback (most recent call last):
        ...
        ValueError: This function cannot produce a (7,3,1)-BIBD

    REFERENCE:

    .. [Denniston69] R. H. F. Denniston,
       Some maximal arcs in finite projective planes.
       Journal of Combinatorial Theory 6, no. 3 (1969): 317-319.
       http://dx.doi.org/10.1016/S0021-9800(69)80095-5

    """
    q = (n-1)//(k-1)-1
    if (k % 2                 or
        q % 2                 or
        q <= k                or
        n != (k-1)*(q+1)+1    or
        not is_prime_power(k) or
        not is_prime_power(q)):
        if existence:
            return False
        raise ValueError("This function cannot produce a ({},{},1)-BIBD".format(n,k))

    if existence:
        return True

    n = k

    # From now on, the code assumes the notations of [Denniston69] for n,q, so
    # that the BIBD returned by the method will have the requested parameters.

    from sage.rings.finite_rings.constructor import FiniteField as GF
    from sage.libs.gap.libgap import libgap
    from sage.matrix.constructor import Matrix

    K   = GF(q,'a')
    one = K.one()

    # An irreducible quadratic form over K[X,Y]
    GO = libgap.GeneralOrthogonalGroup(-1,2,q)
    M  = libgap.InvariantQuadraticForm(GO)['matrix']
    M  = Matrix(M)
    M  = M.change_ring(K)
    Q  = lambda xx,yy : M[0,0]*xx**2+(M[0,1]+M[1,0])*xx*yy+M[1,1]*yy**2

    # Here, the additive subgroup H (of order n) of K mentioned in
    # [Denniston69] is the set of all elements of K of degree < log_n
    # (seeing elements of K as polynomials in 'a')

    K_iter = list(K) # faster iterations
    log_n = is_prime_power(n,get_data=True)[1]
    C = [(x,y,one)
         for x in K_iter
         for y in K_iter
         if Q(x,y).polynomial().degree() < log_n]

    from sage.combinat.designs.block_design import DesarguesianProjectivePlaneDesign
    return DesarguesianProjectivePlaneDesign(q).trace(C)._blocks
コード例 #4
0
ファイル: block_design.py プロジェクト: aaditya-thakkar/sage
def HughesPlane(q2, check=True):
    r"""
    Return the Hughes projective plane of order ``q2``.

    Let `q` be an odd prime, the Hughes plane of order `q^2` is a finite
    projective plane of order `q^2` introduced by D. Hughes in [Hu57]_. Its
    construction is as follows.

    Let `K = GF(q^2)` be a finite field with `q^2` elements and `F = GF(q)
    \subset K` be its unique subfield with `q` elements. We define a twisted
    multiplication on `K` as

    .. MATH::

        x \circ y =
        \begin{cases}
        x\ y & \text{if y is a square in K}\\
        x^q\ y & \text{otherwise}
        \end{cases}

    The points of the Hughes plane are the triples `(x, y, z)` of points in `K^3
    \backslash \{0,0,0\}` up to the equivalence relation `(x,y,z) \sim (x \circ
    k, y \circ k, z \circ k)` where `k \in K`.

    For `a = 1` or `a \in (K \backslash F)` we define a block `L(a)` as the set of
    triples `(x,y,z)` so that `x + a \circ y + z = 0`. The rest of the blocks
    are obtained by letting act the group `GL(3, F)` by its standard action.

    For more information, see :wikipedia:`Hughes_plane` and [We07].

    .. SEEALSO::

        :func:`DesarguesianProjectivePlaneDesign` to build the Desarguesian
        projective planes

    INPUT:

    - ``q2`` -- an even power of an odd prime number

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

    EXAMPLES::

        sage: H = designs.HughesPlane(9)
        sage: H
        (91,10,1)-Balanced Incomplete Block Design

    We prove in the following computations that the Desarguesian plane ``H`` is
    not Desarguesian. Let us consider the two triangles `(0,1,10)` and `(57, 70,
    59)`. We show that the intersection points `D_{0,1} \cap D_{57,70}`,
    `D_{1,10} \cap D_{70,59}` and `D_{10,0} \cap D_{59,57}` are on the same line
    while `D_{0,70}`, `D_{1,59}` and `D_{10,57}` are not concurrent::

        sage: blocks = H.blocks()
        sage: line = lambda p,q: (b for b in blocks if p in b and q in b).next()

        sage: b_0_1 = line(0, 1)
        sage: b_1_10 = line(1, 10)
        sage: b_10_0 = line(10, 0)
        sage: b_57_70 = line(57, 70)
        sage: b_70_59 = line(70, 59)
        sage: b_59_57 = line(59, 57)

        sage: set(b_0_1).intersection(b_57_70)
        {2}
        sage: set(b_1_10).intersection(b_70_59)
        {73}
        sage: set(b_10_0).intersection(b_59_57)
        {60}

        sage: line(2, 73) == line(73, 60)
        True

        sage: b_0_57 = line(0, 57)
        sage: b_1_70 = line(1, 70)
        sage: b_10_59 = line(10, 59)

        sage: p = set(b_0_57).intersection(b_1_70)
        sage: q = set(b_1_70).intersection(b_10_59)
        sage: p == q
        False

    TESTS:

    Some wrong input::

        sage: designs.HughesPlane(5)
        Traceback (most recent call last):
        ...
        EmptySetError: No Hughes plane of non-square order exists.

        sage: designs.HughesPlane(16)
        Traceback (most recent call last):
        ...
        EmptySetError: No Hughes plane of even order exists.

    Check that it works for non-prime `q`::

        sage: designs.HughesPlane(3**4)    # not tested - 10 secs
        (6643,82,1)-Balanced Incomplete Block Design
    """
    if not q2.is_square():
        raise EmptySetError("No Hughes plane of non-square order exists.")
    if q2%2 == 0:
        raise EmptySetError("No Hughes plane of even order exists.")
    q = q2.sqrt()
    K = FiniteField(q2, prefix='x', conway=True)
    F = FiniteField(q, prefix='y', conway=True)
    A = q3_minus_one_matrix(F)
    A = A.change_ring(K)
    m = K.list()
    V = VectorSpace(K, 3)
    zero = K.zero()
    one = K.one()
    points = [(x, y, one) for x in m for y in m] + \
             [(x, one, zero) for x in m] + \
             [(one, zero, zero)]
    relabel = {tuple(p):i for i,p in enumerate(points)}
    blcks = []
    for a in m:
        if a not in F or a == 1:
            # build L(a)
            aa = ~a
            l = []
            l.append(V((-a, one, zero)))
            for x in m:
                y = - aa * (x+one)
                if not y.is_square():
                    y *= aa**(q-1)
                l.append(V((x, y, one)))
            # compute the orbit of L(a)
            blcks.append([relabel[normalize_hughes_plane_point(p,q)] for p in l])
            for i in range(q2 + q):
                l = [A*j for j in l]
                blcks.append([relabel[normalize_hughes_plane_point(p,q)] for p in l])
    from bibd import BalancedIncompleteBlockDesign
    return BalancedIncompleteBlockDesign(q2**2+q2+1, blcks, check=check)
コード例 #5
0
ファイル: block_design.py プロジェクト: aaditya-thakkar/sage
def DesarguesianProjectivePlaneDesign(n, point_coordinates=True, check=True):
    r"""
    Return the Desarguesian projective plane of order ``n`` as a 2-design.

    The Desarguesian projective plane of order `n` can also be defined as the
    projective plane over a field of order `n`. For more information, have a
    look at :wikipedia:`Projective_plane`.

    INPUT:

    - ``n`` -- an integer which must be a power of a prime number

    - ``point_coordinates`` (boolean) -- whether to label the points with their
      homogeneous coordinates (default) or with integers.

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

    .. SEEALSO::

        :func:`ProjectiveGeometryDesign`

    EXAMPLES::

        sage: designs.DesarguesianProjectivePlaneDesign(2)
        (7,3,1)-Balanced Incomplete Block Design
        sage: designs.DesarguesianProjectivePlaneDesign(3)
        (13,4,1)-Balanced Incomplete Block Design
        sage: designs.DesarguesianProjectivePlaneDesign(4)
        (21,5,1)-Balanced Incomplete Block Design
        sage: designs.DesarguesianProjectivePlaneDesign(5)
        (31,6,1)-Balanced Incomplete Block Design
        sage: designs.DesarguesianProjectivePlaneDesign(6)
        Traceback (most recent call last):
        ...
        ValueError: the order of a finite field must be a prime power

    """
    K = FiniteField(n, 'a')
    n2 = n**2
    relabel = {x:i for i,x in enumerate(K)}
    Kiter = relabel  # it is much faster to iterate throug a dict than through
                     # the finite field K

    # we decompose the (equivalence class) of points [x:y:z] of the projective
    # plane into an affine plane, an affine line and a point. At the same time,
    # we relabel the points with the integers from 0 to n^2 + n as follows:
    # - the affine plane is the set of points [x:y:1] (i.e. the third coordinate
    #   is non-zero) and gets relabeled from 0 to n^2-1
    affine_plane   = lambda x,y: relabel[x] + n * relabel[y]

    # - the affine line is the set of points [x:1:0] (i.e. the third coordinate is
    #   zero but not the second one) and gets relabeld from n^2 to n^2 + n - 1
    line_infinity  = lambda x: n2 + relabel[x]

    # - the point is [1:0:0] and gets relabeld n^2 + n
    point_infinity = n2 + n

    blcks = []

    # the n^2 lines of the form "x = sy + az"
    for s in Kiter:
        for a in Kiter:
            # points in the affine plane
            blcks.append([affine_plane(s*y+a, y) for y in Kiter])
            # point at infinity
            blcks[-1].append(line_infinity(s))

    # the n horizontals of the form "y = az"
    for a in Kiter:
        # points in the affine plane
        blcks.append([affine_plane(x,a) for x in Kiter])
        # point at infinity
        blcks[-1].append(point_infinity)

    # the line at infinity "z = 0"
    blcks.append(range(n2,n2+n+1))
    if check:
        from designs_pyx import is_projective_plane
        if not is_projective_plane(blcks):
            raise RuntimeError('There is a problem in the function DesarguesianProjectivePlane')
    from bibd import BalancedIncompleteBlockDesign
    B = BalancedIncompleteBlockDesign(n2+n+1, blcks, check=check)

    if point_coordinates:
        zero = K.zero()
        one  = K.one()
        d = {affine_plane(x,y): (x,y,one)
             for x in Kiter
             for y in Kiter}
        d.update({line_infinity(x): (x,one,zero)
                  for x in Kiter})
        d[n2+n]=(one,zero,zero)
        B.relabel(d)

    return B
コード例 #6
0
ファイル: block_design.py プロジェクト: bopopescu/Sage-8
def HughesPlane(q2, check=True):
    r"""
    Return the Hughes projective plane of order ``q2``.

    Let `q` be an odd prime, the Hughes plane of order `q^2` is a finite
    projective plane of order `q^2` introduced by D. Hughes in [Hu57]_. Its
    construction is as follows.

    Let `K = GF(q^2)` be a finite field with `q^2` elements and `F = GF(q)
    \subset K` be its unique subfield with `q` elements. We define a twisted
    multiplication on `K` as

    .. MATH::

        x \circ y =
        \begin{cases}
        x\ y & \text{if y is a square in K}\\
        x^q\ y & \text{otherwise}
        \end{cases}

    The points of the Hughes plane are the triples `(x, y, z)` of points in `K^3
    \backslash \{0,0,0\}` up to the equivalence relation `(x,y,z) \sim (x \circ
    k, y \circ k, z \circ k)` where `k \in K`.

    For `a = 1` or `a \in (K \backslash F)` we define a block `L(a)` as the set of
    triples `(x,y,z)` so that `x + a \circ y + z = 0`. The rest of the blocks
    are obtained by letting act the group `GL(3, F)` by its standard action.

    For more information, see :wikipedia:`Hughes_plane` and [We07].

    .. SEEALSO::

        :func:`DesarguesianProjectivePlaneDesign` to build the Desarguesian
        projective planes

    INPUT:

    - ``q2`` -- an even power of an odd prime number

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

    EXAMPLES::

        sage: H = designs.HughesPlane(9)
        sage: H
        (91,10,1)-Balanced Incomplete Block Design

    We prove in the following computations that the Desarguesian plane ``H`` is
    not Desarguesian. Let us consider the two triangles `(0,1,10)` and `(57, 70,
    59)`. We show that the intersection points `D_{0,1} \cap D_{57,70}`,
    `D_{1,10} \cap D_{70,59}` and `D_{10,0} \cap D_{59,57}` are on the same line
    while `D_{0,70}`, `D_{1,59}` and `D_{10,57}` are not concurrent::

        sage: blocks = H.blocks()
        sage: line = lambda p,q: (b for b in blocks if p in b and q in b).next()

        sage: b_0_1 = line(0, 1)
        sage: b_1_10 = line(1, 10)
        sage: b_10_0 = line(10, 0)
        sage: b_57_70 = line(57, 70)
        sage: b_70_59 = line(70, 59)
        sage: b_59_57 = line(59, 57)

        sage: set(b_0_1).intersection(b_57_70)
        {2}
        sage: set(b_1_10).intersection(b_70_59)
        {73}
        sage: set(b_10_0).intersection(b_59_57)
        {60}

        sage: line(2, 73) == line(73, 60)
        True

        sage: b_0_57 = line(0, 57)
        sage: b_1_70 = line(1, 70)
        sage: b_10_59 = line(10, 59)

        sage: p = set(b_0_57).intersection(b_1_70)
        sage: q = set(b_1_70).intersection(b_10_59)
        sage: p == q
        False

    TESTS:

    Some wrong input::

        sage: designs.HughesPlane(5)
        Traceback (most recent call last):
        ...
        EmptySetError: No Hughes plane of non-square order exists.

        sage: designs.HughesPlane(16)
        Traceback (most recent call last):
        ...
        EmptySetError: No Hughes plane of even order exists.

    Check that it works for non-prime `q`::

        sage: designs.HughesPlane(3**4)    # not tested - 10 secs
        (6643,82,1)-Balanced Incomplete Block Design
    """
    if not q2.is_square():
        raise EmptySetError("No Hughes plane of non-square order exists.")
    if q2 % 2 == 0:
        raise EmptySetError("No Hughes plane of even order exists.")
    q = q2.sqrt()
    K = FiniteField(q2, prefix='x', conway=True)
    F = FiniteField(q, prefix='y', conway=True)
    A = q3_minus_one_matrix(F)
    A = A.change_ring(K)
    m = K.list()
    V = VectorSpace(K, 3)
    zero = K.zero()
    one = K.one()
    points = [(x, y, one) for x in m for y in m] + \
             [(x, one, zero) for x in m] + \
             [(one, zero, zero)]
    relabel = {tuple(p): i for i, p in enumerate(points)}
    blcks = []
    for a in m:
        if a not in F or a == 1:
            # build L(a)
            aa = ~a
            l = []
            l.append(V((-a, one, zero)))
            for x in m:
                y = -aa * (x + one)
                if not y.is_square():
                    y *= aa**(q - 1)
                l.append(V((x, y, one)))
            # compute the orbit of L(a)
            blcks.append(
                [relabel[normalize_hughes_plane_point(p, q)] for p in l])
            for i in range(q2 + q):
                l = [A * j for j in l]
                blcks.append(
                    [relabel[normalize_hughes_plane_point(p, q)] for p in l])
    from bibd import BalancedIncompleteBlockDesign
    return BalancedIncompleteBlockDesign(q2**2 + q2 + 1, blcks, check=check)
コード例 #7
0
def DesarguesianProjectivePlaneDesign(n, point_coordinates=True, check=True):
    r"""
    Return the Desarguesian projective plane of order ``n`` as a 2-design.

    The Desarguesian projective plane of order `n` can also be defined as the
    projective plane over a field of order `n`. For more information, have a
    look at :wikipedia:`Projective_plane`.

    INPUT:

    - ``n`` -- an integer which must be a power of a prime number

    - ``point_coordinates`` (boolean) -- whether to label the points with their
      homogeneous coordinates (default) or with integers.

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

    .. SEEALSO::

        :func:`ProjectiveGeometryDesign`

    EXAMPLES::

        sage: designs.DesarguesianProjectivePlaneDesign(2)
        (7,3,1)-Balanced Incomplete Block Design
        sage: designs.DesarguesianProjectivePlaneDesign(3)
        (13,4,1)-Balanced Incomplete Block Design
        sage: designs.DesarguesianProjectivePlaneDesign(4)
        (21,5,1)-Balanced Incomplete Block Design
        sage: designs.DesarguesianProjectivePlaneDesign(5)
        (31,6,1)-Balanced Incomplete Block Design
        sage: designs.DesarguesianProjectivePlaneDesign(6)
        Traceback (most recent call last):
        ...
        ValueError: the order of a finite field must be a prime power

    """
    K = FiniteField(n, 'a')
    n2 = n**2
    relabel = {x: i for i, x in enumerate(K)}
    Kiter = relabel  # it is much faster to iterate throug a dict than through
    # the finite field K

    # we decompose the (equivalence class) of points [x:y:z] of the projective
    # plane into an affine plane, an affine line and a point. At the same time,
    # we relabel the points with the integers from 0 to n^2 + n as follows:
    # - the affine plane is the set of points [x:y:1] (i.e. the third coordinate
    #   is non-zero) and gets relabeled from 0 to n^2-1
    affine_plane = lambda x, y: relabel[x] + n * relabel[y]

    # - the affine line is the set of points [x:1:0] (i.e. the third coordinate is
    #   zero but not the second one) and gets relabeld from n^2 to n^2 + n - 1
    line_infinity = lambda x: n2 + relabel[x]

    # - the point is [1:0:0] and gets relabeld n^2 + n
    point_infinity = n2 + n

    blcks = []

    # the n^2 lines of the form "x = sy + az"
    for s in Kiter:
        for a in Kiter:
            # points in the affine plane
            blcks.append([affine_plane(s * y + a, y) for y in Kiter])
            # point at infinity
            blcks[-1].append(line_infinity(s))

    # the n horizontals of the form "y = az"
    for a in Kiter:
        # points in the affine plane
        blcks.append([affine_plane(x, a) for x in Kiter])
        # point at infinity
        blcks[-1].append(point_infinity)

    # the line at infinity "z = 0"
    blcks.append(range(n2, n2 + n + 1))
    if check:
        from designs_pyx import is_projective_plane
        if not is_projective_plane(blcks):
            raise RuntimeError(
                'There is a problem in the function DesarguesianProjectivePlane'
            )
    from bibd import BalancedIncompleteBlockDesign
    B = BalancedIncompleteBlockDesign(n2 + n + 1, blcks, check=check)

    if point_coordinates:
        zero = K.zero()
        one = K.one()
        d = {affine_plane(x, y): (x, y, one) for x in Kiter for y in Kiter}
        d.update({line_infinity(x): (x, one, zero) for x in Kiter})
        d[n2 + n] = (one, zero, zero)
        B.relabel(d)

    return B