コード例 #1
0
    def __init__(self, field=None):
        """
        Create a linear feedback shift cryptosystem.

        INPUT: A string monoid over a binary alphabet.

        OUTPUT:

        EXAMPLES::

            sage: E = LFSRCryptosystem(FiniteField(2))
            sage: E
            LFSR cryptosystem over Finite Field of size 2

        TESTS::

            sage: E = LFSRCryptosystem(FiniteField(2))
            sage: E == loads(dumps(E))
            True

        TODO: Implement LFSR cryptosystem for arbitrary rings. The current
        implementation is limited to the finite field of 2 elements only
        because of the dependence on binary strings.
        """
        if field is None:
            field = FiniteField(2)
        if field.cardinality() != 2:
            raise NotImplementedError("Not yet implemented.")
        S = BinaryStrings()
        P = PolynomialRing(FiniteField(2), 'x')
        SymmetricKeyCryptosystem.__init__(self, S, S, None)
        self._field = field
コード例 #2
0
def twin_prime_powers_difference_set(p, check=True):
    r"""
    Return a difference set on `GF(p) \times GF(p+2)`.

    The difference set is built from the following element of the cartesian
    product of finite fields `GF(p) \times GF(p+2)`:

    - `(x,0)` with any `x`
    - `(x,y)` with `x` and `y` squares
    - `(x,y)` with `x` and `y` non-squares

    For more information see :wikipedia:`Difference_set`.

    INPUT:

    - ``check`` -- boolean (default: ``True``). If ``True`` then the result of
      the computation is checked before being returned. This should not be
      needed but ensures that the output is correct.

    EXAMPLES::

        sage: from sage.combinat.designs.difference_family import twin_prime_powers_difference_set
        sage: G,D = twin_prime_powers_difference_set(3)
        sage: G
        The cartesian product of (Finite Field of size 3, Finite Field of size 5)
        sage: D
        [[(1, 1), (1, 4), (2, 2), (2, 3), (0, 0), (1, 0), (2, 0)]]
    """
    from sage.rings.finite_rings.constructor import FiniteField
    from sage.categories.cartesian_product import cartesian_product
    from itertools import product
    Fp = FiniteField(p, 'x')
    Fq = FiniteField(p + 2, 'x')
    Fpset = set(Fp)
    Fqset = set(Fq)
    Fp_squares = set(x**2 for x in Fpset)
    Fq_squares = set(x**2 for x in Fqset)

    # Pairs of squares, pairs of non-squares
    d = []
    d.extend(product(Fp_squares.difference([0]), Fq_squares.difference([0])))
    d.extend(
        product(Fpset.difference(Fp_squares), Fqset.difference(Fq_squares)))

    # All (x,0)
    d.extend((x, 0) for x in Fpset)

    G = cartesian_product([Fp, Fq])

    if check and not is_difference_family(G, [d]):
        raise RuntimeError("twin_prime_powers_difference_set produced a wrong "
                           "difference set with p={}. Please contact "
                           "*****@*****.**".format(p))

    return G, [d]
コード例 #3
0
    def __init__(self, p, use_database=True):
        """
        TESTS::

            sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice
            sage: PCL = PseudoConwayLattice(3)
            sage: PCL.polynomial(3)
            x^3 + 2*x + 1

            sage: PCL = PseudoConwayLattice(5, use_database=False)
            sage: PCL.polynomial(12)
            x^12 + 2*x^11 + x^10 + 4*x^9 + 4*x^8 + 4*x^7 + x^6 + 4*x^5 + x^4 + 3*x + 2
            sage: PCL.polynomial(6)
            x^6 + x^5 + 4*x^4 + 3*x^3 + 3*x^2 + 2*x + 2
            sage: PCL.polynomial(11)
            x^11 + x^6 + 3*x^3 + 4*x + 3
        """
        self.p = p
        from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
        self.ring = PolynomialRing(FiniteField(p), 'x')
        if use_database:
            C = sage.databases.conway.ConwayPolynomials()
            self.nodes = {n: self.ring(C.polynomial(p, n))
                          for n in C.degrees(p)}
        else:
            self.nodes = {}
コード例 #4
0
    def __classcall__(cls, *args, **kwds):
        """
        Normalize input to ensure a unique representation.

        EXAMPLES::

            sage: A = AffineSpace(2, GF(4,'a'))
            sage: AffineGroup(A) is AffineGroup(2,4)
            True
            sage: AffineGroup(A) is AffineGroup(2, GF(4,'a'))
            True
            sage: A = AffineGroup(2, QQ)
            sage: V = QQ^2
            sage: A is AffineGroup(V)
            True
        """
        if len(args) == 1:
            V = args[0]
            if isinstance(V, AffineGroup):
                return V
            try:
                degree = V.dimension_relative()
            except AttributeError:
                degree = V.dimension()
            ring = V.base_ring()
        if len(args) == 2:
            degree, ring = args
            from sage.rings.integer import is_Integer
            if is_Integer(ring):
                from sage.rings.finite_rings.constructor import FiniteField
                var = kwds.get('var', 'a')
                ring = FiniteField(ring, var)
        return super(AffineGroup, cls).__classcall__(cls, degree, ring)
コード例 #5
0
def QuaternionMatrixGroupGF3():
    r"""
    The quaternion group as a set of `2\times 2` matrices over `GF(3)`.

    OUTPUT:

    A matrix group consisting of `2\times 2` matrices with
    elements from the finite field of order 3.  The group is
    the quaternion group, the nonabelian group of order 8 that
    is not isomorphic to the group of symmetries of a square
    (the dihedral group `D_4`).

    .. note::
        This group is most easily available via ``groups.matrix.QuaternionGF3()``.

    EXAMPLES:

    The generators are the matrix representations of the
    elements commonly called `I` and `J`, while `K`
    is the product of `I` and `J`. ::

        sage: from sage.groups.misc_gps.misc_groups import QuaternionMatrixGroupGF3
        sage: Q = QuaternionMatrixGroupGF3()
        sage: Q.order()
        8
        sage: aye = Q.gens()[0]; aye
        [1 1]
        [1 2]
        sage: jay = Q.gens()[1]; jay
        [2 1]
        [1 1]
        sage: kay = aye*jay; kay
        [0 2]
        [1 0]

    TESTS::

        sage: groups.matrix.QuaternionGF3()
        Matrix group over Finite Field of size 3 with 2 generators:
            [[[1, 1], [1, 2]], [[2, 1], [1, 1]]]

        sage: Q = QuaternionMatrixGroupGF3()
        sage: QP = Q.as_permutation_group()
        sage: QP.is_isomorphic(QuaternionGroup())
        True
        sage: H = DihedralGroup(4)
        sage: H.order()
        8
        sage: QP.is_abelian(), H.is_abelian()
        (False, False)
        sage: QP.is_isomorphic(H)
        False
    """
    from sage.rings.finite_rings.constructor import FiniteField
    from sage.matrix.matrix_space import MatrixSpace
    from sage.groups.matrix_gps.matrix_group import MatrixGroup
    MS = MatrixSpace(FiniteField(3), 2)
    aye = MS([1,1,1,2])
    jay = MS([2,1,1,1])
    return MatrixGroup([aye, jay])
コード例 #6
0
    def __init__(self, n):
        """
        Args:
            n (int): The number of elements in the finite field.
        """

        f = FiniteField(n)
        operations = {'+': lambda x, y: x + y, '*': lambda x, y: x * y}
        AlgebraicStructure.__init__(self, set(f), operations)
コード例 #7
0
    def test_generic_02(self):

        F = FiniteField(2**8, 'a')
        shares = [(1, 1), (2, 121), (3, 97), (4, 77), (5, 29)]
        points = [(F.fetch_int(x), F.fetch_int(y)) for x, y in shares]
        p = berlekamp_welsh(5, points)
        print(p)
        print([coeff.integer_representation() for coeff in p])
        print(map(lambda x: x.integer_representation(), p))
コード例 #8
0
ファイル: gap.py プロジェクト: thalespaiva/sagelib
def gfq_gap_to_sage(x, F):
    """
    INPUT:
    
    
    -  ``x`` - gap finite field element
    
    -  ``F`` - Sage finite field
    
    
    OUTPUT: element of F
    
    EXAMPLES::
    
        sage: x = gap('Z(13)')
        sage: F = GF(13, 'a')
        sage: F(x)
        2
        sage: F(gap('0*Z(13)'))
        0
        sage: F = GF(13^2, 'a')
        sage: x = gap('Z(13)')
        sage: F(x)
        2
        sage: x = gap('Z(13^2)^3')
        sage: F(x)
        12*a + 11
        sage: F.multiplicative_generator()^3
        12*a + 11
    
    AUTHOR:

    - David Joyner and William Stein
    """
    from sage.rings.finite_rings.constructor import FiniteField

    s = str(x)
    if s[:2] == '0*':
        return F(0)
    i1 = s.index("(")
    i2 = s.index(")")
    q = eval(s[i1 + 1:i2].replace('^', '**'))
    if q == F.order():
        K = F
    else:
        K = FiniteField(q, F.variable_name())
    if s.find(')^') == -1:
        e = 1
    else:
        e = int(s[i2 + 2:])
    if F.degree() == 1:
        g = int(gap.eval('Int(Z(%s))' % q))
    else:
        g = K.multiplicative_generator()
    return F(K(g**e))
