Example #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
    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))
Example #3
0
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))
    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
def DuadicCodeOddPair(F,S1,S2):
    """
    Constructs the "odd pair" of duadic codes associated to the
    "splitting" S1, S2 of n.

    .. warning::

       Maybe the splitting should be associated to a sum of
       q-cyclotomic cosets mod n, where q is a *prime*.

    EXAMPLES::

        sage: from sage.coding.code_constructions import is_a_splitting
        sage: n = 11; q = 3
        sage: C = Zmod(n).cyclotomic_cosets(q); C
        [[0], [1, 3, 4, 5, 9], [2, 6, 7, 8, 10]]
        sage: S1 = C[1]
        sage: S2 = C[2]
        sage: is_a_splitting(S1,S2,11)
        True
        sage: codes.DuadicCodeOddPair(GF(q),S1,S2)
        (Linear code of length 11, dimension 6 over Finite Field of size 3,
         Linear code of length 11, dimension 6 over Finite Field of size 3)

    This is consistent with Theorem 6.1.3 in [HP]_.
    """
    n = len(S1) + len(S2) + 1
    if not is_a_splitting(S1,S2,n):
        raise TypeError("%s, %s must be a splitting of %s."%(S1,S2,n))
    q = F.order()
    k = Mod(q,n).multiplicative_order()
    FF = GF(q**k,"z")
    z = FF.gen()
    zeta = z**((q**k-1)/n)
    P1 = PolynomialRing(FF,"x")
    x = P1.gen()
    g1 = prod([x-zeta**i for i in S1+[0]])
    g2 = prod([x-zeta**i for i in S2+[0]])
    j = sum([x**i/n for i in range(n)])
    P2 = PolynomialRing(F,"x")
    x = P2.gen()
    coeffs1 = [lift2smallest_field(c)[0] for c in (g1+j).coefficients(sparse=False)]
    coeffs2 = [lift2smallest_field(c)[0] for c in (g2+j).coefficients(sparse=False)]
    gg1 = P2(coeffs1)
    gg2 = P2(coeffs2)
    C1 = CyclicCodeFromGeneratingPolynomial(n,gg1)
    C2 = CyclicCodeFromGeneratingPolynomial(n,gg2)
    return C1,C2
def DuadicCodeEvenPair(F,S1,S2):
    r"""
    Constructs the "even pair" of duadic codes associated to the
    "splitting" (see the docstring for ``is_a_splitting``
    for the definition) S1, S2 of n.

    .. warning::

       Maybe the splitting should be associated to a sum of
       q-cyclotomic cosets mod n, where q is a *prime*.

    EXAMPLES::

        sage: from sage.coding.code_constructions import is_a_splitting
        sage: n = 11; q = 3
        sage: C = Zmod(n).cyclotomic_cosets(q); C
        [[0], [1, 3, 4, 5, 9], [2, 6, 7, 8, 10]]
        sage: S1 = C[1]
        sage: S2 = C[2]
        sage: is_a_splitting(S1,S2,11)
        True
        sage: codes.DuadicCodeEvenPair(GF(q),S1,S2)
        (Linear code of length 11, dimension 5 over Finite Field of size 3,
         Linear code of length 11, dimension 5 over Finite Field of size 3)
    """
    n = len(S1) + len(S2) + 1
    if not is_a_splitting(S1,S2,n):
        raise TypeError("%s, %s must be a splitting of %s."%(S1,S2,n))
    q = F.order()
    k = Mod(q,n).multiplicative_order()
    FF = GF(q**k,"z")
    z = FF.gen()
    zeta = z**((q**k-1)/n)
    P1 = PolynomialRing(FF,"x")
    x = P1.gen()
    g1 = prod([x-zeta**i for i in S1+[0]])
    g2 = prod([x-zeta**i for i in S2+[0]])
    P2 = PolynomialRing(F,"x")
    x = P2.gen()
    gg1 = P2([lift2smallest_field(c)[0] for c in g1.coefficients(sparse=False)])
    gg2 = P2([lift2smallest_field(c)[0] for c in g2.coefficients(sparse=False)])
    C1 = CyclicCodeFromGeneratingPolynomial(n,gg1)
    C2 = CyclicCodeFromGeneratingPolynomial(n,gg2)
    return C1,C2
Example #7
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)
Example #8
0
File: bibd.py Project: Etn40ff/sage
def BIBD_5q_5_for_q_prime_power(q):
    r"""
    Return a `(5q,5,1)`-BIBD with `q\equiv 1\pmod 4` a prime power.

    See Theorem 24 [ClaytonSmith]_.

    INPUT:

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

    EXAMPLES::

        sage: from sage.combinat.designs.bibd import BIBD_5q_5_for_q_prime_power
        sage: for q in [25, 45, 65, 85, 125, 145, 185, 205, 305, 405, 605]: # long time
        ....:     _ = BIBD_5q_5_for_q_prime_power(q/5)                      # long time
    """
    from sage.rings.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
Example #9
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
    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)
