Beispiel #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
Beispiel #2
0
def twin_prime_powers_difference_set(p, check=True):
    r"""
    Return a difference set on `GF(p) \times GF(p+2)`.

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

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

    For more information see :wikipedia:`Difference_set`.

    INPUT:

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

    EXAMPLES::

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

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

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

    G = cartesian_product([Fp, Fq])

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

    return G, [d]
    def __init__(self, p, use_database=True):
        """
        TESTS::

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

            sage: PCL = PseudoConwayLattice(5, use_database=False)
            sage: PCL.polynomial(12)
            x^12 + 4*x^11 + 2*x^10 + 4*x^9 + 2*x^8 + 2*x^7 + 4*x^6 + x^5 + 2*x^4 + 2*x^2 + x + 2
            sage: PCL.polynomial(6)
            x^6 + x^5 + 4*x^4 + 3*x^3 + 3*x^2 + 2*x + 2
            sage: PCL.polynomial(11)
            x^11 + x^6 + 3*x^3 + 4*x + 3
        """
        self.p = p
        from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
        self.ring = PolynomialRing(FiniteField(p), 'x')
        if use_database:
            C = sage.databases.conway.ConwayPolynomials()
            self.nodes = {
                n: self.ring(C.polynomial(p, n))
                for n in C.degrees(p)
            }
        else:
            self.nodes = {}
Beispiel #4
0
    def _test_category_contains(self, tester=None, **options):
        """
        Test the implicit __contains__ method of this category::

            sage: from yacop.modules.projective_spaces import RealProjectiveSpace
            sage: M=RealProjectiveSpace()
            sage: M.category()
            Category of yacop left module algebras over mod 2 Steenrod algebra, milnor basis
            sage: M in M.category()
            True
            sage: M._test_category_contains()

        """
        from sage.misc.lazy_format import LazyFormat
        from sage.rings.finite_rings.finite_field_constructor import FiniteField

        tester = self._tester(**options)
        tester.assertTrue(
            self in self.category(),
            LazyFormat("%s not contained in its category %s" %
                       (self, self.category())),
        )
        M = ModulesWithBasis(FiniteField(self.base_ring().characteristic()))
        tester.assertTrue(self in M,
                          LazyFormat("%s not contained in %s" % (self, M)))
Beispiel #5
0
    def __init__(self, prime=2, level=1, base_ring=ZZ):
        r"""
        Create a supersingular module.

        EXAMPLES::

            sage: SupersingularModule(3)
            Module of supersingular points on X_0(1)/F_3 over Integer Ring
        """
        if not prime.is_prime():
            raise ValueError("the argument prime must be a prime number")
        if prime.divides(level):
            raise ValueError(
                "the argument level must be coprime to the argument prime")
        if level != 1:
            raise NotImplementedError(
                "supersingular modules of level > 1 not yet implemented")
        self.__prime = prime
        self.__finite_field = FiniteField(prime**2, 'a')
        self.__level = level
        self.__hecke_matrices = {}
        hecke.HeckeModule_free_module.__init__(self,
                                               base_ring,
                                               prime * level,
                                               weight=2)
Beispiel #6
0
    def __classcall__(cls, *args, **kwds):
        """
        Normalize input to ensure a unique representation.

        EXAMPLES::

            sage: A = AffineSpace(2, GF(4,'a'))
            sage: AffineGroup(A) is AffineGroup(2,4)
            True
            sage: AffineGroup(A) is AffineGroup(2, GF(4,'a'))
            True
            sage: A = AffineGroup(2, QQ)
            sage: V = QQ^2
            sage: A is AffineGroup(V)
            True
        """
        if len(args) == 1:
            V = args[0]
            if isinstance(V, AffineGroup):
                return V
            try:
                degree = V.dimension_relative()
            except AttributeError:
                degree = V.dimension()
            ring = V.base_ring()
        if len(args) == 2:
            degree, ring = args
            from sage.rings.integer import is_Integer
            if is_Integer(ring):
                from sage.rings.finite_rings.finite_field_constructor import FiniteField
                var = kwds.get('var', 'a')
                ring = FiniteField(ring, var)
        return super(AffineGroup, cls).__classcall__(cls, degree, ring)
Beispiel #7
0
    def __init__(this, p, category=None):
        """
        TESTS::

            sage: from yacop.testing.testalgebra import Testclass1
            sage: X=Testclass1(5)
            sage: X.monomial((2,1,8,0))
            x^2*a*y^8
            sage: X.monomial((3,0,-17,1))
            x^3*b/y^17

            sage: from yacop.utils.region import region
            sage: X._manual_test_left_action(region(tmax=20))
            1126 non-zero multiplications checked
            sage: X._manual_test_left_conj_action(region(tmax=20)) # long time
            1148 non-zero multiplications checked

        """
        # must admit the "category" keyword for suspendability
        R = PolynomialRing(FiniteField(p), "x,a,y,b")
        x, a, y, b = R.gens()
        I = R.ideal([a**2, b**2])
        degs = lambda idx: (1, -1, 0) if (idx & 1) else (2, 0, 0)
        SteenrodAlgebraBase.__init__(this,
                                     R, [degs(n) for n in range(4)],
                                     I,
                                     SteenrodAlgebra(p),
                                     category=category)
Beispiel #8
0
    def upper_bound_on_elliptic_factors(self, p=None, ellmax=2):
        r"""
        Return an upper bound (provably correct) on the number of
        elliptic curves of conductor equal to the level of this
        supersingular module.

        INPUT:

        - ``p`` -- (default: 997) prime to work modulo

        ALGORITHM: Currently we only use `T_2`.  Function will be
        extended to use more Hecke operators later.

        The prime p is replaced by the smallest prime that does not
        divide the level.

        EXAMPLES::

            sage: SupersingularModule(37).upper_bound_on_elliptic_factors()
            2

        (There are 4 elliptic curves of conductor 37, but only 2 isogeny
        classes.)
        """
        from sage.misc.verbose import verbose

        # NOTE: The heuristic runtime is *very* roughly `p^2/(2\cdot 10^6)`.
        # ellmax -- (default: 2) use Hecke operators T_ell with ell <= ellmax
        if p is None:
            p = 997

        while self.level() % p == 0:
            p = next_prime(p)

        ell = 2
        t = self.hecke_matrix(ell).change_ring(FiniteField(p))

        # TODO: temporarily try using sparse=False
        # turn this off when sparse rank is optimized.
        t = t.dense_matrix()

        B = ZZ(4 * ell).isqrt()
        bnd = 0
        lower = -B
        upper = B + 1
        for a in range(lower, upper):
            tm = verbose("computing T_%s - %s" % (ell, a))
            if a == lower:
                c = a
            else:
                c = 1
            for i in range(t.nrows()):
                t[i, i] += c
            tm = verbose("computing kernel", tm)
            # dim = t.kernel().dimension()
            dim = t.nullity()
            bnd += dim
            verbose('got dimension = %s; new bound = %s' % (dim, bnd), tm)
        return bnd
Beispiel #9
0
def steenrod_algebra_intersect(algebras):
    """
    TESTS::

         sage: from yacop.categories.utils import steenrod_algebra_intersect
         sage: A = SteenrodAlgebra(3)
         sage: B = SteenrodAlgebra(3,profile=((1,),(2,2)))
         sage: C = SteenrodAlgebra(3,profile=((),(1,2)))
         sage: steenrod_algebra_intersect((A,B))
         sub-Hopf algebra of mod 3 Steenrod algebra, milnor basis, profile function ([1], [2, 2])
         sage: steenrod_algebra_intersect((A,GF(3),A))
         Finite Field of size 3
    """
    from sage.algebras.steenrod.steenrod_algebra import SteenrodAlgebra

    for dummy in (0,):
        A0 = algebras[0]
        if not all(A.characteristic() == A0.characteristic() for A in algebras):
            break
        for A in algebras:
            if not hasattr(A, "is_generic"):
                # this algebra is not a Steenrod algebra
                return FiniteField(A.characteristic())
        if not all(A.is_generic() == A0.is_generic() for A in algebras):
            break
        rtrunc = +Infinity if all(A._truncation_type > 0 for A in algebras) else 0
        isgen = A0.is_generic()
        profiles = (
            [A._profile for A in algebras]
            if isgen
            else [(A._profile, ()) for A in algebras]
        )
        proflen = max(
            [
                0,
            ]
            + [len(p[0]) for p in profiles]
            + [len(p[1]) for p in profiles]
        )
        nprof0 = [
            min(A.profile(i, component=0) for A in algebras)
            for i in range(1, proflen + 1)
        ]
        nprof1 = [
            min(A.profile(i, component=1) for A in algebras) for i in range(0, proflen)
        ]
        prof = (nprof0, nprof1) if isgen else nprof0
        # return prof
        res = SteenrodAlgebra(
            A0.prime(), generic=isgen, profile=prof, truncation_type=rtrunc
        )
        return res
    raise ValueError("algebras not compatible")
Beispiel #10
0
def category_meet(self, other):
    """
    TESTS::
        sage: from yacop.categories.utils import category_meet
        sage: from yacop.categories.left_modules import YacopLeftModules
        sage: from yacop.categories.right_modules import YacopRightModules
        sage: A3=YacopLeftModules(SteenrodAlgebra(3))
        sage: category_meet(A3,A3)
        Category of yacop left modules over mod 3 Steenrod algebra, milnor basis
        sage: category_meet(A3,Modules(GF(3)))
        Category of vector spaces over Finite Field of size 3
        sage: A2=YacopLeftModules(SteenrodAlgebra(2))
        sage: B2=YacopLeftModules(SteenrodAlgebra(2,profile=(2,1,1)))
        sage: category_meet(A2,B2)
        Category of yacop left modules over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [2, 1, 1]
        sage: A2=YacopRightModules(SteenrodAlgebra(2))
        sage: B2=YacopRightModules(SteenrodAlgebra(2,profile=(2,1,1)))
        sage: category_meet(A2,B2)
        Category of yacop right modules over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [2, 1, 1]

    """

    import yacop.categories

    oR = other.base_ring()
    B = steenrod_algebra_intersect((self.base_ring(), oR))
    if not hasattr(B, "is_generic"):
        return Modules(FiniteField(B.characteristic()))

    is_algebra = self._yacop_has_multiplication() and other._yacop_has_multiplication()
    is_right = self._yacop_has_right_action() and other._yacop_has_right_action()
    is_left = self._yacop_has_left_action() and other._yacop_has_left_action()
    is_bimod = is_left and is_right

    if is_algebra:
        if is_bimod:
            return yacop.categories.bimodules.YacopBimoduleAlgebras(B)
        elif is_right:
            return yacop.categories.right_modules.YacopRightModuleAlgebras(B)
        else:
            return yacop.categories.left_modules.YacopLeftModuleAlgebras(B)
    else:
        if is_bimod:
            return yacop.categories.bimodules.YacopBimodules(B)
        elif is_right:
            return yacop.categories.right_modules.YacopRightModules(B)
        else:
            return yacop.categories.left_modules.YacopLeftModules(B)
Beispiel #11
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 time
        """
        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)