コード例 #9
0
    def test_generic_01(self):

        F = FiniteField(2**8, 'a')

        #shares = [(1, 22), (2, 82), (3, 110), (4, 218), (5, 230)]
        points = [(1, 22), (2, 82), (3, 110), (4, 219)]
        points = [(F.fetch_int(x), F.fetch_int(y)) for x, y in shares]
        p = berlekamp_welsh(1, points)
        pint = ([coeff.integer_representation() for coeff in p])
        #pint = (map(lambda x: x.integer_representation(), p))
        print(p, pint)
        assert [42, 60] == pint
コード例 #10
0
    def test_01(self):
        order = 2**8
        F = FiniteField(order, 'a')
        P = PolynomialRing(F, 'x')
        n = 7
        deg = 2
        poly = F.fetch_int(42)
        for i in range(1, deg + 1):
            poly += F.random_element() * P.gen()**i

        # evaluate polynomial at different points (shares)
        print(poly)
        points = [(F.fetch_int(i), poly(F.fetch_int(i)))
                  for i in range(1, n + 1)]
        points[0] = (points[0][0], points[0][1] + F.fetch_int(9))
        print(points)
        assert poly == berlekamp_welsh(deg, points)
コード例 #11
0
def conway_polynomial(p, n):
    """
    Return the Conway polynomial of degree `n` over ``GF(p)``.

    If the requested polynomial is not known, this function raises a
    ``RuntimeError`` exception.

    INPUT:

    - ``p`` -- prime number

    - ``n`` -- positive integer

    OUTPUT:

    - the Conway polynomial of degree `n` over the finite field
      ``GF(p)``, loaded from a table.

    .. NOTE::

       The first time this function is called a table is read from
       disk, which takes a fraction of a second. Subsequent calls do
       not require reloading the table.

    See also the ``ConwayPolynomials()`` object, which is the table of
    Conway polynomials used by this function.

    EXAMPLES::

        sage: conway_polynomial(2,5)
        x^5 + x^2 + 1
        sage: conway_polynomial(101,5)
        x^5 + 2*x + 99
        sage: conway_polynomial(97,101)
        Traceback (most recent call last):
        ...
        RuntimeError: requested Conway polynomial not in database.
    """
    (p, n) = (int(p), int(n))
    R = FiniteField(p)['x']
    try:
        return R(sage.databases.conway.ConwayPolynomials()[p][n])
    except KeyError:
        raise RuntimeError("requested Conway polynomial not in database.")