Example #11
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')
Example #12
0
def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, check_hyperoval=True):
    r"""
    Return the collinearity graph of the generalized quadrangle `T_2^*(q)`, or of its dual

    Let `q=2^k` and `\Theta=PG(3,q)`.  `T_2^*(q)` is a generalized quadrangle [GQwiki]_
    of order `(q-1,q+1)`, see 3.1.3 in [PT09]_. Fix a plane `\Pi \subset \Theta` and a
    `hyperoval <http://en.wikipedia.org/wiki/Oval_(projective_plane)#Even_q>`__
    `O \subset \Pi`. The points of `T_2^*(q):=T_2^*(O)` are the points of `\Theta`
    outside `\Pi`, and the lines are the lines of `\Theta` outside `\Pi`
    that meet `\Pi` in a point of `O`.

    INPUT:

    - ``q`` -- a power of two

    - ``dual`` -- if ``False`` (default), return the graph of `T_2^*(O)`.
      Otherwise return the graph of the dual `T_2^*(O)`.

    - ``hyperoval`` -- a hyperoval (i.e. a complete 2-arc; a set of points in the plane
      meeting every line in 0 or 2 points) in the plane of points with 0th coordinate
      0 in `PG(3,q)` over the field ``field``. Each point of ``hyperoval`` must be a length 4
      vector over ``field`` with 1st non-0 coordinate equal to 1. By default, ``hyperoval`` and
      ``field`` are not specified, and constructed on the fly. In particular, ``hyperoval``
      we build is the classical one, i.e. a conic with the point of intersection of its
      tangent lines.

    - ``field`` -- an instance of a finite field of order `q`, must be provided
      if ``hyperoval`` is provided.

    - ``check_hyperoval`` -- (default: ``True``) if ``True``,
      check ``hyperoval`` for correctness.


    EXAMPLES:

    using the built-in construction::

        sage: g=graphs.T2starGeneralizedQuadrangleGraph(4); g
        T2*(O,4); GQ(3, 5): Graph on 64 vertices
        sage: g.is_strongly_regular(parameters=True)
        (64, 18, 2, 6)
        sage: g=graphs.T2starGeneralizedQuadrangleGraph(4,dual=True); g
        T2*(O,4)*; GQ(5, 3): Graph on 96 vertices
        sage: g.is_strongly_regular(parameters=True)
        (96, 20, 4, 4)

    supplying your own hyperoval::

        sage: F=GF(4,'b')
        sage: O=[vector(F,(0,0,0,1)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F)
        sage: g=graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F); g
        T2*(O,4); GQ(3, 5): Graph on 64 vertices
        sage: g.is_strongly_regular(parameters=True)
        (64, 18, 2, 6)

    TESTS::

        sage: F=GF(4,'b') # repeating a point...
        sage: O=[vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F)
        sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F)
        Traceback (most recent call last):
        ...
        RuntimeError: incorrect hyperoval size
        sage: O=[vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F)
        sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F)
        Traceback (most recent call last):
        ...
        RuntimeError: incorrect hyperoval
    """
    from sage.combinat.designs.incidence_structures import IncidenceStructure
    from sage.combinat.designs.block_design import ProjectiveGeometryDesign as PG
    from sage.modules.free_module_element import free_module_element as vector

    p, k = is_prime_power(q,get_data=True)
    if k==0 or p!=2:
       raise ValueError('q must be a power of 2')
    if field is None:
        F = FiniteField(q, 'a')
    else:
        F = field

    Theta = PG(3, 1, F, point_coordinates=1)
    Pi = set(filter(lambda x: x[0]==F.zero(), Theta.ground_set()))
    if hyperoval is None:
        O = filter(lambda x: x[1]+x[2]*x[3]==0 or (x[1]==1 and x[2]==0 and x[3]==0), Pi)
        O = set(O)
    else:
        map(lambda x: x.set_immutable(), hyperoval)
        O = set(hyperoval)
        if check_hyperoval:
            if len(O) != q+2:
                raise RuntimeError("incorrect hyperoval size")
            for L in Theta.blocks():
                if set(L).issubset(Pi):
                    if not len(O.intersection(L)) in [0,2]:
                        raise RuntimeError("incorrect hyperoval")
    L = map(lambda z: filter(lambda y: not y in O, z),
            filter(lambda x: len(O.intersection(x)) == 1, Theta.blocks()))
    if dual:
        G = IncidenceStructure(L).intersection_graph()
        G.name('T2*(O,'+str(q)+')*; GQ'+str((q+1,q-1)))
    else:
        G = IncidenceStructure(L).dual().intersection_graph()
        G.name('T2*(O,'+str(q)+'); GQ'+str((q-1,q+1)))
    return G
Example #13
0
def v_4_1_BIBD(v, check=True):
    r"""
    Return 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
    :func:`balanced_incomplete_block_design`. It exists if and only if `v\equiv 1,4
    \pmod {12}`.

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

    .. SEEALSO::

        * :func:`balanced_incomplete_block_design`

    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

    TESTS:

    Check that the `(25,4)` and `(37,4)`-difference family are available::

        sage: assert designs.difference_family(25,4,existence=True)
        sage: _ = designs.difference_family(25,4)
        sage: assert designs.difference_family(37,4,existence=True)
        sage: _ = designs.difference_family(37,4)

    Check some larger `(v,4,1)`-BIBD (see :trac:`17557`)::

        sage: for v in range(400):                                      # long time
        ....:     if v%12 in [1,4]:                                     # long time
        ....:         _ = designs.balanced_incomplete_block_design(v,4) # long time
    """
    k = 4
    if v == 0:
        return []
    if v <= 12 or v % 12 not in [1, 4]:
        raise EmptySetError(
            "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:
        # note: this construction can also be obtained from difference_family
        from block_design import projective_plane
        return projective_plane(3)._blocks
    if v == 16:
        from block_design import AffineGeometryDesign
        from sage.rings.finite_rings.constructor import FiniteField
        return AffineGeometryDesign(2, 1, FiniteField(4, 'x'))._blocks
    if v == 25 or v == 37:
        from difference_family import difference_family
        G, D = difference_family(v, 4)
        return BIBD_from_difference_family(G, D, check=False)
    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]]

    # 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:
        assert is_pairwise_balanced_design(bibd, v, [k])

    return bibd