Beispiel #12
0
def conway_polynomial(p, n):
    """
    Return the Conway polynomial of degree `n` over ``GF(p)``.

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

    INPUT:

    - ``p`` -- prime number

    - ``n`` -- positive integer

    OUTPUT:

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

    .. NOTE::

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

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

    EXAMPLES::

        sage: conway_polynomial(2,5)
        x^5 + x^2 + 1
        sage: conway_polynomial(101,5)
        x^5 + 2*x + 99
        sage: conway_polynomial(97,101)
        Traceback (most recent call last):
        ...
        RuntimeError: requested Conway polynomial not in database.
    """
    (p, n) = (int(p), int(n))
    R = FiniteField(p)['x']
    try:
        return R(sage.databases.conway.ConwayPolynomials()[p][n])
    except KeyError:
        raise RuntimeError("requested Conway polynomial not in database.")
Beispiel #13
0
    def _subfield(self, n):
        """
        Return the unique subfield of degree `n` of ``self``.

        EXAMPLES::

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

        """
        if n == 1:
            return self.base_ring()
        else:
            from sage.rings.finite_rings.finite_field_constructor import FiniteField
            return FiniteField(self.base_ring().cardinality()**n,
                               name=self.variable_name() + str(n),
                               modulus=self._get_polynomial(n),
                               check_irreducible=False)
 def generate_wp_candidates(self, p, ideal_p, **kwargs):
     eps = self.eps
     q = self.q
     for a, b in product(range(q), repeat=2):
         if (p**2 * a**2 - b**2 * eps - p) % (q) == 0:
             verbose('Found a=%s, b=%s' % (a, b))
             break
     c = (self.GFq(p)**-1 * b * eps).lift()
     d = a
     a, b, c, d = lift(matrix(ZZ, 2, 2, [p * a, b, c, d]), q).list()
     Fp = FiniteField(p)
     if c % p == 0:
         c += a * q
         d += b * q
     assert c % p != 0
     r = (Fp(-a) * Fp(c * q)**-1).lift()
     a += q * c * r
     b += q * d * r
     ans = matrix(ZZ, 2, 2, [a, b, p * c, p * d])
     ans.set_immutable()
     yield ans