コード例 #12
0
    def check_consistency(self, n):
        """
        Check that the pseudo-Conway polynomials of degree dividing
        `n` in this lattice satisfy the required compatibility
        conditions.

        EXAMPLES::

            sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice
            sage: PCL = PseudoConwayLattice(2, use_database=False)
            sage: PCL.check_consistency(6)
            sage: PCL.check_consistency(60)  # long

        """
        p = self.p
        K = FiniteField(p**n, modulus = self.polynomial(n), names='a')
        a = K.gen()
        for m in n.divisors():
            assert (a**((p**n-1)//(p**m-1))).minimal_polynomial() == self.polynomial(m)
コード例 #13
0
    def _subfield(self, n):
        """
        Return the unique subfield of degree `n` of ``self``.

        EXAMPLES::

            sage: F = GF(3).algebraic_closure()
            sage: F._subfield(4)
            Finite Field in z4 of size 3^4

        """
        if n == 1:
            return self.base_ring()
        else:
            from sage.rings.finite_rings.constructor import FiniteField
            return FiniteField(self.base_ring().cardinality()**n,
                               name=self.variable_name() + str(n),
                               modulus=self._get_polynomial(n),
                               check_irreducible=False)
コード例 #14
0
def BIBD_5q_5_for_q_prime_power(q):
    r"""
    Returns 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.arith import is_prime_power
    from sage.rings.finite_rings.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
コード例 #15
0
    def __init__(self, field=None):
        """
        Create a shrinking generator cryptosystem.

        INPUT: A string monoid over a binary alphabet.

        OUTPUT:

        EXAMPLES::

            sage: E = ShrinkingGeneratorCryptosystem()
            sage: E
            Shrinking generator cryptosystem over Finite Field of size 2
        """
        if field is None:
            field = FiniteField(2)
        if field.cardinality() != 2:
            raise NotImplementedError("Not yet implemented.")
        S = BinaryStrings()
        P = PolynomialRing(field, 'x')
        SymmetricKeyCryptosystem.__init__(self, S, S, None)
        self._field = field
コード例 #16
0
    def polynomial(self, name=None):
        """
        Returns the polynomial ``name``.

        EXAMPLES::

            sage: k.<a> = GF(3)
            sage: k.polynomial()
            x
        """
        if name is None:
            name = self.variable_name()
        try:
            return self.__polynomial[name]
        except  AttributeError:
            from sage.rings.finite_rings.constructor import FiniteField
            R = FiniteField(self.characteristic())[name]
            f = self[name]([0,1])
            try:
                self.__polynomial[name] = f
            except (KeyError, AttributeError):
                self.__polynomial = {}
                self.__polynomial[name] = f
            return f
コード例 #17
0
    def __init__(self, n=7, k=3, order=2**8):
        r"""
        Sharmir secret sharing.

        EXAMPLES::

            sage: from sage.crypto.smc.shamir_ss import ShamirSS
            sage: sss = ShamirSS()
            sage: secret = 42
            sage: shares = sss.share(secret)
            sage: secret == sss.reconstruct(shares)
            True
        """
        self._k = k  # threshold
        self._n = n  # number shares
        self._order = order  # order of field

        from sage.rings.finite_rings.constructor import FiniteField
        self._F = FiniteField(self._order, 'a')
        if not self._F.is_prime_field() and not hasattr(self._F, 'fetch_int'):
            raise TypeError("field order not supported")

        from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
        self._P = PolynomialRing(self._F, 'x')
コード例 #18
0
    #print "r =", r
    #print "ss=", ss
    #print "rr=", rr
    #print "-----------------"

    assert r == s and m == ss and m == rr, "ERROR!!!"


### main
def parseargs():
    """ Parse the commandline arguments
    """
    parser = argparse.ArgumentParser(description='')
    parser.add_argument('-m', '--manual', action='store_true',
                        help='Run test cases manually.')
    return parser.parse_args()


if __name__ == '__main__':
    args = parseargs()

    F = FiniteField(7)
    simple_test(F, 6, 3)

    F = FiniteField(257)
    simple_test(F, 4, 3)
    simple_test(F, 256, 90)

    F = FiniteField(256, 'a')
    simple_test(F, 15, 7)
コード例 #19
0
def difference_family(v, k, l=1, existence=False, check=True):
    r"""
    Return a (``k``, ``l``)-difference family on an Abelian group of cardinality ``v``.

    Let `G` be a finite Abelian group. For a given subset `D` of `G`, we define
    `\Delta D` to be the multi-set of differences `\Delta D = \{x - y; x \in D,
    y \in D, x \not= y\}`. A `(G,k,\lambda)`-*difference family* is a collection
    of `k`-subsets of `G`, `D = \{D_1, D_2, \ldots, D_b\}` such that the union
    of the difference sets `\Delta D_i` for `i=1,...b`, seen as a multi-set,
    contains each element of `G \backslash \{0\}` exactly `\lambda`-times.

    When there is only one block, i.e. `\lambda(v - 1) = k(k-1)`, then a
    `(G,k,\lambda)`-difference family is also called a *difference set*.

    See also :wikipedia:`Difference_set`.

    If there is no such difference family, an ``EmptySetError`` is raised and if
    there is no construction at the moment ``NotImplementedError`` is raised.

    EXAMPLES::

        sage: K,D = designs.difference_family(73,4)
        sage: D
        [[0, 1, 8, 64],
         [0, 25, 54, 67],
         [0, 41, 36, 69],
         [0, 3, 24, 46],
         [0, 2, 16, 55],
         [0, 50, 35, 61]]

        sage: K,D = designs.difference_family(337,7)
        sage: D
        [[1, 175, 295, 64, 79, 8, 52],
         [326, 97, 125, 307, 142, 249, 102],
         [121, 281, 310, 330, 123, 294, 226],
         [17, 279, 297, 77, 332, 136, 210],
         [150, 301, 103, 164, 55, 189, 49],
         [35, 59, 215, 218, 69, 280, 135],
         [289, 25, 331, 298, 252, 290, 200],
         [191, 62, 66, 92, 261, 180, 159]]

    For `k=6,7` we look at the set of small prime powers for which a
    construction is available::

        sage: def prime_power_mod(r,m):
        ....:     k = m+r
        ....:     while True:
        ....:         if is_prime_power(k):
        ....:             yield k
        ....:         k += m

        sage: from itertools import islice
        sage: l6 = {True:[], False: [], Unknown: []}
        sage: for q in islice(prime_power_mod(1,30), 60):
        ....:     l6[designs.difference_family(q,6,existence=True)].append(q)
        sage: l6[True]
        [31, 121, 151, 181, 211, ...,  3061, 3121, 3181]
        sage: l6[Unknown]
        [61]
        sage: l6[False]
        []

        sage: l7 = {True: [], False: [], Unknown: []}
        sage: for q in islice(prime_power_mod(1,42), 60):
        ....:     l7[designs.difference_family(q,7,existence=True)].append(q)
        sage: l7[True]
        [337, 421, 463, 883, 1723, 3067, 3319, 3529, 3823, 3907, 4621, 4957, 5167]
        sage: l7[Unknown]
        [43, 127, 169, 211, ..., 4999, 5041, 5209]
        sage: l7[False]
        []

    Other constructions for `\lambda > 1`::

        sage: for v in xrange(2,100):
        ....:     constructions = []
        ....:     for k in xrange(2,10):
        ....:         for l in xrange(2,10):
        ....:             if designs.difference_family(v,k,l,existence=True):
        ....:                 constructions.append((k,l))
        ....:                 _ = designs.difference_family(v,k,l)
        ....:     if constructions:
        ....:         print "%2d: %s"%(v, ', '.join('(%d,%d)'%(k,l) for k,l in constructions))
         2: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
         3: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
         4: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
         5: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
         7: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
         8: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
         9: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        11: (3,2), (4,3), (4,6), (5,2), (5,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        13: (3,2), (4,3), (5,4), (5,5), (6,5), (7,6), (8,7), (9,8)
        15: (4,6), (5,6), (7,3)
        16: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        17: (3,2), (4,3), (5,4), (5,5), (6,5), (7,6), (8,7), (9,8)
        19: (3,2), (4,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,4), (9,5), (9,6), (9,7), (9,8)
        21: (4,3), (6,3), (6,5)
        22: (4,2), (6,5), (7,4), (8,8)
        23: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        25: (3,2), (4,3), (5,4), (6,5), (7,6), (7,7), (8,7), (9,8)
        27: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        28: (3,2), (6,5)
        29: (3,2), (4,3), (5,4), (6,5), (7,3), (7,6), (8,4), (8,6), (8,7), (9,8)
        31: (3,2), (4,2), (4,3), (5,2), (5,4), (6,5), (7,6), (8,7), (9,8)
        32: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        33: (5,5), (6,5)
        34: (4,2)
        35: (5,2), (8,4)
        37: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,2), (9,3), (9,8)
        39: (6,5)
        40: (3,2)
        41: (3,2), (4,3), (5,4), (6,3), (6,5), (7,6), (8,7), (9,8)
        43: (3,2), (4,2), (4,3), (5,4), (6,5), (7,2), (7,3), (7,6), (8,4), (8,7), (9,8)
        46: (4,2), (6,2)
        47: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        49: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,3), (9,8)
        51: (5,2), (6,3)
        53: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        55: (9,4)
        57: (7,3)
        59: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        61: (3,2), (4,3), (5,4), (6,2), (6,3), (6,5), (7,6), (8,7), (9,8)
        64: (3,2), (4,3), (5,4), (6,5), (7,2), (7,6), (8,7), (9,8)
        67: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        71: (3,2), (4,3), (5,2), (5,4), (6,5), (7,3), (7,6), (8,4), (8,7), (9,8)
        73: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        75: (5,2)
        79: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        81: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        83: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        85: (7,2), (7,3), (8,2)
        89: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        97: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,3), (9,8)

    TESTS:

    Check more of the Wilson constructions from [Wi72]_::

        sage: Q5 = [241, 281,421,601,641, 661, 701, 821,881]
        sage: Q9 = [73, 1153, 1873, 2017]
        sage: Q15 = [76231]
        sage: Q4 = [13, 73, 97, 109, 181, 229, 241, 277, 337, 409, 421, 457]
        sage: Q8 = [1009, 3137, 3697]
        sage: for Q,k in [(Q4,4),(Q5,5),(Q8,8),(Q9,9),(Q15,15)]:
        ....:     for q in Q:
        ....:         assert designs.difference_family(q,k,1,existence=True) is True
        ....:         _ = designs.difference_family(q,k,1)

    Check Singer difference sets::

        sage: sgp = lambda q,d: ((q**(d+1)-1)//(q-1), (q**d-1)//(q-1), (q**(d-1)-1)//(q-1))

        sage: for q in range(2,10):
        ....:     if is_prime_power(q):
        ....:         for d in [2,3,4]:
        ....:           v,k,l = sgp(q,d)
        ....:           assert designs.difference_family(v,k,l,existence=True) is True
        ....:           _ = designs.difference_family(v,k,l)

    Check twin primes difference sets::

        sage: for p in [3,5,7,9,11]:
        ....:     v = p*(p+2); k = (v-1)/2;  lmbda = (k-1)/2
        ....:     G,D = designs.difference_family(v,k,lmbda)

    Check the database:

        sage: from sage.combinat.designs.database import DF
        sage: for v,k,l in DF:
        ....:     df = designs.difference_family(v,k,l,check=True)

    .. TODO::

        Implement recursive constructions from Buratti "Recursive for difference
        matrices and relative difference families" (1998) and Jungnickel
        "Composition theorems for difference families and regular planes" (1978)
    """
    from block_design import are_hyperplanes_in_projective_geometry_parameters

    from database import DF

    if (v, k, l) in DF:
        if existence:
            return True

        vv, blocks = DF[v, k, l].iteritems().next()

        # Build the group
        from sage.rings.finite_rings.integer_mod_ring import Zmod
        if len(vv) == 1:
            G = Zmod(vv[0])
        else:
            from sage.categories.cartesian_product import cartesian_product
            G = cartesian_product([Zmod(i) for i in vv])

        df = [[G(i) for i in b] for b in blocks]

        if check:
            assert is_difference_family(
                G, df, v=v, k=k,
                l=l), "Sage built an invalid ({},{},{})-DF!".format(v, k, l)

        return G, df

    e = k * (k - 1)
    t = l * (v - 1) // e  # number of blocks

    D = None

    factorization = arith.factor(v)

    if len(factorization) == 1:  # i.e. is v a prime power
        from sage.rings.finite_rings.constructor import GF
        G = K = GF(v, 'z')
        x = K.multiplicative_generator()

        if l == (k - 1):
            if existence:
                return True
            return K, K.cyclotomic_cosets(x**((v - 1) // k))[1:]

        if t == 1:
            # some of the difference set constructions VI.18.48 from the
            # Handbook of combinatorial designs
            # q = 3 mod 4
            if v % 4 == 3 and k == (v - 1) // 2:
                if existence:
                    return True
                D = K.cyclotomic_cosets(x**2, [1])

            # q = 4t^2 + 1, t odd
            elif v % 8 == 5 and k == (v - 1) // 4 and arith.is_square(
                (v - 1) // 4):
                if existence:
                    return True
                D = K.cyclotomic_cosets(x**4, [1])

            # q = 4t^2 + 9, t odd
            elif v % 8 == 5 and k == (v + 3) // 4 and arith.is_square(
                (v - 9) // 4):
                if existence:
                    return True
                D = K.cyclotomic_cosets(x**4, [1])
                D[0].insert(0, K.zero())

        if D is None and l == 1:
            one = K.one()

            # Wilson (1972), Theorem 9
            if k % 2 == 1:
                m = (k - 1) // 2
                xx = x**m
                to_coset = {
                    x**i * xx**j: i
                    for i in xrange(m) for j in xrange((v - 1) / m)
                }
                r = x**((v - 1) // k)  # primitive k-th root of unity
                if len(set(to_coset[r**j - one]
                           for j in xrange(1, m + 1))) == m:
                    if existence:
                        return True
                    B = [r**j for j in xrange(k)
                         ]  # = H^((k-1)t) whose difference is
                    # H^(mt) (r^i - 1, i=1,..,m)
                    # Now pick representatives a translate of R for by a set of
                    # representatives of H^m / H^(mt)
                    D = [[x**(i * m) * b for b in B] for i in xrange(t)]

            # Wilson (1972), Theorem 10
            else:
                m = k // 2
                xx = x**m
                to_coset = {
                    x**i * xx**j: i
                    for i in xrange(m) for j in xrange((v - 1) / m)
                }
                r = x**((v - 1) // (k - 1))  # primitive (k-1)-th root of unity
                if (all(to_coset[r**j - one] != 0 for j in xrange(1, m))
                        and len(set(to_coset[r**j - one]
                                    for j in xrange(1, m))) == m - 1):
                    if existence:
                        return True
                    B = [K.zero()] + [r**j for j in xrange(k - 1)]
                    D = [[x**(i * m) * b for b in B] for i in xrange(t)]

            # Wilson (1972), Theorem 11
            if D is None and k == 6:
                r = x**((v - 1) // 3)  # primitive cube root of unity
                r2 = r * r
                xx = x**5
                to_coset = {
                    x**i * xx**j: i
                    for i in xrange(5) for j in xrange((v - 1) / 5)
                }
                for c in to_coset:
                    if c == 1 or c == r or c == r2:
                        continue
                    if len(
                            set(to_coset[elt]
                                for elt in (r - 1, c * (r - 1), c - 1, c - r,
                                            c - r**2))) == 5:
                        if existence:
                            return True
                        B = [one, r, r**2, c, c * r, c * r**2]
                        D = [[x**(i * 5) * b for b in B] for i in xrange(t)]
                        break

    # Twin prime powers construction (see :wikipedia:`Difference_set`)
    #
    # i.e. v = p(p+2) where p and p+2 are prime powers
    #      k = (v-1)/2
    #      lambda = (k-1)/2
    elif (len(factorization) == 2
          and abs(pow(*factorization[0]) - pow(*factorization[1])) == 2
          and k == (v - 1) // 2 and (l is None or 2 * l == (v - 1) // 2 - 1)):

        # A difference set can be built from the set of elements
        # (x,y) in GF(p) x GF(p+2) such that:
        #
        # - either y=0
        # - x and y with x and y     squares
        # - x and y with x and y non-squares
        if existence:
            return True

        from sage.rings.finite_rings.constructor import FiniteField
        from sage.categories.cartesian_product import cartesian_product
        from itertools import product
        p, q = pow(*factorization[0]), pow(*factorization[1])
        if p > q:
            p, q = q, p
        Fp = FiniteField(p, 'x')
        Fq = FiniteField(q, 'x')
        Fpset = set(Fp)
        Fqset = set(Fq)
        Fp_squares = set(x**2 for x in Fpset)
        Fq_squares = set(x**2 for x in Fqset)

        # Pairs of squares, pairs of non-squares
        d = []
        d.extend(
            product(Fp_squares.difference([0]), Fq_squares.difference([0])))
        d.extend(
            product(Fpset.difference(Fp_squares),
                    Fqset.difference(Fq_squares)))

        # All (x,0)
        d.extend((x, 0) for x in Fpset)

        G = cartesian_product([Fp, Fq])
        D = [d]

    if D is None and are_hyperplanes_in_projective_geometry_parameters(
            v, k, l):
        _, (q, d) = are_hyperplanes_in_projective_geometry_parameters(
            v, k, l, True)
        if existence:
            return True
        else:
            G, D = singer_difference_set(q, d)

    if D is None:
        if existence:
            return Unknown
        raise NotImplementedError("No constructions for these parameters")

    if check and not is_difference_family(G, D, verbose=False):
        raise RuntimeError

    return G, D
コード例 #20
0
    def polynomial(self, n):
        r"""
        Return the pseudo-Conway polynomial of degree `n` in this
        lattice.

        INPUT:

        - ``n`` -- positive integer

        OUTPUT:

        - a pseudo-Conway polynomial of degree `n` for the prime `p`.

        ALGORITHM:

        Uses an algorithm described in [HL99]_, modified to find
        pseudo-Conway polynomials rather than Conway polynomials.  The
        major difference is that we stop as soon as we find a
        primitive polynomial.

        REFERENCE:

        .. [HL99] L. Heath and N. Loehr (1999).  New algorithms for
           generating Conway polynomials over finite fields.
           Proceedings of the tenth annual ACM-SIAM symposium on
           discrete algorithms, pp. 429-437.

        EXAMPLES::

            sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice
            sage: PCL = PseudoConwayLattice(2, use_database=False)
            sage: PCL.polynomial(3)
            x^3 + x + 1
            sage: PCL.polynomial(4)
            x^4 + x^3 + 1
            sage: PCL.polynomial(60)
            x^60 + x^59 + x^58 + x^55 + x^54 + x^53 + x^52 + x^51 + x^48 + x^46 + x^45 + x^42 + x^41 + x^39 + x^38 + x^37 + x^35 + x^32 + x^31 + x^30 + x^28 + x^24 + x^22 + x^21 + x^18 + x^17 + x^16 + x^15 + x^14 + x^10 + x^8 + x^7 + x^5 + x^3 + x^2 + x + 1
        """
        if n in self.nodes:
            return self.nodes[n]

        p = self.p

        if n == 1:
            f = self.ring.gen() - FiniteField(p).multiplicative_generator()
            self.nodes[1] = f
            return f

        # Work in an arbitrary field K of order p**n.
        K = FiniteField(p**n, names='a')

        # TODO: something like the following
        # gcds = [n.gcd(d) for d in self.nodes.keys()]
        # xi = { m: (...) for m in gcds }
        xi = {q: self.polynomial(n//q).any_root(K, -n//q, assume_squarefree=True)
              for q in n.prime_divisors()}

        # The following is needed to ensure that in the concrete instantiation
        # of the "new" extension all previous choices are compatible.
        _frobenius_shift(K, xi)

        # Construct a compatible element having order the lcm of orders
        q, x = xi.popitem()
        v = p**(n//q) - 1
        for q, xitem in xi.iteritems():
            w = p**(n//q) - 1
            g, alpha, beta = v.xgcd(w)
            x = x**beta * xitem**alpha
            v = v.lcm(w)

        r = p**n - 1
        # Get the missing part of the order to be primitive
        g = r // v
        # Iterate through g-th roots of x until a primitive one is found
        z = x.nth_root(g)
        root = K.multiplicative_generator()**v
        while z.multiplicative_order() != r:
            z *= root
        # The following should work but tries to create a huge list
        # whose length overflows Python's ints for large parameters
        #Z = x.nth_root(g, all=True)
        #for z in Z:
        #    if z.multiplicative_order() == r:
        #         break
        f = z.minimal_polynomial()
        self.nodes[n] = f
        return f
コード例 #21
0
def OA_from_Vmt(m, t, V):
    r"""
    Returns an Orthogonal Array from a V(m,t)

    *Definition*

    Let `q` be a prime power and let `q=mt+1` for `m,t` integers. Let `\omega`
    be a primitive element of `\mathbb{F}_q`. A `V(m,t)` vector is a vector
    `(a_1,\dots,a_{m+1}` for which, for each `1\leq k < m`, the differences

    .. MATH::

        \{a_{i+k}-a_i:1\leq i \leq m+1,i+k\neq m+2\}

    represent the `m` cyclotomic classes of `\mathbb{F}_{mt+1}` (compute subscripts
    modulo `m+2`). In other words, for fixed `k`, is
    `a_{i+k}-a_i=\omega^{mx+\alpha}` and `a_{j+k}-a_j=\omega^{my+\beta}` then
    `\alpha\not\equiv\beta \mod{m}`

    *Construction of a quasi-difference matrix from a `V(m,t)` vector*

    Starting with a `V(m,t)` vector `(a_1,\dots,a_{m+1})`, form a single column
    of length `m+2` whose first entry is empty, and whose remaining entries are
    `(a_1,\dots,a_{m+1})`. Form `t` columns by multiplying this column by the
    `t` th roots, i.e. the powers of `\omega^m`. From each of these `t` columns,
    form `m+2` columns by taking the `m+2` cyclic shifts of the column. The
    result is a `(a,m+2;1,0;t)-QDM`.

    For more information, refer to the Handbook of Combinatorial Designs
    [DesignHandbook]_.

    INPUT:

    - ``m,t`` (integers)

    - ``V`` -- the vector `V(m,t)`.

    .. SEEALSO::

        :func:`OA_from_quasi_difference_matrix`

    EXAMPLES::

        sage: _ = designs.orthogonal_array(6,46) # indirect doctest
    """
    from sage.rings.finite_rings.constructor import FiniteField
    q = m * t + 1
    Fq = FiniteField(q)
    w = Fq.primitive_element()

    # Cyclic shift of a list
    cyclic_shift = lambda l, i: l[-i:] + l[:-i]

    M = []
    wm = w**m
    for i in range(t):
        L = [None]
        for e in V:
            L.append(e * wm**i)
        for ii in range(m + 2):
            M.append(cyclic_shift(L, ii))

    M.append([0] * q)
    M = zip(*M)
    M = OA_from_quasi_difference_matrix(M, Fq, add_col=False)

    return M
コード例 #22
0
    def ButterflyGraph(self, n, vertices='strings'):
        """
        Returns a n-dimensional butterfly graph. The vertices consist of
        pairs (v,i), where v is an n-dimensional tuple (vector) with binary
        entries (or a string representation of such) and i is an integer in
        [0..n]. A directed edge goes from (v,i) to (w,i+1) if v and w are
        identical except for possibly v[i] != w[i].

        A butterfly graph has `(2^n)(n+1)` vertices and
        `n2^{n+1}` edges.

        INPUT:


        -  ``vertices`` - 'strings' (default) or 'vectors',
           specifying whether the vertices are zero-one strings or actually
           tuples over GF(2).


        EXAMPLES::

            sage: digraphs.ButterflyGraph(2).edges(labels=False)
            [(('00', 0), ('00', 1)),
            (('00', 0), ('10', 1)),
            (('00', 1), ('00', 2)),
            (('00', 1), ('01', 2)),
            (('01', 0), ('01', 1)),
            (('01', 0), ('11', 1)),
            (('01', 1), ('00', 2)),
            (('01', 1), ('01', 2)),
            (('10', 0), ('00', 1)),
            (('10', 0), ('10', 1)),
            (('10', 1), ('10', 2)),
            (('10', 1), ('11', 2)),
            (('11', 0), ('01', 1)),
            (('11', 0), ('11', 1)),
            (('11', 1), ('10', 2)),
            (('11', 1), ('11', 2))]
            sage: digraphs.ButterflyGraph(2,vertices='vectors').edges(labels=False)
            [(((0, 0), 0), ((0, 0), 1)),
            (((0, 0), 0), ((1, 0), 1)),
            (((0, 0), 1), ((0, 0), 2)),
            (((0, 0), 1), ((0, 1), 2)),
            (((0, 1), 0), ((0, 1), 1)),
            (((0, 1), 0), ((1, 1), 1)),
            (((0, 1), 1), ((0, 0), 2)),
            (((0, 1), 1), ((0, 1), 2)),
            (((1, 0), 0), ((0, 0), 1)),
            (((1, 0), 0), ((1, 0), 1)),
            (((1, 0), 1), ((1, 0), 2)),
            (((1, 0), 1), ((1, 1), 2)),
            (((1, 1), 0), ((0, 1), 1)),
            (((1, 1), 0), ((1, 1), 1)),
            (((1, 1), 1), ((1, 0), 2)),
            (((1, 1), 1), ((1, 1), 2))]
        """
        # We could switch to Sage integers to handle arbitrary n.
        if vertices == 'strings':
            if n >= 31:
                raise NotImplementedError(
                    "vertices='strings' is only valid for n<=30.")
            from sage.graphs.generic_graph_pyx import binary
            butterfly = {}
            for v in xrange(2**n):
                for i in range(n):
                    w = v
                    w ^= (1 << i)  # push 1 to the left by i and xor with w
                    bv = binary(v)
                    bw = binary(w)
                    # pad and reverse the strings
                    padded_bv = ('0' * (n - len(bv)) + bv)[::-1]
                    padded_bw = ('0' * (n - len(bw)) + bw)[::-1]
                    butterfly[(padded_bv, i)] = [(padded_bv, i + 1),
                                                 (padded_bw, i + 1)]
        elif vertices == 'vectors':
            from sage.modules.free_module import VectorSpace
            from sage.rings.finite_rings.constructor import FiniteField
            from copy import copy
            butterfly = {}
            for v in VectorSpace(FiniteField(2), n):
                for i in xrange(n):
                    w = copy(v)
                    w[i] += 1  # Flip the ith bit
                    # We must call tuple since vectors are mutable.  To obtain
                    # a vector from the tuple t, just call vector(t).
                    butterfly[(tuple(v), i)] = [(tuple(v), i + 1),
                                                (tuple(w), i + 1)]
        else:
            raise NotImplementedError(
                "vertices must be 'strings' or 'vectors'.")
        return DiGraph(butterfly)
コード例 #23
0
def mutually_orthogonal_latin_squares(n, k=None, partitions=False):
    r"""
    Returns `k` Mutually Orthogonal `n\times n` Latin Squares (MOLS).

    For more information on Latin Squares and MOLS, see
    :mod:`~sage.combinat.designs.latin_squares` or the :wikipedia:`Latin_square`,
    or even the
    :wikipedia:`Wikipedia entry on MOLS <Graeco-Latin_square#Mutually_orthogonal_Latin_squares>`.

    INPUT:

    - ``n`` (integer) -- size of the latin square.

    - ``k`` (integer) -- returns `k` MOLS. If set to ``None`` (default), returns
      the maximum number of MOLS that Sage can build.

      .. WARNING::

          This has no reason to be the maximum number of `n\times n` MOLS, just
          the best Sage can do !

    - ``partition`` (boolean) -- a Latin Square can be seen as 3 partitions of
      the `n^2` cells of the array into `n` sets of size `n`, respectively :

      * The partition of rows
      * The partition of columns
      * The partition of number (cells numbered with 0, cells numbered with 1,
        ...)

      These partitions have the additional property that any two sets from
      different partitions intersect on exactly one element.

      When ``partition`` is set to ``True``, this function returns a list of `k+2`
      partitions satisfying this intersection property instead of the `k+2` MOLS
      (though the data is exactly the same in both cases).

    EXAMPLES::

        sage: designs.mutually_orthogonal_latin_squares(5)
        [
        [0 1 2 3 4]  [0 1 2 3 4]  [0 1 2 3 4]  [0 1 2 3 4]
        [3 0 1 4 2]  [4 3 0 2 1]  [1 2 4 0 3]  [2 4 3 1 0]
        [4 3 0 2 1]  [1 2 4 0 3]  [2 4 3 1 0]  [3 0 1 4 2]
        [1 2 4 0 3]  [2 4 3 1 0]  [3 0 1 4 2]  [4 3 0 2 1]
        [2 4 3 1 0], [3 0 1 4 2], [4 3 0 2 1], [1 2 4 0 3]
        ]
        sage: designs.mutually_orthogonal_latin_squares(7,3)
        [
        [0 1 2 3 4 5 6]  [0 1 2 3 4 5 6]  [0 1 2 3 4 5 6]
        [4 0 3 1 6 2 5]  [5 6 0 4 2 1 3]  [6 4 1 0 5 3 2]
        [5 6 0 4 2 1 3]  [6 4 1 0 5 3 2]  [1 3 5 2 0 6 4]
        [6 4 1 0 5 3 2]  [1 3 5 2 0 6 4]  [2 5 4 6 3 0 1]
        [1 3 5 2 0 6 4]  [2 5 4 6 3 0 1]  [3 2 6 5 1 4 0]
        [2 5 4 6 3 0 1]  [3 2 6 5 1 4 0]  [4 0 3 1 6 2 5]
        [3 2 6 5 1 4 0], [4 0 3 1 6 2 5], [5 6 0 4 2 1 3]
        ]
        sage: designs.mutually_orthogonal_latin_squares(5,2,partitions=True)
        [[[0, 1, 2, 3, 4],
          [5, 6, 7, 8, 9],
          [10, 11, 12, 13, 14],
          [15, 16, 17, 18, 19],
          [20, 21, 22, 23, 24]],
         [[0, 5, 10, 15, 20],
          [1, 6, 11, 16, 21],
          [2, 7, 12, 17, 22],
          [3, 8, 13, 18, 23],
          [4, 9, 14, 19, 24]],
        [[0, 6, 12, 18, 24],
          [1, 7, 14, 15, 23],
          [2, 9, 13, 16, 20],
          [3, 5, 11, 19, 22],
          [4, 8, 10, 17, 21]],
        [[0, 7, 13, 19, 21],
          [1, 9, 10, 18, 22],
          [2, 8, 11, 15, 24],
          [3, 6, 14, 17, 20],
          [4, 5, 12, 16, 23]]]

    TESTS::

        sage: designs.mutually_orthogonal_latin_squares(5,5)
        Traceback (most recent call last):
        ...
        ValueError: There exist at most n-1 MOLS of size n.
    """
    from sage.rings.finite_rings.constructor import FiniteField
    from sage.combinat.designs.block_design import AffineGeometryDesign
    from sage.rings.arith import is_prime_power
    from sage.matrix.constructor import Matrix
    from sage.rings.arith import factor

    if k is not None and k >= n:
        raise ValueError("There exist at most n-1 MOLS of size n.")

    if is_prime_power(n):
        if k is None:
            k = n - 1
        # Section 6.4.1 of [Stinson2004]
        Fp = FiniteField(n, 'x')
        B = AffineGeometryDesign(2, 1, Fp).blocks()
        parallel_classes = [[] for _ in range(k + 2)]
        for b in B:
            for p in parallel_classes:
                if (not p) or all(i not in p[0] for i in b):
                    p.append(b)
                    break

        if partitions:
            return parallel_classes

        coord = {v: i for i, L in enumerate(parallel_classes[0]) for v in L}
        coord = {
            v: (coord[v], i)
            for i, L in enumerate(parallel_classes[1]) for v in L
        }

        matrices = []
        for P in parallel_classes[2:]:
            matrices.append(
                Matrix({coord[v]: i
                        for i, L in enumerate(P) for v in L}))
        return matrices
    else:
        # Theorem 6.33 of [Stinson2004], MacNeish's theorem.
        subcases = [p**i for p, i in factor(n)]
        s = min(subcases) - 1
        if k is None:
            k = s
        elif k > s:
            raise NotImplementedError("I don't know how to build these MOLS.")
        subcalls = [mutually_orthogonal_latin_squares(p, k) for p in subcases]
        matrices = [
            latin_square_product(*[sc[i] for sc in subcalls]) for i in range(k)
        ]

        if partitions:
            partitions = [[[i * n + j for j in range(n)] for i in range(n)],
                          [[j * n + i for j in range(n)] for i in range(n)]]
            for m in matrices:
                partition = [[] for i in range(n)]
                for i in range(n):
                    for j in range(n):
                        partition[m[i, j]].append(i * n + j)
                partitions.append(partition)

            return partitions

        else:
            return matrices
コード例 #24
0
def TaylorTwographDescendantSRG(q, clique_partition=None):
    r"""
    constructing the descendant graph of the Taylor's two-graph for `U_3(q)`, `q` odd

    This is a strongly regular graph with parameters
    `(v,k,\lambda,\mu)=(q^3, (q^2+1)(q-1)/2, (q-1)^3/4-1, (q^2+1)(q-1)/4)`
    obtained as a two-graph descendant of the
    :func:`Taylor's two-graph <sage.combinat.designs.twographs.taylor_twograph>` `T`.
    This graph admits a partition into cliques of size `q`, which are useful in
    :func:`TaylorTwographSRG <sage.graphs.generators.classical_geometries.TaylorTwographSRG>`,
    a strongly regular graph on `q^3+1` vertices in the
    Seidel switching class of `T`, for which we need `(q^2+1)/2` cliques.
    The cliques are the `q^2` lines on `v_0` of the projective plane containing the unital
    for `U_3(q)`, and intersecting the unital (i.e. the vertices of the graph and the point
    we remove) in `q+1` points. This is all taken from §7E of [BvL84]_.

    INPUT:

    - ``q`` -- a power of an odd prime number

    - ``clique_partition`` -- if ``True``, return `q^2-1` cliques of size `q`
      with empty pairwise intersection. (Removing all of them leaves a clique, too),
      and the point removed from the unital.

    EXAMPLES::

        sage: g=graphs.TaylorTwographDescendantSRG(3); g
        Taylor two-graph descendant SRG: Graph on 27 vertices
        sage: g.is_strongly_regular(parameters=True)
        (27, 10, 1, 5)
        sage: from sage.combinat.designs.twographs import taylor_twograph
        sage: T = taylor_twograph(3)                           # long time
        sage: g.is_isomorphic(T.descendant(T.ground_set()[1])) # long time
        True
        sage: g=graphs.TaylorTwographDescendantSRG(5)    # not tested (long time)
        sage: g.is_strongly_regular(parameters=True)  # not tested (long time)
        (125, 52, 15, 26)

    TESTS::

        sage: g,l,_=graphs.TaylorTwographDescendantSRG(3,clique_partition=True)
        sage: all(map(lambda x: g.is_clique(x), l))
        True
        sage: graphs.TaylorTwographDescendantSRG(4)
        Traceback (most recent call last):
        ...
        ValueError: q must be an odd prime power
        sage: graphs.TaylorTwographDescendantSRG(6)
        Traceback (most recent call last):
        ...
        ValueError: q must be an odd prime power
    """
    from sage.rings.arith import is_prime_power
    p, k = is_prime_power(q, get_data=True)
    if k == 0 or p == 2:
        raise ValueError('q must be an odd prime power')
    from sage.schemes.projective.projective_space import ProjectiveSpace
    from sage.rings.finite_rings.constructor import FiniteField
    from sage.modules.free_module_element import free_module_element as vector
    from sage.rings.finite_rings.integer_mod import mod
    from __builtin__ import sum
    Fq = FiniteField(q**2, 'a')
    PG = map(tuple, ProjectiveSpace(2, Fq))

    def S(x, y):
        return sum(map(lambda j: x[j] * y[2 - j]**q, xrange(3)))

    V = filter(lambda x: S(x, x) == 0, PG)  # the points of the unital
    v0 = V[0]
    V.remove(v0)
    if mod(q, 4) == 1:
        G = Graph(
            [V, lambda y, z: not (S(v0, y) * S(y, z) * S(z, v0)).is_square()],
            loops=False)
    else:
        G = Graph(
            [V, lambda y, z: (S(v0, y) * S(y, z) * S(z, v0)).is_square()],
            loops=False)
    G.name("Taylor two-graph descendant SRG")
    if clique_partition:
        lines = map(lambda x: filter(lambda t: t[0] + x * t[1] == 0, V),
                    filter(lambda z: z != 0, Fq))
        return (G, lines, v0)
    else:
        return G
コード例 #25
0
def v_4_1_BIBD(v, check=True):
    r"""
    Returns a `(v,4,1)`-BIBD.

    A `(v,4,1)`-BIBD is an edge-decomposition of the complete graph `K_v` into
    copies of `K_4`. For more information, see
    :meth:`BalancedIncompleteBlockDesign`. It exists if and only if `v\equiv 1,4
    \pmod {12}`.

    See page 167 of [Stinson2004]_ for the construction details.

    .. SEEALSO::

        * :meth:`BalancedIncompleteBlockDesign`

    INPUT:

    - ``v`` (integer) -- number of points.

    - ``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: from sage.combinat.designs.bibd import v_4_1_BIBD  # long time
        sage: for n in range(13,100):                            # long time
        ....:    if n%12 in [1,4]:                               # long time
        ....:       _ = v_4_1_BIBD(n, check = True)              # long time
    """
    from sage.rings.finite_rings.constructor import FiniteField
    k = 4
    if v == 0:
        return []
    if v <= 12 or v % 12 not in [1, 4]:
        raise ValueError(
            "A K_4-decomposition of K_v exists iif v=2,4 mod 12, v>12 or v==0")

    # Step 1. Base cases.
    if v == 13:
        from block_design import ProjectivePlaneDesign
        return ProjectivePlaneDesign(3).blocks()
    if v == 16:
        from block_design import AffineGeometryDesign
        return AffineGeometryDesign(2, 1, FiniteField(4, 'x')).blocks()
    if v == 25:
        return [[0, 1, 17, 22], [0, 2, 11, 21], [0, 3, 15, 18], [0, 4, 7, 13],
                [0, 5, 12, 14], [0, 6, 19, 23], [0, 8, 16, 24], [0, 9, 10, 20],
                [1, 2, 3, 4], [1, 5, 6, 7], [1, 8, 12, 15], [1, 9, 13, 16],
                [1, 10, 11, 14], [1, 18, 20, 23], [1, 19, 21, 24],
                [2, 5, 15, 24], [2, 6, 9, 17], [2, 7, 14, 18], [2, 8, 22, 23],
                [2, 10, 12, 13], [2, 16, 19, 20], [3, 5, 16, 22],
                [3, 6, 11, 20], [3, 7, 12, 19], [3, 8, 9, 14], [3, 10, 17, 24],
                [3, 13, 21, 23], [4, 5, 10, 23], [4, 6, 8, 21], [4, 9, 18, 24],
                [4, 11, 15, 16], [4, 12, 17, 20], [4, 14, 19, 22],
                [5, 8, 13, 20], [5, 9, 11, 19], [5, 17, 18,
                                                 21], [6, 10, 15, 22],
                [6, 12, 16, 18], [6, 13, 14, 24], [7, 8, 11,
                                                   17], [7, 9, 15, 23],
                [7, 10, 16, 21], [7, 20, 22, 24], [8, 10, 18, 19],
                [9, 12, 21, 22], [11, 12, 23, 24], [11, 13, 18, 22],
                [13, 15, 17, 19], [14, 15, 20, 21], [14, 16, 17, 23]]
    if v == 28:
        return [[0, 1, 23, 26], [0, 2, 10, 11], [0, 3, 16, 18], [0, 4, 15, 20],
                [0, 5, 8, 9], [0, 6, 22, 25], [0, 7, 14, 21], [0, 12, 17, 27],
                [0, 13, 19, 24],
                [1, 2, 24, 27], [1, 3, 11, 12], [1, 4, 17, 19], [1, 5, 14, 16],
                [1, 6, 9, 10], [1, 7, 20, 25], [1, 8, 15, 22], [1, 13, 18, 21],
                [2, 3, 21, 25], [2, 4, 12, 13], [2, 5, 18, 20], [2, 6, 15, 17],
                [2, 7, 19, 22], [2, 8, 14, 26], [2, 9, 16, 23], [3, 4, 22, 26],
                [3, 5, 7, 13], [3, 6, 14, 19], [3, 8, 20, 23], [3, 9, 15, 27],
                [3, 10, 17, 24], [4, 5, 23, 27], [4, 6, 7, 8], [4, 9, 14, 24],
                [4, 10, 16, 21], [4, 11, 18, 25], [5, 6, 21, 24],
                [5, 10, 15, 25], [5, 11, 17, 22], [5, 12, 19, 26],
                [6, 11, 16, 26], [6, 12, 18, 23], [6, 13, 20, 27],
                [7, 9, 17, 18], [7, 10, 26, 27], [7, 11, 23, 24],
                [7, 12, 15, 16], [8, 10, 18, 19], [8, 11, 21, 27],
                [8, 12, 24, 25], [8, 13, 16, 17], [9, 11, 19, 20],
                [9, 12, 21, 22], [9, 13, 25, 26], [10, 12, 14, 20],
                [10, 13, 22, 23], [11, 13, 14, 15], [14, 17, 23, 25],
                [14, 18, 22, 27], [15, 18, 24, 26], [15, 19, 21, 23],
                [16, 19, 25, 27], [16, 20, 22, 24], [17, 20, 21, 26]]
    if v == 37:
        return [[0, 1, 3, 24], [0, 2, 23, 36], [0, 4, 26, 32], [0, 5, 9, 31],
                [0, 6, 11, 15], [0, 7, 17, 25], [0, 8, 20,
                                                 27], [0, 10, 18, 30],
                [0, 12, 19, 29], [0, 13, 14, 16], [0, 21, 34, 35],
                [0, 22, 28, 33], [1, 2, 4, 25], [1, 5, 27, 33], [1, 6, 10, 32],
                [1, 7, 12, 16], [1, 8, 18, 26], [1, 9, 21,
                                                 28], [1, 11, 19, 31],
                [1, 13, 20, 30], [1, 14, 15, 17], [1, 22, 35, 36],
                [1, 23, 29, 34], [2, 3, 5, 26], [2, 6, 28, 34], [2, 7, 11, 33],
                [2, 8, 13, 17], [2, 9, 19, 27], [2, 10, 22, 29],
                [2, 12, 20, 32], [2, 14, 21, 31], [2, 15, 16, 18],
                [2, 24, 30, 35], [3, 4, 6, 27], [3, 7, 29, 35], [3, 8, 12, 34],
                [3, 9, 14, 18], [3, 10, 20, 28], [3, 11, 23, 30],
                [3, 13, 21, 33], [3, 15, 22, 32], [3, 16, 17, 19],
                [3, 25, 31, 36], [4, 5, 7, 28], [4, 8, 30, 36], [4, 9, 13, 35],
                [4, 10, 15, 19], [4, 11, 21, 29], [4, 12, 24, 31],
                [4, 14, 22, 34], [4, 16, 23, 33], [4, 17, 18,
                                                   20], [5, 6, 8, 29],
                [5, 10, 14, 36], [5, 11, 16, 20], [5, 12, 22, 30],
                [5, 13, 25, 32], [5, 15, 23, 35], [5, 17, 24, 34],
                [5, 18, 19, 21], [6, 7, 9, 30], [6, 12, 17,
                                                 21], [6, 13, 23, 31],
                [6, 14, 26, 33], [6, 16, 24, 36], [6, 18, 25, 35],
                [6, 19, 20, 22], [7, 8, 10, 31], [7, 13, 18, 22],
                [7, 14, 24, 32], [7, 15, 27, 34], [7, 19, 26, 36],
                [7, 20, 21, 23], [8, 9, 11, 32], [8, 14, 19, 23],
                [8, 15, 25, 33], [8, 16, 28, 35], [8, 21, 22, 24],
                [9, 10, 12, 33], [9, 15, 20, 24], [9, 16, 26, 34],
                [9, 17, 29, 36], [9, 22, 23, 25], [10, 11, 13, 34],
                [10, 16, 21, 25], [10, 17, 27, 35], [10, 23, 24, 26],
                [11, 12, 14, 35], [11, 17, 22, 26], [11, 18, 28, 36],
                [11, 24, 25, 27], [12, 13, 15, 36], [12, 18, 23, 27],
                [12, 25, 26, 28], [13, 19, 24, 28], [13, 26, 27, 29],
                [14, 20, 25, 29], [14, 27, 28, 30], [15, 21, 26, 30],
                [15, 28, 29, 31], [16, 22, 27, 31], [16, 29, 30, 32],
                [17, 23, 28, 32], [17, 30, 31, 33], [18, 24, 29, 33],
                [18, 31, 32, 34], [19, 25, 30, 34], [19, 32, 33, 35],
                [20, 26, 31, 35], [20, 33, 34, 36], [21, 27, 32, 36]]

    # Step 2 : this is function PBD_4_5_8_9_12
    PBD = PBD_4_5_8_9_12((v - 1) / (k - 1), check=False)

    # Step 3 : Theorem 7.20
    bibd = BIBD_from_PBD(PBD, v, k, check=False)

    if check:
        _check_pbd(bibd, v, [k])

    return bibd
コード例 #26
0
def UnitaryPolarGraph(m, q, algorithm="gap"):
    r"""
    Returns the Unitary Polar Graph `U(m,q)`.

    For more information on Unitary Polar graphs, see the `page of
    Andries Brouwer's website <http://www.win.tue.nl/~aeb/graphs/srghub.html>`_.

    INPUT:

    - ``m,q`` (integers) -- `q` must be a prime power.

    - ``algorithm`` -- if set to 'gap' then the computation is carried via GAP
      library interface, computing totally singular subspaces, which is faster for
      large examples (especially with `q>2`). Otherwise it is done directly.

    EXAMPLES::

        sage: G = graphs.UnitaryPolarGraph(4,2); G
        Unitary Polar Graph U(4, 2); GQ(4, 2): Graph on 45 vertices
        sage: G.is_strongly_regular(parameters=True)
        (45, 12, 3, 3)
        sage: graphs.UnitaryPolarGraph(5,2).is_strongly_regular(parameters=True)
        (165, 36, 3, 9)
        sage: graphs.UnitaryPolarGraph(6,2)    # not tested (long time)
        Unitary Polar Graph U(6, 2): Graph on 693 vertices

    TESTS::

        sage: graphs.UnitaryPolarGraph(4,3, algorithm="gap").is_strongly_regular(parameters=True)
        (280, 36, 8, 4)
        sage: graphs.UnitaryPolarGraph(4,3).is_strongly_regular(parameters=True)
        (280, 36, 8, 4)
        sage: graphs.UnitaryPolarGraph(4,3, algorithm="foo")
        Traceback (most recent call last):
        ...
        ValueError: unknown algorithm!
    """
    if algorithm == "gap":
        from sage.libs.gap.libgap import libgap
        G = _polar_graph(m, q**2, libgap.GeneralUnitaryGroup(m, q))

    elif algorithm == None:  # slow on large examples
        from sage.schemes.projective.projective_space import ProjectiveSpace
        from sage.rings.finite_rings.constructor import FiniteField
        from sage.modules.free_module_element import free_module_element as vector
        from __builtin__ import sum as psum
        Fq = FiniteField(q**2, 'a')
        PG = map(vector, ProjectiveSpace(m - 1, Fq))
        map(lambda x: x.set_immutable(), PG)

        def P(x, y):
            return psum(map(lambda j: x[j] * y[m - 1 - j]**q, xrange(m))) == 0

        V = filter(lambda x: P(x, x), PG)
        G = Graph(
            [
                V,
                lambda x, y:  # bottleneck is here, of course:
                P(x, y)
            ],
            loops=False)
    else:
        raise ValueError("unknown algorithm!")

    G.relabel()
    G.name("Unitary Polar Graph U" + str((m, q)))
    if m == 4:
        G.name(G.name() + '; GQ' + str((q**2, q)))
    if m == 5:
        G.name(G.name() + '; GQ' + str((q**2, q**3)))
    return G
コード例 #27
0
def SymplecticPolarGraph(d, q, algorithm=None):
    r"""
    Returns the Symplectic Polar Graph `Sp(d,q)`.

    The Symplectic Polar Graph `Sp(d,q)` is built from a projective space of dimension
    `d-1` over a field `F_q`, and a symplectic form `f`. Two vertices `u,v` are
    made adjacent if `f(u,v)=0`.

    See the page `on symplectic graphs on Andries Brouwer's website
    <http://www.win.tue.nl/~aeb/graphs/Sp.html>`_.

    INPUT:

    - ``d,q`` (integers) -- note that only even values of `d` are accepted by
      the function.

    - ``algorithm`` -- if set to 'gap' then the computation is carried via GAP
      library interface, computing totally singular subspaces, which is faster for `q>3`.
      Otherwise it is done directly.

    EXAMPLES:

    Computation of the spectrum of `Sp(6,2)`::

        sage: g = graphs.SymplecticGraph(6,2)
        doctest:...: DeprecationWarning: SymplecticGraph is deprecated. Please use sage.graphs.generators.classical_geometries.SymplecticPolarGraph instead.
        See http://trac.sagemath.org/19136 for details.
        sage: g.is_strongly_regular(parameters=True)
        (63, 30, 13, 15)
        sage: set(g.spectrum()) == {-5, 3, 30}
        True

    The parameters of `Sp(4,q)` are the same as of `O(5,q)`, but they are
    not isomorphic if `q` is odd::

        sage: G = graphs.SymplecticPolarGraph(4,3)
        sage: G.is_strongly_regular(parameters=True)
        (40, 12, 2, 4)
        sage: O=graphs.OrthogonalPolarGraph(5,3)
        sage: O.is_strongly_regular(parameters=True)
        (40, 12, 2, 4)
        sage: O.is_isomorphic(G)
        False
        sage: graphs.SymplecticPolarGraph(6,4,algorithm="gap").is_strongly_regular(parameters=True) # not tested (long time)
        (1365, 340, 83, 85)

    TESTS::

        sage: graphs.SymplecticPolarGraph(4,4,algorithm="gap").is_strongly_regular(parameters=True)
        (85, 20, 3, 5)
        sage: graphs.SymplecticPolarGraph(4,4).is_strongly_regular(parameters=True)
        (85, 20, 3, 5)
        sage: graphs.SymplecticPolarGraph(4,4,algorithm="blah")
        Traceback (most recent call last):
        ...
        ValueError: unknown algorithm!
    """
    if d < 1 or d % 2 != 0:
        raise ValueError("d must be even and greater than 2")

    if algorithm == "gap":  # faster for larger (q>3)  fields
        from sage.libs.gap.libgap import libgap
        G = _polar_graph(d, q, libgap.SymplecticGroup(d, q))

    elif algorithm == None:  # faster for small (q<4) fields
        from sage.rings.finite_rings.constructor import FiniteField
        from sage.modules.free_module import VectorSpace
        from sage.schemes.projective.projective_space import ProjectiveSpace
        from sage.matrix.constructor import identity_matrix, block_matrix, zero_matrix

        F = FiniteField(q, "x")
        M = block_matrix(F, 2, 2, [
            zero_matrix(F, d / 2),
            identity_matrix(F, d / 2), -identity_matrix(F, d / 2),
            zero_matrix(F, d / 2)
        ])

        V = VectorSpace(F, d)
        PV = list(ProjectiveSpace(d - 1, F))
        G = Graph([[tuple(_) for _ in PV], lambda x, y: V(x) *
                   (M * V(y)) == 0],
                  loops=False)

    else:
        raise ValueError("unknown algorithm!")

    G.name("Symplectic Polar Graph Sp(" + str(d) + "," + str(q) + ")")
    G.relabel()
    return G
コード例 #28
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)
コード例 #29
0
ファイル: block_design.py プロジェクト: bopopescu/Sage-8
def DesarguesianProjectivePlaneDesign(n, 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

    - ``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, 'x')
    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
    return BalancedIncompleteBlockDesign(n2 + n + 1, blcks, check=check)
コード例 #30
0
def difference_matrix(g, k, lmbda=1, existence=False, check=True):
    r"""
    Return a `(g,k,\lambda)`-difference matrix

    A matrix `M` is a `(g,k,\lambda)`-difference matrix if it has size `\lambda
    g\times k`, its entries belong to the group `G` of cardinality `g`, and
    for any two rows `R,R'` of `M` and `x\in G` there are exactly `\lambda`
    values `i` such that `R_i-R'_i=x`.

    INPUT:

    - ``k`` -- (integer) number of columns. If ``k=None`` it is set to the
      largest value available.

    - ``g`` -- (integer) cardinality of the group `G`

    - ``lmbda`` -- (integer; default: 1) -- number of times each element of `G`
      appears as a difference.

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

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

      .. NOTE::

          When ``k=None`` and ``existence=True`` the function returns an
          integer, i.e. the largest `k` such that we can build a
          `(g,k,\lambda)`-DM.

    EXAMPLES::

        sage: G,M = designs.difference_matrix(25,10); G
        Finite Field in x of size 5^2
        sage: designs.difference_matrix(993,None,existence=1)
        32

    Here we print for each `g` the maximum possible `k` for which Sage knows
    how to build a `(g,k,1)`-difference matrix::

        sage: for g in range(2,30):
        ....:     k_max = designs.difference_matrix(g=g,k=None,existence=True)
        ....:     print "{:2} {}".format(g, k_max)
        ....:     _ = designs.difference_matrix(g,k_max)
         2 2
         3 3
         4 4
         5 5
         6 2
         7 7
         8 8
         9 9
        10 2
        11 11
        12 6
        13 13
        14 2
        15 3
        16 16
        17 17
        18 2
        19 19
        20 4
        21 6
        22 2
        23 23
        24 8
        25 25
        26 2
        27 27
        28 6
        29 29

    TESTS::

        sage: designs.difference_matrix(10,12,1,existence=True)
        False
        sage: designs.difference_matrix(10,12,1)
        Traceback (most recent call last):
        ...
        EmptySetError: No (10,12,1)-Difference Matrix exists as k(=12)>g(=10)
        sage: designs.difference_matrix(10,9,1,existence=True)
        Unknown
        sage: designs.difference_matrix(10,9,1)
        Traceback (most recent call last):
        ...
        NotImplementedError: I don't know how to build a (10,9,1)-Difference Matrix!
    """

    if lmbda == 1 and k is not None and k > g:
        if existence:
            return False
        raise EmptySetError(
            "No ({},{},{})-Difference Matrix exists as k(={})>g(={})".format(
                g, k, lmbda, k, g))

    # Prime powers
    elif lmbda == 1 and is_prime_power(g):
        if k is None:
            if existence:
                return g
            else:
                k = g
        elif existence:
            return True
        F = FiniteField(g, 'x')
        F_set = list(F)
        F_k_set = F_set[:k]

        G = F
        M = [[x * y for y in F_k_set] for x in F_set]

    # Treat the case k=None
    # (find the max k such that there exists a DM)
    elif k is None:
        i = 2
        while difference_matrix(g=g, k=i, lmbda=lmbda, existence=True):
            i += 1
        return i - 1

    # From the database
    elif (g, lmbda) in DM_constructions and DM_constructions[g, lmbda][0] >= k:
        if existence:
            return True
        _, f = DM_constructions[g, lmbda]
        G, M = f()
        M = [R[:k] for R in M]

    # Product construction
    elif find_product_decomposition(g, k, lmbda):
        if existence:
            return True
        (g1, lmbda1), (g2, lmbda2) = find_product_decomposition(g, k, lmbda)
        G1, M1 = difference_matrix(g1, k, lmbda1)
        G2, M2 = difference_matrix(g2, k, lmbda2)
        G, M = difference_matrix_product(k,
                                         M1,
                                         G1,
                                         lmbda1,
                                         M2,
                                         G2,
                                         lmbda2,
                                         check=False)

    else:
        if existence:
            return Unknown
        raise NotImplementedError(
            "I don't know how to build a ({},{},{})-Difference Matrix!".format(
                g, k, lmbda))

    if check and not is_difference_matrix(M, G, k, lmbda, 1):
        raise RuntimeError(
            "Sage built something which is not a ({},{},{})-DM!".format(
                g, k, lmbda))

    return G, M