Example #14
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.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
Example #15
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
    """
    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.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
Example #16
0
def AhrensSzekeresGeneralizedQuadrangleGraph(q, dual=False):
    r"""
    Return the collinearity graph of the generalized quadrangle `AS(q)`, or of its dual

    Let `q` be an odd prime power.  `AS(q)` is a generalized quadrangle [GQwiki]_ of
    order `(q-1,q+1)`, see 3.1.5 in [PT09]_. Its points are elements
    of `F_q^3`, and lines are sets of size `q` of the form

    * `\{ (\sigma, a, b) \mid \sigma\in F_q \}`
    * `\{ (a, \sigma, b) \mid \sigma\in F_q \}`
    * `\{ (c \sigma^2 - b \sigma + a, -2 c \sigma + b, \sigma) \mid \sigma\in F_q \}`,

    where `a`, `b`, `c` are arbitrary elements of `F_q`.

    INPUT:

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

    - ``dual`` -- if ``False`` (default), return the collinearity graph of `AS(q)`.
      Otherwise return the collinearity graph of the dual `AS(q)`.

    EXAMPLES::

        sage: g=graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5); g
        AS(5); GQ(4, 6): Graph on 125 vertices
        sage: g.is_strongly_regular(parameters=True)
        (125, 28, 3, 7)
        sage: g=graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5,dual=True); g
        AS(5)*; GQ(6, 4): Graph on 175 vertices
        sage: g.is_strongly_regular(parameters=True)
        (175, 30, 5, 5)

    REFERENCE:

    .. [GQwiki] `Generalized quadrangle
      <http://en.wikipedia.org/wiki/Generalized_quadrangle>`__

    .. [PT09] S. Payne, J. A. Thas.
      Finite generalized quadrangles.
      European Mathematical Society,
      2nd edition, 2009.
    """
    from sage.combinat.designs.incidence_structures import IncidenceStructure
    p, k = is_prime_power(q,get_data=True)
    if k==0 or p==2:
       raise ValueError('q must be an odd prime power')
    F = FiniteField(q, 'a')
    L = []
    for a in F:
        for b in F:
            L.append(tuple(map(lambda s: (s, a, b), F)))
            L.append(tuple(map(lambda s: (a, s, b), F)))
            for c in F:
                L.append(tuple(map(lambda s: (c*s**2 - b*s + a, -2*c*s + b, s), F)))
    if dual:
        G = IncidenceStructure(L).intersection_graph()
        G.name('AS('+str(q)+')*; GQ'+str((q+1,q-1)))
    else:
        G = IncidenceStructure(L).dual().intersection_graph()
        G.name('AS('+str(q)+'); GQ'+str((q-1,q+1)))
    return G
Example #17
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)
Example #18
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.modules.free_module_element import free_module_element as vector
        Fq = FiniteField(q**2, 'a')
        PG = map(vector, ProjectiveSpace(m - 1, Fq))
        map(lambda x: x.set_immutable(), PG)
        def P(x,y):
            return sum(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
Example #19
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
Example #20
0
def hadamard_matrix_paleyII(n):
    """
    Implements the Paley type II construction.

    The Paley type II case corresponds to the case `p \cong 1 \mod{4}` for a
    prime `p` (see [Hora]_).

    EXAMPLES::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12).det()
        2985984
        sage: 12^6
        2985984

    We note that the method returns a normalised Hadamard matrix ::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12)
        [ 1  1| 1  1| 1  1| 1  1| 1  1| 1  1]
        [ 1 -1|-1  1|-1  1|-1  1|-1  1|-1  1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1| 1 -1| 1  1|-1 -1|-1 -1| 1  1]
        [ 1  1|-1 -1| 1 -1|-1  1|-1  1| 1 -1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1| 1  1| 1 -1| 1  1|-1 -1|-1 -1]
        [ 1  1| 1 -1|-1 -1| 1 -1|-1  1|-1  1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1|-1 -1| 1  1| 1 -1| 1  1|-1 -1]
        [ 1  1|-1  1| 1 -1|-1 -1| 1 -1|-1  1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1|-1 -1|-1 -1| 1  1| 1 -1| 1  1]
        [ 1  1|-1  1|-1  1| 1 -1|-1 -1| 1 -1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1| 1  1|-1 -1|-1 -1| 1  1| 1 -1]
        [ 1  1| 1 -1|-1  1|-1  1| 1 -1|-1 -1]

    TESTS::

        sage: from sage.combinat.matrices.hadamard_matrix import (hadamard_matrix_paleyII, is_hadamard_matrix)
        sage: test_cases = [2*(x+1) for x in range(50) if is_prime_power(x) and x%4==1]
        sage: all(is_hadamard_matrix(hadamard_matrix_paleyII(n),normalized=True,verbose=True)
        ....:     for n in test_cases)
        True
    """
    q = n//2 - 1
    if not(n%2==0 and is_prime_power(q) and (q % 4 == 1)):
        raise ValueError("The order %s is not covered by the Paley type II construction." % n)

    from sage.rings.finite_rings.constructor import FiniteField
    K = FiniteField(q,'x')
    K_list = list(K)
    K_list.insert(0,K.zero())
    H = matrix(ZZ, [[(1 if (x-y).is_square() else -1)
                     for x in K_list]
                    for y in K_list])
    for i in range(q+1):
        H[0,i] = 1
        H[i,0] = 1
        H[i,i] = 0

    tr = { 0: matrix(2,2,[ 1,-1,-1,-1]),
           1: matrix(2,2,[ 1, 1, 1,-1]),
          -1: matrix(2,2,[-1,-1,-1, 1])}

    H = block_matrix(q+1,q+1,[tr[v] for r in H for v in r])

    return normalise_hadamard(H)
Example #21
0
class ShamirSS(SageObject):
    r"""
    Shamir secret sharing.
   
    This class implements the original version of perfectly secure secret sharing 
    as proposed by Shamir in [Shamir1979]_. It is a very basic implementation
    intended for educational purposes only.

    INPUT:

    - ``k``  --  (default: ``3``) the threshold for reconstruction.
    - ``n``  --  (default: ``7``) the number of shares.
    - ``order`` --  (default: ``2^8``) field order for data to share.

    EXAMPLES::

        sage: from sage.crypto.smc.shamir_ss import ShamirSS

    Generate shares::

        sage: k = 3; n = 7
        sage: sss = ShamirSS(n,k)
        sage: secret = 42
        sage: shares = sss.share(secret)

    Reconstruct secret (Lagrange interpolation)::

        sage: secret == sss.reconstruct(shares)
        True

    Reconstruct with error shares (Belekamp-Welsch decoder)::

        sage: shares[0] = (shares[0][0], shares[0][1]+1)
        sage: secret == sss.reconstruct(shares, decoder='bw')
        True

    Input vectors::

        sage: sss = ShamirSS()
        sage: secret = [42, 43, 44, 45]
        sage: shares = sss.share(secret)
        sage: secret == sss.reconstruct(shares)
        True

    TESTS:

    More random input::

        sage: secret = randint(0,255)
        sage: shares = sss.share(secret)
        sage: secret == sss.reconstruct(shares, decoder='lg')
        True
        sage: secret == sss.reconstruct(shares, decoder='bw')
        True

    Secret must be integer representation in field::

        sage: secret = 333
        sage: shares = sss.share(secret)
        Traceback (most recent call last):
        ...
        TypeError: secret must be within 0 and field order.

    Working in prime fields::

        sage: from sage.rings.arith import random_prime

        sage: order = random_prime(10**10)
        sage: secret = randint(0, order-1)
        sage: sss = ShamirSS(7, 3, order)
        sage: shares = sss.share(secret)
        sage: secret == sss.reconstruct(shares)
        True

        sage: shares[0] = (shares[0][0], shares[0][1]+1)
        sage: secret == sss.reconstruct(shares, decoder='bw')
        True

        sage: shares[1] = (shares[1][0], shares[1][1]+1)
        sage: secret == sss.reconstruct(shares, decoder='bw')
        True

        sage: shares[-1] = (shares[-1][0], shares[-1][1]+1)
        sage: secret == sss.reconstruct(shares, decoder='bw')
        False

    Working in extension fields::

        sage: order = 2**randint(3,15)
        sage: secret = randint(0, order)
        sage: sss = ShamirSS(7, 3, order)
        sage: shares = sss.share(secret)
        sage: secret == sss.reconstruct(shares[:-2])
        True

        sage: shares[0] = (shares[0][0], shares[0][1]+1)
        sage: secret == sss.reconstruct(shares, decoder='bw')
        True

        sage: shares[1] = (shares[1][0], shares[1][1]+1)
        sage: secret == sss.reconstruct(shares, decoder='bw')
        True

        sage: shares[-1] = (shares[-1][0], shares[-1][1]+1)
        sage: secret == sss.reconstruct(shares, decoder='bw')
        False
    """
    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')

    ### begin module private api

    def _latex_(self):
        r"""
        Return Latex representation of self.

        EXAMPLES::

            sage: from sage.crypto.smc.shamir_ss import ShamirSS
            sage: sss=ShamirSS()
            sage: latex(sss)
            `(7,3)`-Shamir secret sharing over the field `\Bold{F}_{2^{8}}`
        """
        from sage.misc.latex import latex
        return "`({},{})`-Shamir secret sharing over the field `{}`".format(
            self._n, self._k, latex(self._F))


    def _to_GF(self, x):
        r""" 
        Convert integer representation to finite field

        INPUT:

        - ``x`` --  the integer representation to be converted.

        OUTPUT:

        The finite field representation.

        EXAMPLES::
        
            sage: from sage.crypto.smc.shamir_ss import ShamirSS
            sage: sss = ShamirSS()
            sage: sss._to_GF(42)
            a^5 + a^3 + a
            sage: sss._to_GF(255)
            a^7 + a^6 + a^5 + a^4 + a^3 + a^2 + a + 1
        """
        # input checking
        if x > self._F.order():
            raise TypeError("secret must be within 0 and field order.")

        # convert to field type
        if self._F.is_prime_field():
            return self._F(x)
        else:
            return self._F.fetch_int(x)


    def _to_Int(self, x):
        r""" 
        Convert field representation to integer

        INPUT:

        - ``x`` -- the field element to be converted.

        OUTPUT:

        The integer representation of the field element.

        EXAMPLES::
        
            sage: from sage.crypto.smc.shamir_ss import ShamirSS
            sage: sss = ShamirSS()
            sage: secret = 42
            sage: test = sss._to_Int(sss._to_GF(42))
            sage: test == secret
            True
        """
        from sage.rings.all import Integer
        if self._F.is_prime_field():
            return Integer(x)
        else:
            return x.integer_representation()


    def _rec_berlekamp_welsh(self, points):
        r"""
        Reconstruct with Berlekamp-Welsh decoding.

        INPUT:

        - ``points`` -- shares as list of tuples.

        OUTPUT:

        Reconstructed secret.

        EXAMPLES::

            sage: from sage.crypto.smc.shamir_ss import ShamirSS

        Decoding with errors::

            sage: sss = ShamirSS()
            sage: secret = 42
            sage: shares = sss.share(secret)
            sage: shares[0] = (shares[0][0], shares[0][1]+1)
            sage: secret == sss.reconstruct(shares, decoder='bw')
            True

            sage: k = 4; n = 10
            sage: sss = ShamirSS(n,k)
            sage: secret = 84
            sage: shares = sss.share(secret)
            sage: shares[0] = (shares[0][0], shares[0][1]+1)
            sage: shares[1] = (shares[1][0], shares[1][1]+1)
            sage: shares[-1] = (shares[-1][0], shares[-1][1]+1)
            sage: secret == sss.reconstruct(shares, decoder='bw')
            True

        """
        from berlekamp_welsh import berlekamp_welsh
        polycoeffs =  berlekamp_welsh(self._k-1, points).coeffs()
        return polycoeffs


    def _rec_lagrange(self, points):
        r""" 
        Reconstruct with Lagrange interpolation.

        INPUT:

        - ``points`` --  shares as list of tuples.

        OUTPUT:

        Reconstructed secret.

        EXAMPLES::

            sage: from sage.crypto.smc.shamir_ss import ShamirSS

        Erasure decoding::

            sage: sss = ShamirSS()
            sage: secret = 42
            sage: shares = sss.share(secret)
            sage: secret == sss.reconstruct(shares)
            True

            sage: k = 4; n = 10
            sage: sss = ShamirSS(n,k)
            sage: secret = 42
            sage: shares = sss.share(secret)
            sage: secret == sss.reconstruct(shares)
            True
        """
        polycoeffs = self._P.lagrange_polynomial(points).coeffs()
        if len(polycoeffs) != self._k:
            raise ValueError("lagrange polynomial degree mismatch.")
        return polycoeffs


    def _repr_(self):
        r"""
        Return String representation of self.

        EXAMPLES::

            sage: from sage.crypto.smc.shamir_ss import ShamirSS
            sage: sss=ShamirSS()
            sage: print(sss)
            (7,3)-Shamir secret sharing over Finite Field in a of size 2^8
        """
        return "({},{})-Shamir secret sharing over {}".format(self._n, self._k, 
                                                              self._F)
    ### begin public api

    def reconstruct(self, shares, decoder='lg'):
        r"""
        Reconstruct shares.

        INPUT:

        - ``shares`` -- a list of shares ((x,y)-tuples of integer) or list of it.
        - ``decoder`` -- (default: ``'lg'``) decoder used to reconstruct secret. Must
            be one of the supported types ``'lg'`` or ``'bw'``.

        OUTPUT:

        The reconstructed secret or list of secrets.

        EXAMPLES::

            sage: from sage.crypto.smc.shamir_ss import ShamirSS

        Simple interface::

            sage: sss = ShamirSS()
            sage: secret = 42
            sage: shares = sss.share(secret)
            sage: secret == sss.reconstruct(shares)
            True

        Decoding with errors::

            sage: shares[0] = (shares[0][0], shares[0][1]+1)
            sage: secret == sss.reconstruct(shares, decoder='bw')
            True

            sage: k = 4; n = 10
            sage: sss = ShamirSS(n,k)
            sage: secret = randint(0, 255)
            sage: shares = sss.share(secret)
            sage: shares[0] = (shares[0][0], shares[0][1]+1)
            sage: shares[1] = (shares[1][0], shares[1][1]+1)
            sage: shares[-1] = (shares[-1][0], shares[-1][1]+1)
            sage: secret == sss.reconstruct(shares, decoder='bw')
            True

        TESTS:

        Working in prime fields::

            sage: from sage.rings.arith import random_prime
            sage: order = random_prime(10**10)
            sage: secret = randint(0, order-1)
            sage: sss = ShamirSS(7, 3, order)
            sage: shares = sss.share(secret)
            sage: secret == sss.reconstruct(shares)
            True

            sage: shares[0] = (shares[0][0], shares[0][1]+1)
            sage: secret == sss.reconstruct(shares, decoder='bw')
            True

            sage: shares[1] = (shares[1][0], shares[1][1]+1)
            sage: secret == sss.reconstruct(shares, decoder='bw')
            True

            sage: shares[-1] = (shares[-1][0], shares[-1][1]+1)
            sage: secret == sss.reconstruct(shares, decoder='bw')
            False

        Working in extension fields::

            sage: order = 2**randint(3, 15)
            sage: secret = randint(0, order-1)
            sage: sss = ShamirSS(7, 3, order)
            sage: shares = sss.share(secret)
            sage: secret == sss.reconstruct(shares[:-2])
            True

            sage: shares[0] = (shares[0][0], shares[0][1]+1)
            sage: secret == sss.reconstruct(shares, decoder='bw')
            True

            sage: shares[1] = (shares[1][0], shares[1][1]+1)
            sage: secret == sss.reconstruct(shares, decoder='bw')
            True

            sage: shares[-1] = (shares[-1][0], shares[-1][1]+1)
            sage: secret == sss.reconstruct(shares, decoder='bw')
            False
        """
        # make shares iterable
        if type(shares[0]) == tuple:
            shares = [shares]

        # set decoder
        if decoder == 'lg':
            decode = self._rec_lagrange
        elif decoder == 'bw':
            decode = self._rec_berlekamp_welsh
        else:
            raise ValueError("unknown decoder.")

        # reconstruct secret
        secret = []
        for element in shares:
            # convert to field
            points = [(self._to_GF(x), self._to_GF(y)) for x,y in element]
            # call decoder
            secret.append(self._to_Int(decode(points)[0]))
        if len(secret) == 1:
            secret = secret[0]
        return secret


    def share(self, secret):
        r"""
        Generate shares.

        A polynomial of degree `k-1` is generated at random with the secret
        being the constant coefficient. It is then evaluated at points starting
        from `1`.

        INPUT:

        - ``secret`` -- the secret to be shared as integer or list of integer.

        OUTPUT:

        The shares or a list of shares, if list input.

        EXAMPLES::

            sage: from sage.crypto.smc.shamir_ss import ShamirSS

        Simple interface::

            sage: sss = ShamirSS()
            sage: secret = 42
            sage: shares = sss.share(secret)
            sage: [i+1 == share[0]  for i, share in enumerate(shares)]
            [True, True, True, True, True, True, True]

        Input vector::

            sage: sss = ShamirSS()
            sage: secret = [42, 43, 44, 45]
            sage: shares = sss.share(secret)
            sage: secret == sss.reconstruct(shares)
            True
        """
        # make input iterable
        from sage.rings.integer import Integer
        if not type(secret) == list:
            secret = [secret]
        
        # generate shares
        shares = []
        for s in secret:
            # random polynomial with s as constant coefficient
            ssp = self._to_GF(s)
            for i in range(1, self._k):
                ssp += self._F.random_element() * self._P.gen()**i

            # evaluate polynomial at different points (shares)
            shares.append([(i, self._to_Int(ssp(self._to_GF(i)))) for i in range(1, self._n+1)])
        
        if len(shares) == 1:
            shares = shares[0]
        return shares
Example #22
0
def v_4_1_rbibd(v, existence=False):
    r"""
    Return a `(v,4,1)`-RBIBD.

    INPUT:

    - `n` (integer)

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

    .. SEEALSO::

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

    .. NOTE::

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

    EXAMPLE::

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

    TESTS::

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

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

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

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

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

    BIBD = BalancedIncompleteBlockDesign(v,
                                         blocks=sum(classes, []),
                                         k=4,
                                         check=True,
                                         copy=False)
    BIBD._classes = classes
    assert BIBD.is_resolvable()
    return BIBD