Beispiel #15
0
    def __init__(self, field=None):
        """
        Create a shrinking generator cryptosystem.

        INPUT: A string monoid over a binary alphabet.

        OUTPUT:

        EXAMPLES::

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

        EXAMPLES::

            sage: k.<a> = GF(3)
            sage: k.polynomial()
            x
        """
        if name is None:
            name = self.variable_name()
        try:
            return self.__polynomial[name]
        except AttributeError:
            from sage.rings.finite_rings.finite_field_constructor import FiniteField
            R = FiniteField(self.characteristic())[name]
            f = self[name]([0, 1])
            try:
                self.__polynomial[name] = f
            except (KeyError, AttributeError):
                self.__polynomial = {}
                self.__polynomial[name] = f
            return f
Beispiel #17
0
def normalize_args_vectorspace(*args, **kwds):
    """
    Normalize the arguments that relate to a vector space.

    INPUT:

    Something that defines an affine space. For example

    * An affine space itself:

      - ``A`` -- affine space

    * A vector space:

      - ``V`` -- a vector space

    * Degree and base ring:

      - ``degree`` -- integer. The degree of the affine group, that
        is, the dimension of the affine space the group is acting on.

      - ``ring`` -- a ring or an integer. The base ring of the affine
        space. If an integer is given, it must be a prime power and
        the corresponding finite field is constructed.

      - ``var='a'`` -- optional keyword argument to specify the finite
        field generator name in the case where ``ring`` is a prime
        power.

    OUTPUT:

    A pair ``(degree, ring)``.

    TESTS::

        sage: from sage.groups.matrix_gps.named_group import normalize_args_vectorspace
        sage: A = AffineSpace(2, GF(4,'a'));  A
        Affine Space of dimension 2 over Finite Field in a of size 2^2
        sage: normalize_args_vectorspace(A)
        (2, Finite Field in a of size 2^2)

        sage: normalize_args_vectorspace(2,4)   # shorthand
        (2, Finite Field in a of size 2^2)

        sage: V = ZZ^3;  V
        Ambient free module of rank 3 over the principal ideal domain Integer Ring
        sage: normalize_args_vectorspace(V)
        (3, Integer Ring)

        sage: normalize_args_vectorspace(2, QQ)
        (2, Rational Field)
    """
    from sage.rings.all import ZZ
    if len(args) == 1:
        V = args[0]
        try:
            degree = V.dimension_relative()
        except AttributeError:
            degree = V.dimension()
        ring = V.base_ring()
    if len(args) == 2:
        degree, ring = args
        try:
            ring = ZZ(ring)
            from sage.rings.finite_rings.finite_field_constructor import FiniteField
            var = kwds.get('var', 'a')
            ring = FiniteField(ring, var)
        except (ValueError, TypeError):
            pass
    return (ZZ(degree), ring)
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: next(b for b in blocks if p in b and q in b)

        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')
    F = FiniteField(q, prefix='y')
    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, 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 through 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 relabeled from n^2 to n^2 + n - 1
    line_infinity = lambda x: n2 + relabel[x]

    # - the point is [1:0:0] and gets relabeled 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