Example #23
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 '\n'.join(rows)
        Day 1   Day 2   Day 3   Day 4   Day 5   Day 6   Day 7
         07e     18e     29e     3ae     4be     5ce     6de
         139     24a     35b     46c     05d     167     028
         26b     03c     14d     257     368     049     15a
         458     569     06a     01b     12c     23d     347
         acd     7bd     78c     89d     79a     8ab     9bc

    TESTS::

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

    if existence:
        return False

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

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

    # Construction 1.1 from [Stinson91] (originally Theorem 6 from [RCW71])
    #
    # For all prime powers q=1 mod 6, there exists a KTS(2q+1)
    elif ((v - 1) // 2) % 6 == 1 and is_prime_power((v - 1) // 2):
        from sage.rings.finite_rings.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
Example #24
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 projective_plane
        return projective_plane(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
Example #25
0
def hadamard_matrix_paleyII(n):
    """
    Implements the Paley type II construction.

    The Paley type II case corresponds to the case `p \cong 1 \mod{4}` for a
    prime `p` (see [Hora]_).

    EXAMPLES::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12).det()
        2985984
        sage: 12^6
        2985984

    We note that the method returns a normalised Hadamard matrix ::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12)
        [ 1  1| 1  1| 1  1| 1  1| 1  1| 1  1]
        [ 1 -1|-1  1|-1  1|-1  1|-1  1|-1  1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1| 1 -1| 1  1|-1 -1|-1 -1| 1  1]
        [ 1  1|-1 -1| 1 -1|-1  1|-1  1| 1 -1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1| 1  1| 1 -1| 1  1|-1 -1|-1 -1]
        [ 1  1| 1 -1|-1 -1| 1 -1|-1  1|-1  1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1|-1 -1| 1  1| 1 -1| 1  1|-1 -1]
        [ 1  1|-1  1| 1 -1|-1 -1| 1 -1|-1  1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1|-1 -1|-1 -1| 1  1| 1 -1| 1  1]
        [ 1  1|-1  1|-1  1| 1 -1|-1 -1| 1 -1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1| 1  1|-1 -1|-1 -1| 1  1| 1 -1]
        [ 1  1| 1 -1|-1  1|-1  1| 1 -1|-1 -1]

    TESTS::

        sage: from sage.combinat.matrices.hadamard_matrix import (hadamard_matrix_paleyII, is_hadamard_matrix)
        sage: test_cases = [2*(x+1) for x in range(50) if is_prime_power(x) and x%4==1]
        sage: all(is_hadamard_matrix(hadamard_matrix_paleyII(n),normalized=True,verbose=True)
        ....:     for n in test_cases)
        True
    """
    q = n//2 - 1
    if not(n%2==0 and is_prime_power(q) and (q % 4 == 1)):
        raise ValueError("The order %s is not covered by the Paley type II construction." % n)

    from sage.rings.finite_rings.constructor import FiniteField
    K = FiniteField(q,'x')
    K_list = list(K)
    K_list.insert(0,K.zero())
    H = matrix(ZZ, [[(1 if (x-y).is_square() else -1)
                     for x in K_list]
                    for y in K_list])
    for i in range(q+1):
        H[0,i] = 1
        H[i,0] = 1
        H[i,i] = 0

    tr = { 0: matrix(2,2,[ 1,-1,-1,-1]),
           1: matrix(2,2,[ 1, 1, 1,-1]),
          -1: matrix(2,2,[-1,-1,-1, 1])}

    H = block_matrix(q+1,q+1,[tr[v] for r in H for v in r])

    return normalise_hadamard(H)
Example #26
0
def ProjectivePlaneDesign(n, type="Desarguesian"):
    r"""
    Returns a projective plane of order `n`.

    A finite projective plane is a 2-design with `n^2+n+1` lines (or blocks) and
    `n^2+n+1` points. For more information on finite projective planes, see the
    :wikipedia:`Projective_plane#Finite_projective_planes`.

    INPUT:

    - ``n`` -- the finite projective plane's order

    - ``type`` -- When set to ``"Desarguesian"``, the method returns
      Desarguesian projective planes, i.e. a finite projective plane obtained by
      considering the 1- and 2- dimensional spaces of `F_n^3`.

      For the moment, no other value is available for this parameter.

    .. SEEALSO::

        :meth:`ProjectiveGeometryDesign`

    EXAMPLES::

        sage: designs.ProjectivePlaneDesign(2)
        Incidence structure with 7 points and 7 blocks

    Non-existent ones::

        sage: designs.ProjectivePlaneDesign(10)
        Traceback (most recent call last):
        ...
        ValueError: No projective plane design of order 10 exists.
        sage: designs.ProjectivePlaneDesign(14)
        Traceback (most recent call last):
        ...
        ValueError: By the Bruck-Ryser-Chowla theorem, no projective plane of order 14 exists.

    An unknown one::

        sage: designs.ProjectivePlaneDesign(12)
        Traceback (most recent call last):
        ...
        ValueError: If such a projective plane exists, we do not know how to build it.

    TESTS::

        sage: designs.ProjectivePlaneDesign(10, type="AnyThingElse")
        Traceback (most recent call last):
        ...
        ValueError: The value of 'type' must be 'Desarguesian'.
    """
    from sage.rings.arith import two_squares

    if type != "Desarguesian":
        raise ValueError("The value of 'type' must be 'Desarguesian'.")

    try:
        F = FiniteField(n, 'x')
    except ValueError:
        if n == 10:
            raise ValueError("No projective plane design of order 10 exists.")
        try:
            if (n % 4) in [1, 2]:
                two_squares(n)
        except ValueError:
            raise ValueError("By the Bruck-Ryser-Chowla theorem, no projective"
                             " plane of order " + str(n) + " exists.")

        raise ValueError("If such a projective plane exists, "
                         "we do not know how to build it.")

    return ProjectiveGeometryDesign(2, 1, F)
Example #27
0
def hadamard_matrix_paleyI(n, normalize=True):
    """
    Implements the Paley type I construction.

    The Paley type I case corresponds to the case `p \cong 3 \mod{4}` for a
    prime `p` (see [Hora]_).

    INPUT:

    - ``n`` -- the matrix size 

    - ``normalize`` (boolean) -- whether to normalize the result.

    EXAMPLES:

    We note that this method by default returns a normalised Hadamard matrix ::

        sage: from sage.combinat.matrices.hadamard_matrix import hadamard_matrix_paleyI
        sage: hadamard_matrix_paleyI(4)
        [ 1  1  1  1]
        [ 1 -1  1 -1]
        [ 1 -1 -1  1]
        [ 1  1 -1 -1]

    Otherwise, it returns a skew Hadamard matrix `H`, i.e. `H=S+I`, with
    `S=-S^\top`  ::

        sage: M=hadamard_matrix_paleyI(4, normalize=False); M
        [ 1  1  1  1]
        [-1  1  1 -1]
        [-1 -1  1  1]
        [-1  1 -1  1]
        sage: S=M-identity_matrix(4); -S==S.T
        True

    TESTS::

        sage: from sage.combinat.matrices.hadamard_matrix import is_hadamard_matrix
        sage: test_cases = [x+1 for x in range(100) if is_prime_power(x) and x%4==3]
        sage: all(is_hadamard_matrix(hadamard_matrix_paleyI(n),normalized=True,verbose=True)
        ....:     for n in test_cases)
        True
        sage: all(is_hadamard_matrix(hadamard_matrix_paleyI(n,normalize=False),verbose=True)
        ....:     for n in test_cases)
        True
    """
    p = n - 1
    if not(is_prime_power(p) and (p % 4 == 3)):
        raise ValueError("The order %s is not covered by the Paley type I construction." % n)

    from sage.rings.finite_rings.constructor import FiniteField
    K = FiniteField(p,'x')
    K_list = list(K)
    K_list.insert(0,K.zero())
    H = matrix(ZZ, [[(1 if (x-y).is_square() else -1)
                     for x in K_list]
                    for y in K_list])
    for i in range(n):
        H[i,0] = -1
        H[0,i] =  1
    if normalize:
        for i in range(n):
            H[i,i] = -1
        H = normalise_hadamard(H)
    return H
Example #28
0
def OA_from_Vmt(m,t,V):
    r"""
    Return 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
Example #29
0
def BCHCode(n,delta,F,b=0):
    r"""
    A 'Bose-Chaudhuri-Hockenghem code' (or BCH code for short) is the
    largest possible cyclic code of length n over field F=GF(q), whose
    generator polynomial has zeros (which contain the set)
    `Z = \{a^{b},a^{b+1}, ..., a^{b+delta-2}\}`, where a is a
    primitive `n^{th}` root of unity in the splitting field
    `GF(q^m)`, b is an integer `0\leq b\leq n-delta+1`
    and m is the multiplicative order of q modulo n. (The integers
    `b,...,b+delta-2` typically lie in the range
    `1,...,n-1`.) The integer `delta \geq 1` is called
    the "designed distance". The length n of the code and the size q of
    the base field must be relatively prime. The generator polynomial
    is equal to the least common multiple of the minimal polynomials of
    the elements of the set `Z` above.

    Special cases are b=1 (resulting codes are called 'narrow-sense'
    BCH codes), and `n=q^m-1` (known as 'primitive' BCH
    codes).

    It may happen that several values of delta give rise to the same
    BCH code. The largest one is called the Bose distance of the code.
    The true minimum distance, d, of the code is greater than or equal
    to the Bose distance, so `d\geq delta`.

    EXAMPLES::

        sage: FF.<a> = GF(3^2,"a")
        sage: x = PolynomialRing(FF,"x").gen()
        sage: L = [b.minpoly() for b in [a,a^2,a^3]]; g = LCM(L)
        sage: f = x^(8)-1
        sage: g.divides(f)
        True
        sage: C = codes.CyclicCode(8,g); C
        Linear code of length 8, dimension 4 over Finite Field of size 3
        sage: C.minimum_distance()
        4
        sage: C = codes.BCHCode(8,3,GF(3),1); C
        Linear code of length 8, dimension 4 over Finite Field of size 3
        sage: C.minimum_distance()
        4
        sage: C = codes.BCHCode(8,3,GF(3)); C
        Linear code of length 8, dimension 5 over Finite Field of size 3
        sage: C.minimum_distance()
        3
        sage: C = codes.BCHCode(26, 5, GF(5), b=1); C
        Linear code of length 26, dimension 10 over Finite Field of size 5

    """
    from sage.misc.misc import srange
    q = F.order()
    R = IntegerModRing(n)
    m = R(q).multiplicative_order()
    FF = GF(q**m,"z")
    z = FF.gen()
    e = z.multiplicative_order()/n
    a = z**e # order n
    P = PolynomialRing(F,"x")
    x = P.gen()
    cosets = Set([])
    for i in srange(b,b+delta-1):
        cosets = cosets.union(Set(cyclotomic_cosets(q, n, i)))
    L0 = [a**j for j in cosets]
    L1 = [P(ai.minpoly()) for ai in L0]
    g = P(LCM(L1))
    #print cosets, "\n", g, "\n", (x**n-1).factor(), "\n", L1, "\n", g.divides(x**n-1)
    if not(g.divides(x**n-1)):
        raise ValueError, "BCH codes does not exist with the given input."
    return CyclicCodeFromGeneratingPolynomial(n,g)
Example #30
0
def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, check_hyperoval=True):
    r"""
    Return the collinearity graph of the generalized quadrangle `T_2^*(q)`, or of its dual

    Let `q=2^k` and `\Theta=PG(3,q)`.  `T_2^*(q)` is a generalized quadrangle [GQwiki]_
    of order `(q-1,q+1)`, see 3.1.3 in [PT09]_. Fix a plane `\Pi \subset \Theta` and a
    `hyperoval <http://en.wikipedia.org/wiki/Oval_(projective_plane)#Even_q>`__
    `O \subset \Pi`. The points of `T_2^*(q):=T_2^*(O)` are the points of `\Theta`
    outside `\Pi`, and the lines are the lines of `\Theta` outside `\Pi`
    that meet `\Pi` in a point of `O`.

    INPUT:

    - ``q`` -- a power of two

    - ``dual`` -- if ``False`` (default), return the graph of `T_2^*(O)`.
      Otherwise return the graph of the dual `T_2^*(O)`.

    - ``hyperoval`` -- a hyperoval (i.e. a complete 2-arc; a set of points in the plane
      meeting every line in 0 or 2 points) in the plane of points with 0th coordinate
      0 in `PG(3,q)` over the field ``field``. Each point of ``hyperoval`` must be a length 4
      vector over ``field`` with 1st non-0 coordinate equal to 1. By default, ``hyperoval`` and
      ``field`` are not specified, and constructed on the fly. In particular, ``hyperoval``
      we build is the classical one, i.e. a conic with the point of intersection of its
      tangent lines.

    - ``field`` -- an instance of a finite field of order `q`, must be provided
      if ``hyperoval`` is provided.

    - ``check_hyperoval`` -- (default: ``True``) if ``True``,
      check ``hyperoval`` for correctness.


    EXAMPLES:

    using the built-in construction::

        sage: g=graphs.T2starGeneralizedQuadrangleGraph(4); g
        T2*(O,4); GQ(3, 5): Graph on 64 vertices
        sage: g.is_strongly_regular(parameters=True)
        (64, 18, 2, 6)
        sage: g=graphs.T2starGeneralizedQuadrangleGraph(4,dual=True); g
        T2*(O,4)*; GQ(5, 3): Graph on 96 vertices
        sage: g.is_strongly_regular(parameters=True)
        (96, 20, 4, 4)

    supplying your own hyperoval::

        sage: F=GF(4,'b')
        sage: O=[vector(F,(0,0,0,1)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F)
        sage: g=graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F); g
        T2*(O,4); GQ(3, 5): Graph on 64 vertices
        sage: g.is_strongly_regular(parameters=True)
        (64, 18, 2, 6)

    TESTS::

        sage: F=GF(4,'b') # repeating a point...
        sage: O=[vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F)
        sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F)
        Traceback (most recent call last):
        ...
        RuntimeError: incorrect hyperoval size
        sage: O=[vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F)
        sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F)
        Traceback (most recent call last):
        ...
        RuntimeError: incorrect hyperoval
    """
    from sage.combinat.designs.incidence_structures import IncidenceStructure
    from sage.combinat.designs.block_design import ProjectiveGeometryDesign as PG
    from sage.modules.free_module_element import free_module_element as vector

    p, k = is_prime_power(q,get_data=True)
    if k==0 or p!=2:
       raise ValueError('q must be a power of 2')
    if field is None:
        F = FiniteField(q, 'a')
    else:
        F = field

    Theta = PG(3, 1, F, point_coordinates=1)
    Pi = set(filter(lambda x: x[0]==F.zero(), Theta.ground_set()))
    if hyperoval is None:
        O = filter(lambda x: x[1]+x[2]*x[3]==0 or (x[1]==1 and x[2]==0 and x[3]==0), Pi)
        O = set(O)
    else:
        map(lambda x: x.set_immutable(), hyperoval)
        O = set(hyperoval)
        if check_hyperoval:
            if len(O) != q+2:
                raise RuntimeError("incorrect hyperoval size")
            for L in Theta.blocks():
                if set(L).issubset(Pi):
                    if not len(O.intersection(L)) in [0,2]:
                        raise RuntimeError("incorrect hyperoval")
    L = map(lambda z: filter(lambda y: not y in O, z),
            filter(lambda x: len(O.intersection(x)) == 1, Theta.blocks()))
    if dual:
        G = IncidenceStructure(L).intersection_graph()
        G.name('T2*(O,'+str(q)+')*; GQ'+str((q+1,q-1)))
    else:
        G = IncidenceStructure(L).dual().intersection_graph()
        G.name('T2*(O,'+str(q)+'); GQ'+str((q-1,q+1)))
    return G
def GDD_4_2(q,existence=False,check=True):
    r"""
    Return a `(2q,\{4\},\{2\})`-GDD for `q` a prime power with `q\equiv 1\pmod{6}`.

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

    INPUT:

    - ``q`` (integer)

    - ``existence`` (boolean) -- instead of building the design, return:

        - ``True`` -- meaning that Sage knows how to build the design

        - ``Unknown`` -- meaning that Sage does not know how to build the
          design, but that the design may exist (see :mod:`sage.misc.unknown`).

        - ``False`` -- meaning that the design does not exist.

    - ``check`` -- (boolean) Whether to check that output is correct before
      returning it. As this is expected to be useless (but we are cautious
      guys), you may want to disable it whenever you want speed. Set to ``True``
      by default.

    EXAMPLE::

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

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

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

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

    return GroupDivisibleDesign(2*q,
                                groups = [[i,i+1] for i in range(0,2*q,2)],
                                blocks = sum(classes,[]),
                                K      = [4],
                                G      = [2],
                                check  = check,
                                copy   = False)
Example #32
0
def GDD_4_2(q, existence=False, check=True):
    r"""
    Return a `(2q,\{4\},\{2\})`-GDD for `q` a prime power with `q\equiv 1\pmod{6}`.

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

    INPUT:

    - ``q`` (integer)

    - ``existence`` (boolean) -- instead of building the design, return:

        - ``True`` -- meaning that Sage knows how to build the design

        - ``Unknown`` -- meaning that Sage does not know how to build the
          design, but that the design may exist (see :mod:`sage.misc.unknown`).

        - ``False`` -- meaning that the design does not exist.

    - ``check`` -- (boolean) Whether to check that output is correct before
      returning it. As this is expected to be useless (but we are cautious
      guys), you may want to disable it whenever you want speed. Set to ``True``
      by default.

    EXAMPLE::

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

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

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

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

    return GroupDivisibleDesign(2 * q,
                                groups=[[i, i + 1]
                                        for i in range(0, 2 * q, 2)],
                                blocks=sum(classes, []),
                                K=[4],
                                G=[2],
                                check=check,
                                copy=False)
Example #33
0
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)
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)
        Incidence structure with 7 points and 7 blocks
        sage: designs.DesarguesianProjectivePlaneDesign(3)
        Incidence structure with 13 points and 13 blocks
        sage: designs.DesarguesianProjectivePlaneDesign(4)
        Incidence structure with 21 points and 21 blocks
        sage: designs.DesarguesianProjectivePlaneDesign(5)
        Incidence structure with 31 points and 31 blocks
        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))

    return BlockDesign(n2 + n + 1,
                       blcks,
                       name="Desarguesian projective plane of order %d" % n,
                       test=check)
Example #35
0
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
Example #36
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.matrix_gps.finitely_generated 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]  [2 1]
        [1 2], [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
    MS = MatrixSpace(FiniteField(3), 2)
    aye = MS([1,1,1,2])
    jay = MS([2,1,1,1])
    return MatrixGroup([aye, jay])
Example #37
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
Example #38
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
def BCHCode(n,delta,F,b=0):
    r"""
    A 'Bose-Chaudhuri-Hockenghem code' (or BCH code for short) is the
    largest possible cyclic code of length n over field F=GF(q), whose
    generator polynomial has zeros (which contain the set)
    `Z = \{a^{b},a^{b+1}, ..., a^{b+delta-2}\}`, where a is a
    primitive `n^{th}` root of unity in the splitting field
    `GF(q^m)`, b is an integer `0\leq b\leq n-delta+1`
    and m is the multiplicative order of q modulo n. (The integers
    `b,...,b+delta-2` typically lie in the range
    `1,...,n-1`.) The integer `delta \geq 1` is called
    the "designed distance". The length n of the code and the size q of
    the base field must be relatively prime. The generator polynomial
    is equal to the least common multiple of the minimal polynomials of
    the elements of the set `Z` above.

    Special cases are b=1 (resulting codes are called 'narrow-sense'
    BCH codes), and `n=q^m-1` (known as 'primitive' BCH
    codes).

    It may happen that several values of delta give rise to the same
    BCH code. The largest one is called the Bose distance of the code.
    The true minimum distance, d, of the code is greater than or equal
    to the Bose distance, so `d\geq delta`.

    EXAMPLES::

        sage: FF.<a> = GF(3^2,"a")
        sage: x = PolynomialRing(FF,"x").gen()
        sage: L = [b.minpoly() for b in [a,a^2,a^3]]; g = LCM(L)
        sage: f = x^(8)-1
        sage: g.divides(f)
        True
        sage: C = codes.CyclicCode(8,g); C
        Linear code of length 8, dimension 4 over Finite Field of size 3
        sage: C.minimum_distance()
        4
        sage: C = codes.BCHCode(8,3,GF(3),1); C
        Linear code of length 8, dimension 4 over Finite Field of size 3
        sage: C.minimum_distance()
        4
        sage: C = codes.BCHCode(8,3,GF(3)); C
        Linear code of length 8, dimension 5 over Finite Field of size 3
        sage: C.minimum_distance()
        3
        sage: C = codes.BCHCode(26, 5, GF(5), b=1); C
        Linear code of length 26, dimension 10 over Finite Field of size 5

    """
    q = F.order()
    R = IntegerModRing(n)
    m = R(q).multiplicative_order()
    FF = GF(q**m,"z")
    z = FF.gen()
    e = z.multiplicative_order()/n
    a = z**e # order n
    P = PolynomialRing(F,"x")
    x = P.gen()
    L1 = []
    for coset in R.cyclotomic_cosets(q, range(b,b+delta-1)):
        L1.extend(P((a**j).minpoly()) for j in coset)
    g = P(LCM(L1))
    #print cosets, "\n", g, "\n", (x**n-1).factor(), "\n", L1, "\n", g.divides(x**n-1)
    if not(g.divides(x**n-1)):
        raise ValueError("BCH codes does not exist with the given input.")
    return CyclicCodeFromGeneratingPolynomial(n,g)
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 its entries are
    element of a group `G` of cardinality `g`, and if 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

    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]

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

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

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

    return G, M
Example #41
0
def hadamard_matrix_paleyI(n, normalize=True):
    """
    Implements the Paley type I construction.

    The Paley type I case corresponds to the case `p \cong 3 \mod{4}` for a
    prime `p` (see [Hora]_).

    INPUT:

    - ``n`` -- the matrix size 

    - ``normalize`` (boolean) -- whether to normalize the result.

    EXAMPLES:

    We note that this method by default returns a normalised Hadamard matrix ::

        sage: from sage.combinat.matrices.hadamard_matrix import hadamard_matrix_paleyI
        sage: hadamard_matrix_paleyI(4)
        [ 1  1  1  1]
        [ 1 -1  1 -1]
        [ 1 -1 -1  1]
        [ 1  1 -1 -1]

    Otherwise, it returns a skew Hadamard matrix `H`, i.e. `H=S+I`, with
    `S=-S^\top`  ::

        sage: M=hadamard_matrix_paleyI(4, normalize=False); M
        [ 1  1  1  1]
        [-1  1  1 -1]
        [-1 -1  1  1]
        [-1  1 -1  1]
        sage: S=M-identity_matrix(4); -S==S.T
        True

    TESTS::

        sage: from sage.combinat.matrices.hadamard_matrix import is_hadamard_matrix
        sage: test_cases = [x+1 for x in range(100) if is_prime_power(x) and x%4==3]
        sage: all(is_hadamard_matrix(hadamard_matrix_paleyI(n),normalized=True,verbose=True)
        ....:     for n in test_cases)
        True
        sage: all(is_hadamard_matrix(hadamard_matrix_paleyI(n,normalize=False),verbose=True)
        ....:     for n in test_cases)
        True
    """
    p = n - 1
    if not(is_prime_power(p) and (p % 4 == 3)):
        raise ValueError("The order %s is not covered by the Paley type I construction." % n)

    from sage.rings.finite_rings.constructor import FiniteField
    K = FiniteField(p,'x')
    K_list = list(K)
    K_list.insert(0,K.zero())
    H = matrix(ZZ, [[(1 if (x-y).is_square() else -1)
                     for x in K_list]
                    for y in K_list])
    for i in range(n):
        H[i,0] = -1
        H[0,i] =  1
    if normalize:
        for i in range(n):
            H[i,i] = -1
        H = normalise_hadamard(H)
    return H
Example #42
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
Example #43
0
def v_4_1_rbibd(v,existence=False):
    r"""
    Return a `(v,4,1)`-RBIBD.

    INPUT:

    - `n` (integer)

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

    .. SEEALSO::

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

    .. NOTE::

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

    EXAMPLE::

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

    TESTS::

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

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

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

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

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

    BIBD = BalancedIncompleteBlockDesign(v,
                                         blocks = sum(classes,[]),
                                         k=4,
                                         check=True,
                                         copy=False)
    BIBD._classes = classes
    assert BIBD.is_resolvable()
    return BIBD
Example #44
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