Beispiel #20
0
def self_orthogonal_binary_codes(n,
                                 k,
                                 b=2,
                                 parent=None,
                                 BC=None,
                                 equal=False,
                                 in_test=None):
    """
    Returns a Python iterator which generates a complete set of
    representatives of all permutation equivalence classes of
    self-orthogonal binary linear codes of length in ``[1..n]`` and
    dimension in ``[1..k]``.

    INPUT:

    -  ``n`` - Integer, maximal length

    -  ``k`` - Integer, maximal dimension

    -  ``b`` - Integer, requires that the generators all have weight divisible
       by ``b`` (if ``b=2``, all self-orthogonal codes are generated, and if
       ``b=4``, all doubly even codes are generated). Must be an even positive
       integer.

    -  ``parent`` - Used in recursion (default: ``None``)

    -  ``BC`` - Used in recursion (default: ``None``)

    -  ``equal`` - If ``True`` generates only [n, k] codes (default: ``False``)

    -  ``in_test`` - Used in recursion (default: ``None``)

    EXAMPLES:

    Generate all self-orthogonal codes of length up to 7 and dimension up
    to 3::

        sage: for B in codes.databases.self_orthogonal_binary_codes(7,3):
        ....:    print(B)
        [2, 1] linear code over GF(2)
        [4, 2] linear code over GF(2)
        [6, 3] linear code over GF(2)
        [4, 1] linear code over GF(2)
        [6, 2] linear code over GF(2)
        [6, 2] linear code over GF(2)
        [7, 3] linear code over GF(2)
        [6, 1] linear code over GF(2)

    Generate all doubly-even codes of length up to 7 and dimension up
    to 3::

        sage: for B in codes.databases.self_orthogonal_binary_codes(7,3,4):
        ....:    print(B); print(B.generator_matrix())
        [4, 1] linear code over GF(2)
        [1 1 1 1]
        [6, 2] linear code over GF(2)
        [1 1 1 1 0 0]
        [0 1 0 1 1 1]
        [7, 3] linear code over GF(2)
        [1 0 1 1 0 1 0]
        [0 1 0 1 1 1 0]
        [0 0 1 0 1 1 1]

    Generate all doubly-even codes of length up to 7 and dimension up
    to 2::

        sage: for B in codes.databases.self_orthogonal_binary_codes(7,2,4):
        ....:    print(B); print(B.generator_matrix())
        [4, 1] linear code over GF(2)
        [1 1 1 1]
        [6, 2] linear code over GF(2)
        [1 1 1 1 0 0]
        [0 1 0 1 1 1]

    Generate all self-orthogonal codes of length equal to 8 and
    dimension equal to 4::

        sage: for B in codes.databases.self_orthogonal_binary_codes(8, 4, equal=True):
        ....:     print(B); print(B.generator_matrix())
        [8, 4] linear code over GF(2)
        [1 0 0 1 0 0 0 0]
        [0 1 0 0 1 0 0 0]
        [0 0 1 0 0 1 0 0]
        [0 0 0 0 0 0 1 1]
        [8, 4] linear code over GF(2)
        [1 0 0 1 1 0 1 0]
        [0 1 0 1 1 1 0 0]
        [0 0 1 0 1 1 1 0]
        [0 0 0 1 0 1 1 1]

    Since all the codes will be self-orthogonal, b must be divisible by
    2::

        sage: list(codes.databases.self_orthogonal_binary_codes(8, 4, 1, equal=True))
        Traceback (most recent call last):
        ...
        ValueError: b (1) must be a positive even integer.
    """
    from sage.rings.finite_rings.finite_field_constructor import FiniteField
    from sage.matrix.constructor import Matrix

    d = int(b)
    if d != b or d % 2 == 1 or d <= 0:
        raise ValueError("b (%s) must be a positive even integer." % b)
    from .linear_code import LinearCode
    from .binary_code import BinaryCode, BinaryCodeClassifier
    if k < 1 or n < 2:
        return
    if equal:
        in_test = lambda M: (M.ncols() - M.nrows()) <= (n - k)
        out_test = lambda C: (C.dimension() == k) and (C.length() == n)
    else:
        in_test = lambda M: True
        out_test = lambda C: True
    if BC is None:
        BC = BinaryCodeClassifier()
    if parent is None:
        for j in range(d, n + 1, d):
            M = Matrix(FiniteField(2), [[1] * j])
            if in_test(M):
                for N in self_orthogonal_binary_codes(n,
                                                      k,
                                                      d,
                                                      M,
                                                      BC,
                                                      in_test=in_test):
                    if out_test(N): yield N
    else:
        C = LinearCode(parent)
        if out_test(C): yield C
        if k == parent.nrows():
            return
        for nn in range(parent.ncols() + 1, n + 1):
            if in_test(parent):
                for child in BC.generate_children(BinaryCode(parent), nn, d):
                    for N in self_orthogonal_binary_codes(n,
                                                          k,
                                                          d,
                                                          child,
                                                          BC,
                                                          in_test=in_test):
                        if out_test(N): yield N
    def __init__(self,
                 q,
                 level,
                 info_magma=None,
                 grouptype=None,
                 magma=None,
                 compute_presentation=True):
        from sage.modular.arithgroup.congroup_gamma import Gamma_constructor
        assert grouptype in ['SL2', 'PSL2']
        self._grouptype = grouptype
        self._compute_presentation = compute_presentation
        self.magma = magma
        self.F = QQ
        self.q = ZZ(q)
        self.discriminant = ZZ(1)
        self.level = ZZ(level / self.q)
        if self.level != 1 and compute_presentation:
            raise NotImplementedError
        self._Gamma = Gamma_constructor(self.q)
        self._Gamma_farey = self._Gamma.farey_symbol()
        self.F_units = []
        self._prec_inf = -1

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

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

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

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

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

        ArithGroup_generic.__init__(self)
        Parent.__init__(self)
Beispiel #22
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.finite_field_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])
Beispiel #23
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.finite_field_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
Beispiel #24
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 [HL1999]_, 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.

        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
        n = Integer(n)

        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.items():
            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
Beispiel #25
0
def _helper_payley_matrix(n, zero_position=True):
    r"""
    Return the matrix constructed in Lemma 1.19 page 291 of [SWW72]_.

    This function return a `n^2` matrix `M` whose rows/columns are indexed by
    the element of a finite field on `n` elements `x_1,...,x_n`. The value
    `M_{i,j}` is equal to `\chi(x_i-x_j)`.

    The elements `x_1,...,x_n` are ordered in such a way that the matrix
    (respectively, its submatrix obtained by removing first row and first column in the case
    ``zero_position=False``) is symmetric with respect to its second diagonal.
    The matrix is symmetric if `n=4k+1`, and skew-symmetric otherwise.

    INPUT:

    - ``n`` -- an odd prime power.

    - ``zero_position`` -- if it is true (default), place 0 of ``F_n`` in the middle,
      otherwise place it first.

    .. SEEALSO::

        :func:`rshcd_from_close_prime_powers`

    EXAMPLES::

        sage: from sage.combinat.matrices.hadamard_matrix import _helper_payley_matrix
        sage: _helper_payley_matrix(5)
        [ 0  1  1 -1 -1]
        [ 1  0 -1  1 -1]
        [ 1 -1  0 -1  1]
        [-1  1 -1  0  1]
        [-1 -1  1  1  0]

    TESTS::

        sage: _helper_payley_matrix(11,zero_position=True)
        [ 0 -1  1 -1 -1  1 -1  1  1  1 -1]
        [ 1  0 -1  1 -1 -1 -1 -1  1  1  1]
        [-1  1  0 -1  1  1 -1 -1 -1  1  1]
        [ 1 -1  1  0 -1  1  1 -1 -1 -1  1]
        [ 1  1 -1  1  0  1 -1  1 -1 -1 -1]
        [-1  1 -1 -1 -1  0  1  1  1 -1  1]
        [ 1  1  1 -1  1 -1  0 -1  1 -1 -1]
        [-1  1  1  1 -1 -1  1  0 -1  1 -1]
        [-1 -1  1  1  1 -1 -1  1  0 -1  1]
        [-1 -1 -1  1  1  1  1 -1  1  0 -1]
        [ 1 -1 -1 -1  1 -1  1  1 -1  1  0]
        sage: _helper_payley_matrix(11,zero_position=False)
        [ 0 -1  1 -1 -1 -1  1  1  1 -1  1]
        [ 1  0 -1  1 -1 -1 -1  1  1  1 -1]
        [-1  1  0 -1  1 -1 -1 -1  1  1  1]
        [ 1 -1  1  0 -1  1 -1 -1 -1  1  1]
        [ 1  1 -1  1  0 -1  1 -1 -1 -1  1]
        [ 1  1  1 -1  1  0 -1  1 -1 -1 -1]
        [-1  1  1  1 -1  1  0 -1  1 -1 -1]
        [-1 -1  1  1  1 -1  1  0 -1  1 -1]
        [-1 -1 -1  1  1  1 -1  1  0 -1  1]
        [ 1 -1 -1 -1  1  1  1 -1  1  0 -1]
        [-1  1 -1 -1 -1  1  1  1 -1  1  0]
    """
    from sage.rings.finite_rings.finite_field_constructor import FiniteField
    K = FiniteField(n, prefix='x')

    # Order the elements of K in K_list
    # so that K_list[i] = -K_list[n - i - 1]
    K_pairs = set(tuple(sorted([x, -x])) for x in K if x)
    K_list = [K.zero()] * n
    shift = 0 if zero_position else 1

    for i, (x, y) in enumerate(sorted(K_pairs)):
        K_list[i + shift] = x
        K_list[-i - 1] = y

    M = matrix(ZZ, n, n, [(1 if (x - y).is_square() else -1) for x in K_list
                          for y in K_list])
    M -= I(n)
    assert (M * J(n)).is_zero()
    assert M * M.transpose() == n * I(n) - J(n)
    return M
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
Beispiel #27
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.finite_field_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)
Beispiel #28
0
    def __init__(self,
                 resolution,
                 module,
                 filename=":memory:",
                 tempdb=False,
                 debug=False):

        import os

        if os.getenv("YACOP_FORCE_PRIVATE_CACHE") == "Y":
            # used for parallel doctesting to avoid conflicts
            # between doctest processes
            filename = filename.replace("cache=shared", "cache=private")

        self.reference_resolution = resolution
        resolution = resolution._worker

        if not isinstance(resolution, GFR):
            raise ValueError("first argument is not a resolution")

        self._resolution = resolution
        self._viewtype = resolution._viewtype
        self._module = module
        self._filename = filename
        self._tempdb = tempdb
        self._prime = self._resolution._prime
        self._gf = FiniteField(self._prime)
        self._errorhandler = None
        self.tcl = Yacop.Interpreter()

        modbbox = module.bbox()
        self._msmin = modbbox.smin
        self._mtmin = modbbox.tmin
        self._memin = modbbox.emin
        if self._msmin is -Infinity:
            raise ValueError("module not bounded from below: smin=%s" %
                             self._msmin)
        if self._mtmin is -Infinity:
            raise ValueError("module not bounded from below: tmin=%s" %
                             self._mtmin)
        if self._memin is -Infinity:
            raise ValueError("module not bounded from below: emin=%s" %
                             self._memin)

        if self._viewtype == "even":
            self._tfactor = 2
        else:
            self._tfactor = 1

        # link the resolution into our Tcl interpreter
        self._resip = resolution.tcl.eval("namespace current")
        self.tcl.createcommand("sagemod", self._tclmodule)
        self.tcl.createcommand("errorCallback", self._errorcallback)

        spolyfunc = "sagepoly_%s" % resolution._viewtype

        self.tcl.eval("""
           yacop::smashres create smashprod {%s::resolution} {%s} [namespace current]::sagemod [namespace current]::errorCallback {%s}
           smashprod setDebug %s
           proc smashprod_fragment_iterator query {
               yield "start"
               set q [subst {
                   select
                   pydict('s',sg.sdeg,'i',sg.ideg,'e',sg.edeg,
                   'srcrgen',sg.resgen, 'srcmod', m.sagename,
                   'data', %s(%d,group_concat(frag_decode(f.format, f.data), ' ')),
                   'tarmod', tm.sagename, 'tarrgen', tg.resgen) as p
                   from smash_generators sg
                   join module_generators m on m.rowid = sg.modgen
                   join smash_fragments f on f.srcgen = sg.rowid
                   join smash_generators tg on tg.rowid = f.targen
                   join module_generators tm on tm.rowid = tg.modgen
                    $query
                    group by f.srcgen, f.targen
                    order by sg.ideg-sg.sdeg, sg.edeg, sg.sdeg
               }]
               smashprod db eval $q {
                   yield $p
               }
           }
           """ % (
            self._resip,
            self._module,
            self._filename,
            debug,
            spolyfunc,
            resolution._prime,
        ))