Example #1
0
    def __init__(self, m, n):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: TestSuite(C).run()
            sage: C = ColoredPermutations(2, 3)
            sage: TestSuite(C).run()
            sage: C = ColoredPermutations(1, 3)
            sage: TestSuite(C).run()
        """
        if m <= 0:
            raise ValueError("m must be a positive integer")
        self._m = ZZ(m)
        self._n = ZZ(n)
        self._C = IntegerModRing(self._m)
        self._P = Permutations(self._n)

        if self._m == 1 or self._m == 2:
            from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups
            category = FiniteCoxeterGroups().Irreducible()
        else:
            from sage.categories.complex_reflection_groups import ComplexReflectionGroups
            category = ComplexReflectionGroups().Finite().Irreducible(
            ).WellGenerated()
        Parent.__init__(self, category=category)
Example #2
0
 def _denominator():
     R = PolynomialRing(ZZ, "T")
     T = R.gen()
     denom = R(1)
     lc = self._f.list()[-1]
     if lc == 1:  # MONIC
         for i in range(2, self._delta + 1):
             if self._delta % i == 0:
                 phi = euler_phi(i)
                 G = IntegerModRing(i)
                 ki = G(self._q).multiplicative_order()
                 denom = denom * (T**ki - 1)**(phi // ki)
         return denom
     else:  # Non-monic
         x = PolynomialRing(self._Fq, "x").gen()
         f = x**self._delta - lc
         L = f.splitting_field("a")
         roots = [r for r, _ in f.change_ring(L).roots()]
         roots_dict = dict([(r, i) for i, r in enumerate(roots)])
         rootsfrob = [
             L.frobenius_endomorphism(self._Fq.degree())(r)
             for r in roots
         ]
         m = zero_matrix(len(roots))
         for i, r in enumerate(roots):
             m[i, roots_dict[rootsfrob[i]]] = 1
     return R(R(m.characteristic_polynomial()) // (T - 1))
def mass_at_two_by_counting_mod_power(self, k):
    """
    Computes the local mass at `p=2` assuming that it's stable `(mod 2^k)`.

    Note: This is **way** too slow to be useful, even when k=1!!!

    TO DO: Remove this routine, or try to compile it!


    INPUT:

        k -- an integer >= 1

    OUTPUT:

        a rational number

    EXAMPLES::

        sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1])
        sage: Q.mass_at_two_by_counting_mod_power(1)
        4

    """
    R = IntegerModRing(2**k)
    Q1 = self.base_change_to(R)
    n = self.dim()
    MS = MatrixSpace(R, n)

    ct = sum([1 for x in mrange([2**k] * (n**2))
              if Q1(MS(x)) == Q1])  ## Count the solutions mod 2^k
    two_mass = ZZ(1) / 2 * (ZZ(ct) / ZZ(2)**(k * n * (n - 1) / 2))
    return two_mass
    def __init__(self, m, n):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: TestSuite(C).run()
            sage: C = ColoredPermutations(2, 3)
            sage: TestSuite(C).run()
            sage: C = ColoredPermutations(1, 3)
            sage: TestSuite(C).run()
        """
        if m <= 0:
            raise ValueError("m must be a positive integer")
        self._m = ZZ(m)
        self._n = ZZ(n)
        self._C = IntegerModRing(self._m)
        self._P = Permutations(self._n)

        if self._m == 1 or self._m == 2:
            from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups
            category = FiniteCoxeterGroups().Irreducible()
        else:
            from sage.categories.complex_reflection_groups import ComplexReflectionGroups
            category = ComplexReflectionGroups().Finite().Irreducible().WellGenerated()
        Parent.__init__(self, category=category)
Example #5
0
    def __init__(self, m, n, category=None):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: TestSuite(C).run()
            sage: C = ColoredPermutations(2, 3)
            sage: TestSuite(C).run()
            sage: C = ColoredPermutations(1, 3)
            sage: TestSuite(C).run()
        """
        if m <= 0:
            raise ValueError("m must be a positive integer")
        self._m = m
        self._n = n
        self._C = IntegerModRing(self._m)
        self._P = Permutations(self._n)
        if category is None:
            category = (Groups(), FiniteEnumeratedSets())
        Parent.__init__(self, category=category)
Example #6
0
    def degree_on_basis(self, i):
        r"""
        Return the degree of the basis element indexed by ``i``,
        which is ``i`` mod `p`.

        EXAMPLES::

            sage: L = lie_algebras.pwitt(Zmod(5), 5)
            sage: L.degree_on_basis(7)
            2
            sage: L.degree_on_basis(2).parent()
            Ring of integers modulo 5
        """
        return IntegerModRing(self._p)(i)
Example #7
0
    def __init__(self, n):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: B = crystals.infinity.Multisegments(2)
            sage: TestSuite(B).run()
        """
        self._cartan_type = CartanType(['A', n, 1])
        self._Zn = IntegerModRing(n + 1)
        Parent.__init__(self,
                        category=(HighestWeightCrystals(),
                                  InfiniteEnumeratedSets()))
        self.module_generators = (self.highest_weight_vector(), )
Example #8
0
    def example(self):
        """
        EXAMPLES::

            sage: M = Semigroups().SetsWithAction().example()
            sage: TestSuite(M).run(skip = ["_test_pickling"])

        """
        from sage.monoids.representations import SetWithAction
        from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
        from sage.sets.finite_set_maps import FiniteSetMaps
        from sage.combinat.automatic_monoid import AutomaticMonoid
        from sage.sets.family import Family
        from sage.combinat.j_trivial_monoids import SubFiniteMonoidsOfFunctions

        Z = IntegerModRing(10)
        ambient = FiniteSetMaps(Z)
        S = AutomaticMonoid(Family({2: ambient(lambda x: 2*x), 3: ambient(lambda x: 3*x) }), category=SubFiniteMonoidsOfFunctions())
        M = SetWithAction(S, Z, action = lambda f,m: f(m))
        M.rename("Representation of the monoid generated by <2,3> acting on Z/10 Z by multiplication")
        return M
Example #9
0
    def __init__(self, m, n, category=None):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: TestSuite(C).run()
            sage: C = ColoredPermutations(2, 3)
            sage: TestSuite(C).run()
            sage: C = ColoredPermutations(1, 3)
            sage: TestSuite(C).run()
        """
        if m <= 0:
            raise ValueError("m must be a positive integer")
        self._m = m
        self._n = n
        self._C = IntegerModRing(self._m)
        self._P = Permutations(self._n)
        if category is None:
            category = (Groups(), FiniteEnumeratedSets())
        Parent.__init__(self, category=category)
Example #10
0
    def __init__(self, e, multicharge=(0,)):
        r"""
        Initialise the parent class for residue sequences.

        EXAMPLES::

            sage: from sage.combinat.tableau_residues import ResidueSequences
            sage: ResidueSequences(e=0, multicharge=(0,1,2))
            0-residue sequences with multicharge (0, 1, 2)
            sage: ResidueSequences(e=0, multicharge=(0,1,2)) == ResidueSequences(e=0, multicharge=(0,1,2))
            True
            sage: ResidueSequences(e=0, multicharge=(0,1,2)) == ResidueSequences(e=3, multicharge=(0,1,2))
            False

        The TestSuite fails ``_test_pickling` because ``__getitem__`` does
        not support slices, so we skip this::

            sage: R = ResidueSequences(e=0, multicharge=(0,1,2))
            sage: TestSuite(R).run(skip='_test_elements')
        """
        self._quantum_characteristic = e
        self._base_ring = IntegerModRing(self._quantum_characteristic)
        self._multicharge = tuple(self._base_ring(i) for i in multicharge)
        super(ResidueSequences, self).__init__(category=Sets())
Example #11
0
def gen_lattice(type='modular', n=4, m=8, q=11, seed=None,
                quotient=None, dual=False, ntl=False, lattice=False):
    r"""
    This function generates different types of integral lattice bases
    of row vectors relevant in cryptography.

    Randomness can be set either with ``seed``, or by using
    :func:`sage.misc.randstate.set_random_seed`.

    INPUT:

    - ``type`` -- one of the following strings
        - ``'modular'`` (default) -- A class of lattices for which
          asymptotic worst-case to average-case connections hold. For
          more refer to [Aj1996]_.
        - ``'random'`` -- Special case of modular (n=1). A dense class
          of lattice used for testing basis reduction algorithms
          proposed by Goldstein and Mayer [GM2002]_.
        - ``'ideal'`` -- Special case of modular. Allows for a more
          compact representation proposed by [LM2006]_.
        - ``'cyclotomic'`` -- Special case of ideal. Allows for
          efficient processing proposed by [LM2006]_.
    - ``n`` -- Determinant size, primal:`det(L) = q^n`, dual:`det(L) = q^{m-n}`.
      For ideal lattices this is also the degree of the quotient polynomial.
    - ``m`` -- Lattice dimension, `L \subseteq Z^m`.
    - ``q`` -- Coefficient size, `q-Z^m \subseteq L`.
    - ``seed`` -- Randomness seed.
    - ``quotient`` -- For the type ideal, this determines the quotient
      polynomial. Ignored for all other types.
    - ``dual`` -- Set this flag if you want a basis for `q-dual(L)`, for example
      for Regev's LWE bases [Reg2005]_.
    - ``ntl`` -- Set this flag if you want the lattice basis in NTL readable
      format.
    - ``lattice`` -- Set this flag if you want a
      :class:`FreeModule_submodule_with_basis_integer` object instead
      of an integer matrix representing the basis.

    OUTPUT: ``B`` a unique size-reduced triangular (primal: lower_left,
      dual: lower_right) basis of row vectors for the lattice in question.

    EXAMPLES:

    Modular basis::

        sage: sage.crypto.gen_lattice(m=10, seed=42)
        [11  0  0  0  0  0  0  0  0  0]
        [ 0 11  0  0  0  0  0  0  0  0]
        [ 0  0 11  0  0  0  0  0  0  0]
        [ 0  0  0 11  0  0  0  0  0  0]
        [ 2  4  3  5  1  0  0  0  0  0]
        [ 1 -5 -4  2  0  1  0  0  0  0]
        [-4  3 -1  1  0  0  1  0  0  0]
        [-2 -3 -4 -1  0  0  0  1  0  0]
        [-5 -5  3  3  0  0  0  0  1  0]
        [-4 -3  2 -5  0  0  0  0  0  1]

    Random basis::

        sage: sage.crypto.gen_lattice(type='random', n=1, m=10, q=11^4, seed=42)
        [14641     0     0     0     0     0     0     0     0     0]
        [  431     1     0     0     0     0     0     0     0     0]
        [-4792     0     1     0     0     0     0     0     0     0]
        [ 1015     0     0     1     0     0     0     0     0     0]
        [-3086     0     0     0     1     0     0     0     0     0]
        [-5378     0     0     0     0     1     0     0     0     0]
        [ 4769     0     0     0     0     0     1     0     0     0]
        [-1159     0     0     0     0     0     0     1     0     0]
        [ 3082     0     0     0     0     0     0     0     1     0]
        [-4580     0     0     0     0     0     0     0     0     1]

    Ideal bases with quotient x^n-1, m=2*n are NTRU bases::

        sage: sage.crypto.gen_lattice(type='ideal', seed=42, quotient=x^4-1)
        [11  0  0  0  0  0  0  0]
        [ 0 11  0  0  0  0  0  0]
        [ 0  0 11  0  0  0  0  0]
        [ 0  0  0 11  0  0  0  0]
        [-2 -3 -3  4  1  0  0  0]
        [ 4 -2 -3 -3  0  1  0  0]
        [-3  4 -2 -3  0  0  1  0]
        [-3 -3  4 -2  0  0  0  1]

    Ideal bases also work with polynomials::

        sage: R.<t> = PolynomialRing(ZZ)
        sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=t^4-1)
        [11  0  0  0  0  0  0  0]
        [ 0 11  0  0  0  0  0  0]
        [ 0  0 11  0  0  0  0  0]
        [ 0  0  0 11  0  0  0  0]
        [ 1  4 -3  3  1  0  0  0]
        [ 3  1  4 -3  0  1  0  0]
        [-3  3  1  4  0  0  1  0]
        [ 4 -3  3  1  0  0  0  1]

    Cyclotomic bases with n=2^k are SWIFFT bases::

        sage: sage.crypto.gen_lattice(type='cyclotomic', seed=42)
        [11  0  0  0  0  0  0  0]
        [ 0 11  0  0  0  0  0  0]
        [ 0  0 11  0  0  0  0  0]
        [ 0  0  0 11  0  0  0  0]
        [-2 -3 -3  4  1  0  0  0]
        [-4 -2 -3 -3  0  1  0  0]
        [ 3 -4 -2 -3  0  0  1  0]
        [ 3  3 -4 -2  0  0  0  1]

    Dual modular bases are related to Regev's famous public-key
    encryption [Reg2005]_::

        sage: sage.crypto.gen_lattice(type='modular', m=10, seed=42, dual=True)
        [ 0  0  0  0  0  0  0  0  0 11]
        [ 0  0  0  0  0  0  0  0 11  0]
        [ 0  0  0  0  0  0  0 11  0  0]
        [ 0  0  0  0  0  0 11  0  0  0]
        [ 0  0  0  0  0 11  0  0  0  0]
        [ 0  0  0  0 11  0  0  0  0  0]
        [ 0  0  0  1 -5 -2 -1  1 -3  5]
        [ 0  0  1  0 -3  4  1  4 -3 -2]
        [ 0  1  0  0 -4  5 -3  3  5  3]
        [ 1  0  0  0 -2 -1  4  2  5  4]

    Relation of primal and dual bases::

        sage: B_primal=sage.crypto.gen_lattice(m=10, q=11, seed=42)
        sage: B_dual=sage.crypto.gen_lattice(m=10, q=11, seed=42, dual=True)
        sage: B_dual_alt=transpose(11*B_primal.inverse()).change_ring(ZZ)
        sage: B_dual_alt.hermite_form() == B_dual.hermite_form()
        True

    TESTS:

    Test some bad quotient polynomials::

        sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=cos(x))
        Traceback (most recent call last):
        ...
        TypeError: unable to convert cos(x) to an integer
        sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=x^23-1)
        Traceback (most recent call last):
        ...
        ValueError: ideal basis requires n = quotient.degree()
        sage: R.<u,v> = ZZ[]
        sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=u+v)
        Traceback (most recent call last):
        ...
        TypeError: quotient should be a univariate polynomial

    We are testing output format choices::

        sage: sage.crypto.gen_lattice(m=10, q=11, seed=42)
        [11  0  0  0  0  0  0  0  0  0]
        [ 0 11  0  0  0  0  0  0  0  0]
        [ 0  0 11  0  0  0  0  0  0  0]
        [ 0  0  0 11  0  0  0  0  0  0]
        [ 2  4  3  5  1  0  0  0  0  0]
        [ 1 -5 -4  2  0  1  0  0  0  0]
        [-4  3 -1  1  0  0  1  0  0  0]
        [-2 -3 -4 -1  0  0  0  1  0  0]
        [-5 -5  3  3  0  0  0  0  1  0]
        [-4 -3  2 -5  0  0  0  0  0  1]

        sage: sage.crypto.gen_lattice(m=10, q=11, seed=42, ntl=True)
        [
        [11 0 0 0 0 0 0 0 0 0]
        [0 11 0 0 0 0 0 0 0 0]
        [0 0 11 0 0 0 0 0 0 0]
        [0 0 0 11 0 0 0 0 0 0]
        [2 4 3 5 1 0 0 0 0 0]
        [1 -5 -4 2 0 1 0 0 0 0]
        [-4 3 -1 1 0 0 1 0 0 0]
        [-2 -3 -4 -1 0 0 0 1 0 0]
        [-5 -5 3 3 0 0 0 0 1 0]
        [-4 -3 2 -5 0 0 0 0 0 1]
        ]

        sage: sage.crypto.gen_lattice(m=10, q=11, seed=42, lattice=True)
        Free module of degree 10 and rank 10 over Integer Ring
        User basis matrix:
        [ 0  0  1  1  0 -1 -1 -1  1  0]
        [-1  1  0  1  0  1  1  0  1  1]
        [-1  0  0  0 -1  1  1 -2  0  0]
        [-1 -1  0  1  1  0  0  1  1 -1]
        [ 1  0 -1  0  0  0 -2 -2  0  0]
        [ 2 -1  0  0  1  0  1  0  0 -1]
        [-1  1 -1  0  1 -1  1  0 -1 -2]
        [ 0  0 -1  3  0  0  0 -1 -1 -1]
        [ 0 -1  0 -1  2  0 -1  0  0  2]
        [ 0  1  1  0  1  1 -2  1 -1 -2]
    """
    from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
    from sage.matrix.constructor import identity_matrix, block_matrix
    from sage.matrix.matrix_space import MatrixSpace
    from sage.rings.integer_ring import IntegerRing
    if seed is not None:
        from sage.misc.randstate import set_random_seed
        set_random_seed(seed)

    if type == 'random':
        if n != 1: raise ValueError('random bases require n = 1')

    ZZ = IntegerRing()
    ZZ_q = IntegerModRing(q)
    A = identity_matrix(ZZ_q, n)

    if type == 'random' or type == 'modular':
        R = MatrixSpace(ZZ_q, m-n, n)
        A = A.stack(R.random_element())

    elif type == 'ideal':
        if quotient is None:
            raise ValueError('ideal bases require a quotient polynomial')
        try:
            quotient = quotient.change_ring(ZZ_q)
        except (AttributeError, TypeError):
            quotient = quotient.polynomial(base_ring=ZZ_q)

        P = quotient.parent()
        # P should be a univariate polynomial ring over ZZ_q
        if not is_PolynomialRing(P):
            raise TypeError("quotient should be a univariate polynomial")
        assert P.base_ring() is ZZ_q

        if quotient.degree() != n:
            raise ValueError('ideal basis requires n = quotient.degree()')
        R = P.quotient(quotient)
        for i in range(m//n):
            A = A.stack(R.random_element().matrix())

    elif type == 'cyclotomic':
        from sage.arith.all import euler_phi
        from sage.misc.functional import cyclotomic_polynomial

        # we assume that n+1 <= min( euler_phi^{-1}(n) ) <= 2*n
        found = False
        for k in range(2*n,n,-1):
            if euler_phi(k) == n:
                found = True
                break
        if not found:
            raise ValueError("cyclotomic bases require that n "
                       "is an image of Euler's totient function")

        R = ZZ_q['x'].quotient(cyclotomic_polynomial(k, 'x'), 'x')
        for i in range(m//n):
            A = A.stack(R.random_element().matrix())

    # switch from representatives 0,...,(q-1) to (1-q)/2,....,(q-1)/2
    def minrep(a):
        if abs(a-q) < abs(a): return a-q
        else: return a
    A_prime = A[n:m].lift().apply_map(minrep)

    if not dual:
        B = block_matrix([[ZZ(q), ZZ.zero()], [A_prime, ZZ.one()] ],
                         subdivide=False)
    else:
        B = block_matrix([[ZZ.one(), -A_prime.transpose()],
            [ZZ.zero(), ZZ(q)]], subdivide=False)
        for i in range(m//2):
            B.swap_rows(i,m-i-1)

    if ntl and lattice:
        raise ValueError("Cannot specify ntl=True and lattice=True "
                         "at the same time")

    if ntl:
        return B._ntl_()
    elif lattice:
        from sage.modules.free_module_integer import IntegerLattice
        return IntegerLattice(B)
    else:
        return B
Example #12
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 #13
0
def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, \
                quotient=None, dual=False, ntl=False):
    """
    This function generates different types of integral lattice bases
    of row vectors relevant in cryptography.

    Randomness can be set either with ``seed``, or by using
    :func:`sage.misc.randstate.set_random_seed`.

    INPUT:

    * ``type`` - one of the following strings
        * ``'modular'`` (default). A class of lattices for which
          asymptotic worst-case to average-case connections hold. For
          more refer to [A96]_.
        * ``'random'`` - Special case of modular (n=1). A dense class
          of lattice used for testing basis reduction algorithms
          proposed by Goldstein and Mayer [GM02]_.
        * ``'ideal'`` - Special case of modular. Allows for a more
          compact representation proposed by [LM06]_.
        * ``'cyclotomic'`` - Special case of ideal. Allows for
          efficient processing proposed by [LM06]_.
    * ``n`` - Determinant size, primal:`det(L) = q^n`, dual:`det(L) = q^{m-n}`.
      For ideal lattices this is also the degree of the quotient polynomial.
    * ``m`` - Lattice dimension, `L \subseteq Z^m`.
    * ``q`` - Coefficent size, `q*Z^m \subseteq L`.
    * ``seed`` - Randomness seed.
    * ``quotient`` - For the type ideal, this determines the quotient
      polynomial. Ignored for all other types.
    * ``dual`` - Set this flag if you want a basis for `q*dual(L)`, for example
      for Regev's LWE bases [R05]_.
    * ``ntl`` - Set this flag if you want the lattice basis in NTL readable
      format.

    OUTPUT: ``B`` a unique size-reduced triangular (primal: lower_left, 
      dual: lower_right) basis of row vectors for the lattice in question.

    EXAMPLES:

    * Modular basis ::

        sage: sage.crypto.gen_lattice(m=10, seed=42)
        [11  0  0  0  0  0  0  0  0  0]
        [ 0 11  0  0  0  0  0  0  0  0]
        [ 0  0 11  0  0  0  0  0  0  0]
        [ 0  0  0 11  0  0  0  0  0  0]
        [ 2  4  3  5  1  0  0  0  0  0]
        [ 1 -5 -4  2  0  1  0  0  0  0]
        [-4  3 -1  1  0  0  1  0  0  0]
        [-2 -3 -4 -1  0  0  0  1  0  0]
        [-5 -5  3  3  0  0  0  0  1  0]
        [-4 -3  2 -5  0  0  0  0  0  1]

    * Random basis ::

        sage: sage.crypto.gen_lattice(type='random', n=1, m=10, q=11^4, seed=42)
        [14641     0     0     0     0     0     0     0     0     0]
        [  431     1     0     0     0     0     0     0     0     0]
        [-4792     0     1     0     0     0     0     0     0     0]
        [ 1015     0     0     1     0     0     0     0     0     0]
        [-3086     0     0     0     1     0     0     0     0     0]
        [-5378     0     0     0     0     1     0     0     0     0]
        [ 4769     0     0     0     0     0     1     0     0     0]
        [-1159     0     0     0     0     0     0     1     0     0]
        [ 3082     0     0     0     0     0     0     0     1     0]
        [-4580     0     0     0     0     0     0     0     0     1]

    * Ideal bases with quotient x^n-1, m=2*n are NTRU bases ::

        sage: sage.crypto.gen_lattice(type='ideal', seed=42, quotient=x^4-1)
        [11  0  0  0  0  0  0  0]
        [ 0 11  0  0  0  0  0  0]
        [ 0  0 11  0  0  0  0  0]
        [ 0  0  0 11  0  0  0  0]
        [ 4 -2 -3 -3  1  0  0  0]
        [-3  4 -2 -3  0  1  0  0]
        [-3 -3  4 -2  0  0  1  0]
        [-2 -3 -3  4  0  0  0  1]

    * Cyclotomic bases with n=2^k are SWIFFT bases ::

        sage: sage.crypto.gen_lattice(type='cyclotomic', seed=42)
        [11  0  0  0  0  0  0  0]
        [ 0 11  0  0  0  0  0  0]
        [ 0  0 11  0  0  0  0  0]
        [ 0  0  0 11  0  0  0  0]
        [ 4 -2 -3 -3  1  0  0  0]
        [ 3  4 -2 -3  0  1  0  0]
        [ 3  3  4 -2  0  0  1  0]
        [ 2  3  3  4  0  0  0  1]

    * Dual modular bases are related to Regev's famous public-key
      encryption [R05]_ ::

        sage: sage.crypto.gen_lattice(type='modular', m=10, seed=42, dual=True)
        [ 0  0  0  0  0  0  0  0  0 11]
        [ 0  0  0  0  0  0  0  0 11  0]
        [ 0  0  0  0  0  0  0 11  0  0]
        [ 0  0  0  0  0  0 11  0  0  0]
        [ 0  0  0  0  0 11  0  0  0  0]
        [ 0  0  0  0 11  0  0  0  0  0]
        [ 0  0  0  1 -5 -2 -1  1 -3  5]
        [ 0  0  1  0 -3  4  1  4 -3 -2]
        [ 0  1  0  0 -4  5 -3  3  5  3]
        [ 1  0  0  0 -2 -1  4  2  5  4]

    * Relation of primal and dual bases ::

        sage: B_primal=sage.crypto.gen_lattice(m=10, q=11, seed=42)
        sage: B_dual=sage.crypto.gen_lattice(m=10, q=11, seed=42, dual=True)
        sage: B_dual_alt=transpose(11*B_primal.inverse()).change_ring(ZZ)
        sage: B_dual_alt.hermite_form() == B_dual.hermite_form()
        True

    REFERENCES:

.. [A96] Miklos Ajtai.
   Generating hard instances of lattice problems (extended abstract).
   STOC, pp. 99--108, ACM, 1996.

.. [GM02] Daniel Goldstein and Andrew Mayer.
   On the equidistribution of Hecke points.
   Forum Mathematicum, 15:2, pp. 165--189, De Gruyter, 2003.

.. [LM06] Vadim Lyubashevsky and Daniele Micciancio.
   Generalized compact knapsacks are collision resistant.
   ICALP, pp. 144--155, Springer, 2006.

.. [R05] Oded Regev.
   On lattices, learning with errors, random linear codes, and cryptography.
   STOC, pp. 84--93, ACM, 2005.
    """
    from sage.rings.finite_rings.integer_mod_ring \
        import IntegerModRing
    from sage.matrix.constructor import matrix, \
        identity_matrix, block_matrix
    from sage.matrix.matrix_space import MatrixSpace
    from sage.rings.integer_ring import IntegerRing
    if seed != None:
        from sage.misc.randstate import set_random_seed
        set_random_seed(seed)

    if type == 'random':
        if n != 1: raise ValueError('random bases require n = 1')

    ZZ = IntegerRing()
    ZZ_q = IntegerModRing(q)
    A = identity_matrix(ZZ_q, n)

    if type == 'random' or type == 'modular':
        R = MatrixSpace(ZZ_q, m-n, n)
        A = A.stack(R.random_element())

    elif type == 'ideal':
        if quotient == None: raise \
            ValueError('ideal bases require a quotient polynomial')
        x = quotient.default_variable()
        if n != quotient.degree(x): raise \
            ValueError('ideal bases require n  = quotient.degree()')
        R = ZZ_q[x].quotient(quotient, x)
        for i in range(m//n):
            A = A.stack(R.random_element().matrix())

    elif type == 'cyclotomic':
        from sage.rings.arith import euler_phi
        from sage.misc.functional import cyclotomic_polynomial

        # we assume that n+1 <= min( euler_phi^{-1}(n) ) <= 2*n
        found = False
        for k in range(2*n,n,-1):
            if euler_phi(k) == n:
                found = True
                break
        if not found: raise \
            ValueError('cyclotomic bases require that n is an image of' + \
                       'Euler\'s totient function')

        R = ZZ_q['x'].quotient(cyclotomic_polynomial(k, 'x'), 'x')
        for i in range(m//n):
            A = A.stack(R.random_element().matrix())

    # switch from representatives 0,...,(q-1) to (1-q)/2,....,(q-1)/2
    def minrep(a):
        if abs(a-q) < abs(a): return a-q
        else: return a
    A_prime = A[n:m].lift().apply_map(minrep)

    if not dual:
        B = block_matrix([[ZZ(q), ZZ.zero()], [A_prime, ZZ.one()] ], \
                         subdivide=False)
    else:
        B = block_matrix([[ZZ.one(), -A_prime.transpose()], [ZZ.zero(), \
                         ZZ(q)]], subdivide=False)
        for i in range(m//2): B.swap_rows(i,m-i-1)

    if not ntl:
        return B
    else:
        return B._ntl_()
Example #14
0
    def basis(self, reduce=True):
        r"""
        Produce a basis for the free abelian group of eta-products of level
        N (under multiplication), attempting to find basis vectors of the
        smallest possible degree.

        INPUT:


        -  ``reduce`` - a boolean (default True) indicating
           whether or not to apply LLL-reduction to the calculated basis


        EXAMPLES::

            sage: EtaGroup(5).basis()
            [Eta product of level 5 : (eta_1)^6 (eta_5)^-6]
            sage: EtaGroup(12).basis()
            [Eta product of level 12 : (eta_1)^2 (eta_2)^1 (eta_3)^2 (eta_4)^-1 (eta_6)^-7 (eta_12)^3,
            Eta product of level 12 : (eta_1)^-4 (eta_2)^2 (eta_3)^4 (eta_6)^-2,
            Eta product of level 12 : (eta_1)^-1 (eta_2)^3 (eta_3)^3 (eta_4)^-2 (eta_6)^-9 (eta_12)^6,
            Eta product of level 12 : (eta_1)^1 (eta_2)^-1 (eta_3)^-3 (eta_4)^-2 (eta_6)^7 (eta_12)^-2,
            Eta product of level 12 : (eta_1)^-6 (eta_2)^9 (eta_3)^2 (eta_4)^-3 (eta_6)^-3 (eta_12)^1]
            sage: EtaGroup(12).basis(reduce=False) # much bigger coefficients
            [Eta product of level 12 : (eta_2)^24 (eta_12)^-24,
            Eta product of level 12 : (eta_1)^-336 (eta_2)^576 (eta_3)^696 (eta_4)^-216 (eta_6)^-576 (eta_12)^-144,
            Eta product of level 12 : (eta_1)^-8 (eta_2)^-2 (eta_6)^2 (eta_12)^8,
            Eta product of level 12 : (eta_1)^1 (eta_2)^9 (eta_3)^13 (eta_4)^-4 (eta_6)^-15 (eta_12)^-4,
            Eta product of level 12 : (eta_1)^15 (eta_2)^-24 (eta_3)^-29 (eta_4)^9 (eta_6)^24 (eta_12)^5]

        ALGORITHM: An eta product of level `N` is uniquely
        determined by the integers `r_d` for `d | N` with
        `d < N`, since `\sum_{d | N} r_d = 0`. The valid
        `r_d` are those that satisfy two congruences modulo 24,
        and one congruence modulo 2 for every prime divisor of N. We beef
        up the congruences modulo 2 to congruences modulo 24 by multiplying
        by 12. To calculate the kernel of the ensuing map
        `\ZZ^m \to (\ZZ/24\ZZ)^n`
        we lift it arbitrarily to an integer matrix and calculate its Smith
        normal form. This gives a basis for the lattice.

        This lattice typically contains "large" elements, so by default we
        pass it to the reduce_basis() function which performs
        LLL-reduction to give a more manageable basis.
        """
        from six.moves import range
        N = self.level()
        divs = divisors(N)[:-1]
        s = len(divs)
        primedivs = prime_divisors(N)

        rows = []
        for i in range(s):
            # generate a row of relation matrix
            row = [
                Mod(divs[i], 24) - Mod(N, 24),
                Mod(N / divs[i], 24) - Mod(1, 24)
            ]
            for p in primedivs:
                row.append(Mod(12 * (N / divs[i]).valuation(p), 24))
            rows.append(row)
        M = matrix(IntegerModRing(24), rows)
        Mlift = M.change_ring(ZZ)
        # now we compute elementary factors of Mlift
        S, U, V = Mlift.smith_form()
        good_vects = []
        for i in range(U.nrows()):
            vect = U.row(i)
            nf = (i < S.ncols() and S[i, i]) or 0
            good_vects.append((vect * 24 / gcd(nf, 24)).list())
        for v in good_vects:
            v.append(-sum([r for r in v]))
        dicts = []
        for v in good_vects:
            dicts.append({})
            for i in range(s):
                dicts[-1][divs[i]] = v[i]
            dicts[-1][N] = v[-1]
        if reduce:
            return self.reduce_basis([self(d) for d in dicts])
        else:
            return [self(d) for d in dicts]
Example #15
0
 
    """
    from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
    from sage.matrix.constructor import identity_matrix, block_matrix
    from sage.matrix.matrix_space import MatrixSpace
    from sage.rings.integer_ring import IntegerRing
    from sage.modules.free_module_integer import IntegerLattice
       
    if seed is not None:
        from sage.misc.randstate import set_random_seed
        set_random_seed(seed)
 
 
    m=n+1
    ZZ = IntegerRing()
    ZZ_q = IntegerModRing(q)
 
 
 
    from sage.arith.all import euler_phi
    from sage.misc.functional import cyclotomic_polynomial
 
    # we assume that n+1 <= min( euler_phi^{-1}(n) ) <= 2*n
    found = False
    for k in range(2*n,n,-1):
        if euler_phi(k) == n:
            found = True
            break
        if not found:
            raise ValueError("cyclotomic bases require that n "
                                 "is an image of Euler's totient function")
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)
Example #17
0
    def padic_H_value(self, p, f, t, prec=None):
        """
        Return the `p`-adic trace of Frobenius, computed using the
        Gross-Koblitz formula.

        INPUT:

        - `p` -- a prime number

        - `f` -- an integer such that `q = p^f`

        - `t` -- a rational parameter

        - ``prec`` -- precision (optional, default 20)

        OUTPUT:

        an integer

        EXAMPLES:

        From Benasque report [Benasque2009]_, page 8::

            sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp
            sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4))
            sage: [H.padic_H_value(3,i,-1) for i in range(1,3)]
            [0, -12]
            sage: [H.padic_H_value(5,i,-1) for i in range(1,3)]
            [-4, 276]
            sage: [H.padic_H_value(7,i,-1) for i in range(1,3)]
            [0, -476]
            sage: [H.padic_H_value(11,i,-1) for i in range(1,3)]
            [0, -4972]

        From [Roberts2015]_ (but note conventions regarding `t`)::

            sage: H = Hyp(gamma_list=[-6,-1,4,3])
            sage: t = 189/125
            sage: H.padic_H_value(13,1,1/t)
            0

        REFERENCES:

        - [MagmaHGM]_
        """
        alpha = self._alpha
        beta = self._beta
        if 0 in alpha:
            H = self.swap_alpha_beta()
            return H.padic_H_value(p, f, ~t, prec)
        t = QQ(t)
        gamma = self.gamma_array()
        q = p ** f

#        m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)}
        m = defaultdict(lambda: 0)
        for r in range(q-1):
            u = QQ((r, q-1))
            if u in beta:
                m[r] = beta.count(u)
        M = self.M_value()
        D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta)
        # also: D = (self.weight() + 1 - m[0]) // 2

        if prec is None:
            prec = (self.weight()*f)//2 + ceil(log(self.degree(),p)) + 1
        # For some reason, working in Qp instead of Zp is much faster;
        # it appears to avoid some costly conversions.
        p_ring = Qp(p, prec=prec)
        teich = p_ring.teichmuller(M / t)

        gauss_table = [padic_gauss_sum(r, p, f, prec, factored=True, algorithm='sage', parent=p_ring)
                       for r in range(q-1)]

        sigma = sum( ((-p)**(sum(gauss_table[(v * r) % (q - 1)][0] * gv
                                for v, gv in gamma.items()) // (p - 1)) *
                     prod(gauss_table[(v * r) % (q - 1)][1] ** gv
                          for v, gv in gamma.items()) * teich ** r)
                     << (f*(D+m[0]-m[r])) for r in range(q-1))
        resu = ZZ(-1) ** m[0] / (1 - q) * sigma
        return IntegerModRing(p**prec)(resu).lift_centered()
Example #18
0
    sage: verifier.interact_once(prover)
    True
Repeat the testing protocol 100 times (if the prover is not genuine, it would a
chance of less than 10^(-12) of getting away):
    sage: verifier.interact(prover, 100)
    True
"""

import hashlib
import random
from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
from sage.modules.free_module import VectorSpace
from sage.quadratic_forms.quadratic_form import QuadraticForm
from sage.structure.sage_object import dumps

ZZ2 = IntegerModRing(2)


def hash_sage_object(x):
    return hashlib.sha512(dumps(x)).digest()


class Instance(object):
    def __init__(self, n, quad_forms, results):
        self.quad_forms = quad_forms
        self.domain_space = VectorSpace(ZZ2, n)
        self.range_space = VectorSpace(ZZ2, len(results))
        self.results = self.range_space(results)

    def __call__(self, vector):
        result = []
Example #19
0
def _is_a_splitting(S1, S2, n, return_automorphism=False):
    r"""
    Check wether ``(S1,S2)`` is a splitting of `\ZZ/n\ZZ`.

    A splitting of `R = \ZZ/n\ZZ` is a pair of subsets of `R` which is a
    partition of `R \\backslash \{0\}` and such that there exists an element `r`
    of `R` such that `r S_1 = S_2` and `r S_2 = S_1` (where `r S` is the
    point-wise multiplication of the elements of `S` by `r`).

    Splittings are useful for computing idempotents in the quotient
    ring `Q = GF(q)[x]/(x^n-1)`.

    INPUT:

    - ``S1, S2`` -- disjoint sublists partitioning ``[1, 2, ..., n-1]``

    - ``n`` (integer)

    - ``return_automorphism`` (boolean) -- whether to return the automorphism
      exchanging `S_1` and `S_2`.

    OUTPUT:

    If ``return_automorphism is False`` (default) the function returns boolean values.

    Otherwise, it returns a pair ``(b, r)`` where ``b`` is a boolean indicating
    whether `S1`, `S2` is a splitting of `n`, and `r` is such that `r S_1 = S_2`
    and `r S_2 = S_1` (if `b` is ``False``, `r` is equal to ``None``).

    EXAMPLES::

        sage: from sage.coding.code_constructions import _is_a_splitting
        sage: _is_a_splitting([1,2],[3,4],5)
        True
        sage: _is_a_splitting([1,2],[3,4],5,return_automorphism=True)
        (True, 4)

        sage: _is_a_splitting([1,3],[2,4,5,6],7)
        False
        sage: _is_a_splitting([1,3,4],[2,5,6],7)
        False

        sage: for P in SetPartitions(6,[3,3]):
        ....:     res,aut= _is_a_splitting(P[0],P[1],7,return_automorphism=True)
        ....:     if res:
        ....:         print((aut, P))
        (3, {{1, 2, 4}, {3, 5, 6}})
        (6, {{1, 2, 3}, {4, 5, 6}})
        (6, {{1, 3, 5}, {2, 4, 6}})
        (6, {{1, 4, 5}, {2, 3, 6}})

    We illustrate now how to find idempotents in quotient rings::

        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: F = GF(q)
        sage: P.<x> = PolynomialRing(F,"x")
        sage: I = Ideal(P,[x^n-1])
        sage: Q.<x> = QuotientRing(P,I)
        sage: i1 = -sum([x^i for i in S1]); i1
        2*x^9 + 2*x^5 + 2*x^4 + 2*x^3 + 2*x
        sage: i2 = -sum([x^i for i in S2]); i2
        2*x^10 + 2*x^8 + 2*x^7 + 2*x^6 + 2*x^2
        sage: i1^2 == i1
        True
        sage: i2^2 == i2
        True
        sage: (1-i1)^2 == 1-i1
        True
        sage: (1-i2)^2 == 1-i2
        True

    We return to dealing with polynomials (rather than elements of
    quotient rings), so we can construct cyclic codes::

        sage: P.<x> = PolynomialRing(F,"x")
        sage: i1 = -sum([x^i for i in S1])
        sage: i2 = -sum([x^i for i in S2])
        sage: i1_sqrd = (i1^2).quo_rem(x^n-1)[1]
        sage: i1_sqrd  == i1
        True
        sage: i2_sqrd = (i2^2).quo_rem(x^n-1)[1]
        sage: i2_sqrd  == i2
        True
        sage: C1 = codes.CyclicCode(length = n, generator_pol = gcd(i1, x^n - 1))
        sage: C2 = codes.CyclicCode(length = n, generator_pol = gcd(1-i2, x^n - 1))
        sage: C1.dual_code().systematic_generator_matrix() == C2.systematic_generator_matrix()
        True

    This is a special case of Theorem 6.4.3 in [HP2003]_.
    """
    R = IntegerModRing(n)
    S1 = set(R(x) for x in S1)
    S2 = set(R(x) for x in S2)

    # we first check whether (S1,S2) is a partition of R - {0}
    if (len(S1) + len(S2) != n - 1 or len(S1) != len(S2) or R.zero() in S1
            or R.zero() in S2 or not S1.isdisjoint(S2)):
        if return_automorphism:
            return False, None
        else:
            return False

    # now that we know that (S1,S2) is a partition, we look for an invertible
    # element b that maps S1 to S2 by multiplication
    for b in Integer(n).coprime_integers(n):
        if b >= 2 and all(b * x in S2 for x in S1):
            if return_automorphism:
                return True, b
            else:
                return True
    if return_automorphism:
        return False, None
    else:
        return False
Example #20
0
################################################################################

from sage.misc.cachefunc import cached_method

from sage.misc.misc import prod
from congroup_generic import is_CongruenceSubgroup
from congroup_gammaH import GammaH_class, is_GammaH, GammaH_constructor
#from congroup_gamma0 import Gamma0_constructor -- circular!
from arithgroup_element import ArithmeticSubgroupElement
from sage.rings.all import ZZ, euler_phi as phi, moebius, divisors
from sage.modular.dirichlet import DirichletGroup

# Just for now until we make an SL_2 group type.
from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
from sage.matrix.matrix_space import MatrixSpace
Mat2Z = MatrixSpace(IntegerModRing(0), 2)


def is_Gamma1(x):
    """
    Return True if x is a congruence subgroup of type Gamma1.

    EXAMPLES::

        sage: from sage.modular.arithgroup.all import is_Gamma1
        sage: is_Gamma1(SL2Z)
        False
        sage: is_Gamma1(Gamma1(13))
        True
        sage: is_Gamma1(Gamma0(6))
        False
Example #21
0
    def _init_frob(self, desired_prec=None):
        """
        Initialise everything for Frobenius polynomial computation.

        TESTS::

            sage: p = 4999
            sage: x = PolynomialRing(GF(p),"x").gen()
            sage: C = CyclicCover(3, x^4 + 4*x^3 + 9*x^2 + 3*x + 1)
            sage: C._init_frob()
            sage: C._init_frobQ
            True
            sage: C._plarge
            True
            sage: C._sqrtp
            True
        """
        def _N0_RH():
            return ceil(
                log(2 * binomial(2 * self._genus, self._genus), self._p) +
                self._genus * self._n / ZZ(2))

        def _find_N0():
            if self._nodenominators:
                return _N0_nodenominators(self._p, self._genus, self._n)
            else:
                return _N0_RH() + self._extraprec

        def _find_N_43():
            """
            Find the precision used for thm 4.3 in Goncalves
            for p >> 0, N = N0 + 2
            """
            p = self._p
            r = self._r
            d = self._d
            delta = self._delta
            N0 = self._N0
            left_side = N0 + floor(log((d * p * (r - 1) + r) / delta) / log(p))

            def right_side_log(n):
                return floor(log(p * (r * n - 1) - r) / log(p))

            n = left_side
            while n <= left_side + right_side_log(n):
                n += 1
            return n

        if not self._init_frobQ or self._N0 != desired_prec:
            if self._r < 2 or self._d < 2:
                raise NotImplementedError(
                    "Only implemented for r, f.degree() >= 2")

            self._init_frobQ = True

            self._Fq = self._f.base_ring()
            self._p = self._Fq.characteristic()
            self._q = self._Fq.cardinality()
            self._n = self._Fq.degree()
            self._epsilon = 0 if self._delta == 1 else 1

            # our basis choice doesn't always give an integral matrix
            if self._epsilon == 0:
                self._extraprec = floor(
                    log(self._r, self._p) +
                    log((2 * self._genus +
                         (self._delta - 2)) / self._delta, self._p))
            else:
                self._extraprec = floor(log(self._r * 2 - 1, self._p))

            self._nodenominators = self._extraprec == 0

            if desired_prec is None:
                self._N0 = _find_N0()
            else:
                self._N0 = desired_prec

            self._plarge = self._p > self._d * self._r * (self._N0 +
                                                          self._epsilon)

            # working prec
            if self._plarge:
                self._N = self._N0 + 1
            else:
                self._N = _find_N_43()

            # we will use the sqrt(p) version?
            self._sqrtp = self._plarge and self._p == self._q
            self._extraworkingprec = self._extraprec
            if not self._plarge:
                # we might have some denominators showing up during horizontal
                # and vertical reductions
                self._extraworkingprec += 2 * ceil(
                    log(self._d * self._r *
                        (self._N0 + self._epsilon), self._p))

            # Rings
            if self._plarge and self._nodenominators:
                if self._n == 1:
                    # IntegerModRing is significantly faster than Zq
                    self._Zq = IntegerModRing(self._p**self._N)
                    if self._sqrtp:
                        self._Zq0 = IntegerModRing(self._p**(self._N - 1))
                    self._Qq = Qq(self._p, prec=self._N, type="capped-rel")
                    self._w = 1
                else:
                    self._Zq = Zq(
                        self._q,
                        names="w",
                        modulus=self._Fq.polynomial(),
                        prec=self._N,
                        type="capped-abs",
                    )
                    self._w = self._Zq.gen()
                    self._Qq = self._Zq.fraction_field()
            else:
                self._Zq = Qq(
                    self._q,
                    names="w",
                    modulus=self._Fq.polynomial(),
                    prec=self._N + self._extraworkingprec,
                )
                self._w = self._Zq.gen()
                self._Qq = self._Zq
            self._Zp = Zp(self._p, prec=self._N + self._extraworkingprec)

            self._Zqx = PolynomialRing(self._Zq, "x")

            # Want to take a lift of f from Fq to Zq
            if self._n == 1:
                # When n = 1, can lift from Fp[x] to Z[x] and then to Zp[x]
                self._flift = self._Zqx([elt.lift() for elt in self._f.list()])
                self._frobf = self._Zqx(self._flift.list())
            else:  # When n > 1, need to be more careful with the lift
                self._flift = self._Zqx([
                    elt.polynomial().change_ring(ZZ)(self._Zq.gen())
                    for elt in self._f.list()
                ])

                self._frobf = self._Zqx(
                    [elt.frobenius() for elt in self._flift.list()])

            self._dflift = self._flift.derivative()

            # Set up local cache for Frob(f)^s

            # This variable will store the powers of frob(f)
            frobpow = [None] * (self._N0 + 2)
            frobpow[0] = self._Zqx(1)
            for k in range(self._N0 + 1):
                frobpow[k + 1] = self._frobf * frobpow[k]
            # We don't make it a polynomials as we need to keep track that the
            # ith coefficient represents  (i*p)-th
            self._frobpow_list = [elt.list() for elt in frobpow]

            if self._sqrtp:
                # precision of self._Zq0
                N = self._N - 1
                vandermonde = matrix(self._Zq0, N, N)
                for i in range(N):
                    vandermonde[i, 0] = 1
                    for j in range(1, N):
                        vandermonde[i, j] = vandermonde[i, j - 1] * (i + 1)
                self._vandermonde = vandermonde.inverse()

                self._horizontal_fat_s = {}
                self._vertical_fat_s = {}
Example #22
0
def discrete_log_rho(a, base, ord=None, operation='*', hash_function=hash):
    """
    Pollard Rho algorithm for computing discrete logarithm in cyclic
    group of prime order.
    If the group order is very small it falls back to the baby step giant step
    algorithm.

    INPUT:

    - ``a`` -- a group element
    - ``base`` -- a group element
    - ``ord`` -- the order of ``base`` or ``None``, in this case we try
      to compute it
    - ``operation`` -- a string (default: ``'*'``) denoting whether we
      are in an additive group or a multiplicative one
    - ``hash_function`` -- having an efficient hash function is critical
      for this algorithm (see examples)

    OUTPUT: an integer `n` such that `a = base^n` (or `a = n*base`)

    ALGORITHM: Pollard rho for discrete logarithm, adapted from the
    article of Edlyn Teske, 'A space efficient algorithm for group
    structure computation'.

    EXAMPLES::

        sage: F.<a> = GF(2^13)
        sage: g = F.gen()
        sage: discrete_log_rho(g^1234, g)
        1234

        sage: F.<a> = GF(37^5)
        sage: E = EllipticCurve(F, [1,1])
        sage: G = (3*31*2^4)*E.lift_x(a)
        sage: discrete_log_rho(12345*G, G, ord=46591, operation='+')
        12345

    It also works with matrices::

        sage: A = matrix(GF(50021),[[10577,23999,28893],[14601,41019,30188],[3081,736,27092]])
        sage: discrete_log_rho(A^1234567, A)
        1234567

    Beware, the order must be prime::

        sage: I = IntegerModRing(171980)
        sage: discrete_log_rho(I(2), I(3))
        Traceback (most recent call last):
        ...
        ValueError: for Pollard rho algorithm the order of the group must be prime

    If it fails to find a suitable logarithm, it raises a ``ValueError``::

        sage: I = IntegerModRing(171980)
        sage: discrete_log_rho(I(31002),I(15501))
        Traceback (most recent call last):
        ...
        ValueError: Pollard rho algorithm failed to find a logarithm

    The main limitation on the hash function is that we don't want to have
    `hash(x*y) = hash(x) + hash(y)`::

        sage: I = IntegerModRing(next_prime(2^23))
        sage: def test():
        ....:     try:
        ....:          discrete_log_rho(I(123456),I(1),operation='+')
        ....:     except Exception:
        ....:          print("FAILURE")
        sage: test()  # random failure
        FAILURE

    If this happens, we can provide a better hash function::

        sage: discrete_log_rho(I(123456),I(1),operation='+', hash_function=lambda x: hash(x*x))
        123456

    AUTHOR:

    - Yann Laigle-Chapuy (2009-09-05)

    """
    from sage.rings.integer import Integer
    from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
    from operator import mul, add, pow

    # should be reasonable choices
    partition_size = 20
    memory_size = 4

    if operation in addition_names:
        mult = add
        power = mul
        if ord is None:
            ord = base.additive_order()
    elif operation in multiplication_names:
        mult = mul
        power = pow
        if ord is None:
            ord = base.multiplicative_order()
    else:
        raise ValueError

    ord = Integer(ord)

    if not ord.is_prime():
        raise ValueError("for Pollard rho algorithm the order of the group must be prime")

    # check if we need to set immutable before hashing
    mut = hasattr(base,'set_immutable')

    isqrtord=ord.isqrt()

    if isqrtord < partition_size: #setup to costly, use bsgs
        return bsgs(base,a, bounds=(0,ord), operation=operation)

    reset_bound = 8*isqrtord # we take some margin

    I=IntegerModRing(ord)

    for s in xrange(10): # to avoid infinite loops
        # random walk function setup
        m=[I.random_element() for i in xrange(partition_size)]
        n=[I.random_element() for i in xrange(partition_size)]
        M=[mult(power(base,Integer(m[i])),power(a,Integer(n[i]))) for i in xrange(partition_size)]

        ax = I.random_element()
        x = power(base,Integer(ax))
        if mut:
            x.set_immutable()

        bx = I(0)

        sigma=[(0,None)]*memory_size
        H={} # memory
        i0=0
        nextsigma = 0
        for i in xrange(reset_bound):
                    #random walk, we need an efficient hash
            s=hash_function(x) % partition_size
            (x,ax,bx) = (mult(M[s],x), ax+m[s], bx+n[s])
            if mut:
                x.set_immutable()
            # look for collisions
            if x in H:
                ay,by=H[x]
                if bx == by:
                    break
                else:
                    res = sage.rings.integer.Integer((ay-ax)/(bx-by))
                    if power(base,res) == a:
                        return res
                    else:
                        break
            # should we remember this value?
            elif i >= nextsigma:
                if sigma[i0][1] is not None:
                    H.pop(sigma[i0][1])
                sigma[i0]=(i,x)
                i0 = (i0+1) % memory_size
                nextsigma = 3*sigma[i0][0] #3 seems a good choice
                H[x]=(ax,bx)

    raise ValueError("Pollard rho algorithm failed to find a logarithm")
Example #23
0
class ColoredPermutations(Parent, UniqueRepresentation):
    r"""
    The group of `m`-colored permutations on `\{1, 2, \ldots, n\}`.

    Let `S_n` be the symmetric group on `n` letters and `C_m` be the cyclic
    group of order `m`. The `m`-colored permutation group on `n` letters
    is given by `P_n^m = C_m \wr S_n`. This is also the complex reflection
    group `G(m, 1, n)`.

    We define our multiplication by

    .. MATH::

        ((s_1, \ldots s_n), \sigma) \cdot ((t_1, \ldots, t_n), \tau)
        = ((s_1 t_{\sigma(1)}, \ldots, s_n t_{\sigma(n)}), \tau \sigma).

    EXAMPLES::

        sage: C = ColoredPermutations(4, 3); C
        4-colored permutations of size 3
        sage: s1,s2,t = C.gens()
        sage: (s1, s2, t)
        ([[0, 0, 0], [2, 1, 3]], [[0, 0, 0], [1, 3, 2]], [[0, 0, 1], [1, 2, 3]])
        sage: s1*s2
        [[0, 0, 0], [3, 1, 2]]
        sage: s1*s2*s1 == s2*s1*s2
        True
        sage: t^4 == C.one()
        True
        sage: s2*t*s2
        [[0, 1, 0], [1, 2, 3]]

    We can also create a colored permutation by passing
    either a list of tuples consisting of ``(color, element)``::

        sage: x = C([(2,1), (3,3), (3,2)]); x
        [[2, 3, 3], [1, 3, 2]]

    or a list of colors and a permutation::

        sage: C([[3,3,1], [1,3,2]])
        [[3, 3, 1], [1, 3, 2]]

    There is also the natural lift from permutations::

        sage: P = Permutations(3)
        sage: C(P.an_element())
        [[0, 0, 0], [3, 1, 2]]

    REFERENCES:

    - :wikipedia:`Generalized_symmetric_group`
    - :wikipedia:`Complex_reflection_group`
    """
    def __init__(self, m, n):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: TestSuite(C).run()
            sage: C = ColoredPermutations(2, 3)
            sage: TestSuite(C).run()
            sage: C = ColoredPermutations(1, 3)
            sage: TestSuite(C).run()
        """
        if m <= 0:
            raise ValueError("m must be a positive integer")
        self._m = ZZ(m)
        self._n = ZZ(n)
        self._C = IntegerModRing(self._m)
        self._P = Permutations(self._n)

        if self._m == 1 or self._m == 2:
            from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups
            category = FiniteCoxeterGroups().Irreducible()
        else:
            from sage.categories.complex_reflection_groups import ComplexReflectionGroups
            category = ComplexReflectionGroups().Finite().Irreducible(
            ).WellGenerated()
        Parent.__init__(self, category=category)

    def _repr_(self):
        """
        Return a string representation of ``self``.

        EXAMPLES::

            sage: ColoredPermutations(4, 3)
            4-colored permutations of size 3
        """
        return "{}-colored permutations of size {}".format(self._m, self._n)

    @cached_method
    def index_set(self):
        """
        Return the index set of ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(3, 4)
            sage: C.index_set()
            (1, 2, 3, 4)

            sage: C = ColoredPermutations(1, 4)
            sage: C.index_set()
            (1, 2, 3)

        TESTS::

            sage: S = SignedPermutations(4)
            sage: S.index_set()
            (1, 2, 3, 4)
        """
        n = self._n
        if self._m != 1:
            n += 1
        return tuple(range(1, n))

    def coxeter_matrix(self):
        """
        Return the Coxeter matrix of ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(3, 4)
            sage: C.coxeter_matrix()
            [1 3 2 2]
            [3 1 3 2]
            [2 3 1 4]
            [2 2 4 1]

            sage: C = ColoredPermutations(1, 4)
            sage: C.coxeter_matrix()
            [1 3 2]
            [3 1 3]
            [2 3 1]

        TESTS::

            sage: S = SignedPermutations(4)
            sage: S.coxeter_matrix()
            [1 3 2 2]
            [3 1 3 2]
            [2 3 1 4]
            [2 2 4 1]
        """
        from sage.combinat.root_system.cartan_type import CartanType
        if self._m == 1:
            return CartanType(['A', self._n - 1]).coxeter_matrix()
        return CartanType(['B', self._n]).coxeter_matrix()

    @cached_method
    def one(self):
        """
        Return the identity element of ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.one()
            [[0, 0, 0], [1, 2, 3]]
        """
        return self.element_class(self, [self._C.zero()] * self._n,
                                  self._P.identity())

    def simple_reflection(self, i):
        r"""
        Return the ``i``-th simple reflection of ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.gens()
            ([[0, 0, 0], [2, 1, 3]], [[0, 0, 0], [1, 3, 2]], [[0, 0, 1], [1, 2, 3]])
            sage: C.simple_reflection(2)
            [[0, 0, 0], [1, 3, 2]]
            sage: C.simple_reflection(3)
            [[0, 0, 1], [1, 2, 3]]

            sage: S = SignedPermutations(4)
            sage: S.simple_reflection(1)
            [2, 1, 3, 4]
            sage: S.simple_reflection(4)
            [1, 2, 3, -4]
        """
        if i not in self.index_set():
            raise ValueError("i must be in the index set")
        colors = [self._C.zero()] * self._n
        if i < self._n:
            p = list(range(1, self._n + 1))
            p[i - 1] = i + 1
            p[i] = i
            return self.element_class(self, colors, self._P(p))
        colors[-1] = self._C.one()
        return self.element_class(self, colors, self._P.identity())

    @cached_method
    def _inverse_simple_reflections(self):
        """
        Return the inverse of the simple reflections of ``self``.

        .. WARNING::

            This returns a ``dict`` that should not be mutated since
            the result is cached.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C._inverse_simple_reflections()
            {1: [[0, 0, 0], [2, 1, 3]],
             2: [[0, 0, 0], [1, 3, 2]],
             3: [[0, 0, 3], [1, 2, 3]]}
        """
        s = self.simple_reflections()
        return {i: ~s[i] for i in self.index_set()}

    @cached_method
    def gens(self):
        """
        Return the generators of ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.gens()
            ([[0, 0, 0], [2, 1, 3]],
             [[0, 0, 0], [1, 3, 2]],
             [[0, 0, 1], [1, 2, 3]])

            sage: S = SignedPermutations(4)
            sage: S.gens()
            ([2, 1, 3, 4], [1, 3, 2, 4], [1, 2, 4, 3], [1, 2, 3, -4])
        """
        return tuple(self.simple_reflection(i) for i in self.index_set())

    def matrix_group(self):
        """
        Return the matrix group corresponding to ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.matrix_group()
            Matrix group over Cyclotomic Field of order 4 and degree 2 with 3 generators (
            [0 1 0]  [1 0 0]  [    1     0     0]
            [1 0 0]  [0 0 1]  [    0     1     0]
            [0 0 1], [0 1 0], [    0     0 zeta4]
            )
        """
        from sage.groups.matrix_gps.finitely_generated import MatrixGroup
        return MatrixGroup([g.to_matrix() for g in self.gens()])

    def as_permutation_group(self):
        r"""
        Return the permutation group corresponding to ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.as_permutation_group()
            Complex reflection group G(4, 1, 3) as a permutation group
        """
        from sage.groups.perm_gps.permgroup_named import ComplexReflectionGroup
        return ComplexReflectionGroup(self._m, 1, self._n)

    def _element_constructor_(self, x):
        """
        Construct an element of ``self`` from ``x``.

        INPUT:

        Either a list of pairs (color, element)
        or a pair of lists (colors, elements).

        TESTS::

            sage: C = ColoredPermutations(4, 3)
            sage: x = C([(2,1), (3,3), (3,2)]); x
            [[2, 3, 3], [1, 3, 2]]
            sage: x == C([[2,3,3], [1,3,2]])
            True
        """
        if isinstance(x, list):
            if isinstance(x[0], tuple):
                c = []
                p = []
                for k in x:
                    if len(k) != 2:
                        raise ValueError(
                            "input must be pairs (color, element)")
                    c.append(self._C(k[0]))
                    p.append(k[1])
                return self.element_class(self, c, self._P(p))

            if len(x) != 2:
                raise ValueError(
                    "input must be a pair of a list of colors and a permutation"
                )
            return self.element_class(self, [self._C(v) for v in x[0]],
                                      self._P(x[1]))

    def _coerce_map_from_(self, C):
        """
        Return a coerce map from ``C`` if it exists and ``None`` otherwise.

        EXAMPLES::

            sage: C = ColoredPermutations(2, 3)
            sage: S = SignedPermutations(3)
            sage: C.has_coerce_map_from(S)
            True

            sage: C = ColoredPermutations(4, 3)
            sage: C.has_coerce_map_from(S)
            False
            sage: S = SignedPermutations(4)
            sage: C.has_coerce_map_from(S)
            False

            sage: P = Permutations(3)
            sage: C.has_coerce_map_from(P)
            True
            sage: P = Permutations(4)
            sage: C.has_coerce_map_from(P)
            False
        """
        if isinstance(C, Permutations) and C.n == self._n:
            return lambda P, x: P.element_class(P, [P._C.zero()] * P._n, x)
        if self._m == 2 and isinstance(C,
                                       SignedPermutations) and C._n == self._n:
            return lambda P, x: P.element_class(
                P, [P._C.zero() if v == 1 else P._C.one()
                    for v in x._colors], x._perm)
        return super(ColoredPermutations, self)._coerce_map_from_(C)

    def __iter__(self):
        """
        Iterate over ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(2, 2)
            sage: [x for x in C]
            [[[0, 0], [1, 2]],
             [[0, 1], [1, 2]],
             [[1, 0], [1, 2]],
             [[1, 1], [1, 2]],
             [[0, 0], [2, 1]],
             [[0, 1], [2, 1]],
             [[1, 0], [2, 1]],
             [[1, 1], [2, 1]]]
        """
        for p in self._P:
            for c in itertools.product(self._C, repeat=self._n):
                yield self.element_class(self, c, p)

    def cardinality(self):
        """
        Return the cardinality of ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.cardinality()
            384
            sage: C.cardinality() == 4**3 * factorial(3)
            True
        """
        return self._m**self._n * self._P.cardinality()

    order = cardinality

    def rank(self):
        """
        Return the rank of ``self``.

        The rank of a complex reflection group is equal to the dimension
        of the complex vector space the group acts on.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 12)
            sage: C.rank()
            12
            sage: C = ColoredPermutations(7, 4)
            sage: C.rank()
            4
            sage: C = ColoredPermutations(1, 4)
            sage: C.rank()
            3
        """
        if self._m == 1:
            return self._n - 1
        return self._n

    def degrees(self):
        r"""
        Return the degrees of ``self``.

        The degrees of a complex reflection group are the degrees of
        the fundamental invariants of the ring of polynomial invariants.

        If `m = 1`, then we are in the special case of the symmetric group
        and the degrees are `(2, 3, \ldots, n, n+1)`. Otherwise the degrees
        are `(m, 2m, \ldots, nm)`.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.degrees()
            (4, 8, 12)
            sage: S = ColoredPermutations(1, 3)
            sage: S.degrees()
            (2, 3)

        We now check that the product of the degrees is equal to the
        cardinality of ``self``::

            sage: prod(C.degrees()) == C.cardinality()
            True
            sage: prod(S.degrees()) == S.cardinality()
            True
        """
        # For the usual symmetric group (self._m=1) we need to start at 2
        start = 2 if self._m == 1 else 1
        return tuple(self._m * i for i in range(start, self._n + 1))

    def codegrees(self):
        r"""
        Return the codegrees of ``self``.

        Let `G` be a complex reflection group. The codegrees
        `d_1^* \leq d_2^* \leq \cdots \leq d_{\ell}^*` of `G` can be
        defined by:

        .. MATH::

            \prod_{i=1}^{\ell} (q - d_i^* - 1)
            = \sum_{g \in G} \det(g) q^{\dim(V^g)},

        where `V` is the natural complex vector space that `G` acts on
        and `\ell` is the :meth:`rank`.

        If `m = 1`, then we are in the special case of the symmetric group
        and the codegrees are `(n-2, n-3, \ldots 1, 0)`. Otherwise the degrees
        are `((n-1)m, (n-2)m, \ldots, m, 0)`.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.codegrees()
            (8, 4, 0)
            sage: S = ColoredPermutations(1, 3)
            sage: S.codegrees()
            (1, 0)

        TESTS:

        We check the polynomial identity::

            sage: R.<q> = ZZ[]
            sage: C = ColoredPermutations(3, 2)
            sage: f = prod(q - ds - 1 for ds in C.codegrees())
            sage: d = lambda x: sum(1 for e in x.to_matrix().eigenvalues() if e == 1)
            sage: g = sum(det(x.to_matrix()) * q**d(x) for x in C)
            sage: f == g
            True
        """
        # Special case for the usual symmetric group
        last = self._n - 1 if self._m == 1 else self._n
        return tuple(self._m * i for i in reversed(range(last)))

    def number_of_reflection_hyperplanes(self):
        """
        Return the number of reflection hyperplanes of ``self``.

        The number of reflection hyperplanes of a complex reflection
        group is equal to the sum of the codegrees plus the rank.

        EXAMPLES::

            sage: C = ColoredPermutations(1, 2)
            sage: C.number_of_reflection_hyperplanes()
            1
            sage: C = ColoredPermutations(1, 3)
            sage: C.number_of_reflection_hyperplanes()
            3
            sage: C = ColoredPermutations(4, 12)
            sage: C.number_of_reflection_hyperplanes()
            276
        """
        return sum(self.codegrees()) + self.rank()

    def fixed_point_polynomial(self, q=None):
        r"""
        The fixed point polynomial of ``self``.

        The fixed point polynomial `f_G` of a complex reflection group `G`
        is counting the dimensions of fixed points subspaces:

        .. MATH::

            f_G(q) = \sum_{w \in W} q^{\dim V^w}.

        Furthermore, let `d_1, d_2, \ldots, d_{\ell}` be the degrees of `G`,
        where `\ell` is the :meth:`rank`. Then the fixed point polynomial
        is given by

        .. MATH::

            f_G(q) = \prod_{i=1}^{\ell} (q + d_i - 1).

        INPUT:

        - ``q`` -- (default: the generator of ``ZZ['q']``) the parameter `q`

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.fixed_point_polynomial()
            q^3 + 21*q^2 + 131*q + 231

            sage: S = ColoredPermutations(1, 3)
            sage: S.fixed_point_polynomial()
            q^2 + 3*q + 2

        TESTS:

        We check the against the degrees and codegrees::

            sage: R.<q> = ZZ[]
            sage: C = ColoredPermutations(4, 3)
            sage: C.fixed_point_polynomial(q) == prod(q + d - 1 for d in C.degrees())
            True
        """
        if q is None:
            q = PolynomialRing(ZZ, 'q').gen(0)
        return prod(q + d - 1 for d in self.degrees())

    def is_well_generated(self):
        r"""
        Return if ``self`` is a well-generated complex reflection group.

        A complex reflection group `G` is well-generated if it is
        generated by `\ell` reflections. Equivalently, `G` is well-generated
        if `d_i + d_i^* = d_{\ell}` for all `1 \leq i \leq \ell`.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.is_well_generated()
            True
            sage: C = ColoredPermutations(2, 8)
            sage: C.is_well_generated()
            True
            sage: C = ColoredPermutations(1, 4)
            sage: C.is_well_generated()
            True
        """
        deg = self.degrees()
        dstar = self.codegrees()
        return all(deg[-1] == d + dstar[i] for i, d in enumerate(deg))

    Element = ColoredPermutation
def Watson_mass_at_2(self):
    """
    Returns the local mass of the quadratic form when `p=2`, according
    to Watson's Theorem 1 of "The 2-adic density of a quadratic form"
    in Mathematika 23 (1976), pp 94--106.

    INPUT:

        none

    OUTPUT:

        a rational number

    EXAMPLES::

        sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1])
        sage: Q.Watson_mass_at_2()               ## WARNING:  WE NEED TO CHECK THIS CAREFULLY!
        384

    """
    ## Make a 0-dim'l quadratic form (for initialization purposes)
    Null_Form = copy.deepcopy(self)
    Null_Form.__init__(ZZ, 0)

    ## Step 0: Compute Jordan blocks and bounds of the scales to keep track of
    Jordan_Blocks = self.jordan_blocks_by_scale_and_unimodular(2)
    scale_list = [B[0] for B in Jordan_Blocks]
    s_min = min(scale_list)
    s_max = max(scale_list)

    ## Step 1: Compute dictionaries of the diagonal block and 2x2 block for each scale
    diag_dict = dict(
        (i, Null_Form)
        for i in range(s_min - 2, s_max + 4))  ## Initialize with the zero form
    dim2_dict = dict(
        (i, Null_Form)
        for i in range(s_min, s_max + 4))  ## Initialize with the zero form
    for (s, L) in Jordan_Blocks:
        i = 0
        while (i < L.dim() - 1) and (L[i, i + 1]
                                     == 0):  ## Find where the 2x2 blocks start
            i = i + 1
        if i < (L.dim() - 1):
            diag_dict[s] = L.extract_variables(range(i))  ## Diagonal Form
            dim2_dict[s + 1] = L.extract_variables(range(
                i, L.dim()))  ## Non-diagonal Form
        else:
            diag_dict[s] = L

    #print "diag_dict = ", diag_dict
    #print "dim2_dict = ", dim2_dict
    #print "Jordan_Blocks = ", Jordan_Blocks

    ## Step 2: Compute three dictionaries of invariants (for n_j, m_j, nu_j)
    n_dict = dict((j, 0) for j in range(s_min + 1, s_max + 2))
    m_dict = dict((j, 0) for j in range(s_min, s_max + 4))
    for (s, L) in Jordan_Blocks:
        n_dict[s + 1] = L.dim()
        if diag_dict[s].dim() == 0:
            m_dict[s + 1] = ZZ.one() / ZZ(2) * L.dim()
        else:
            m_dict[s + 1] = floor(ZZ(L.dim() - 1) / ZZ(2))
            #print " ==>", ZZ(L.dim() - 1) / ZZ(2), floor(ZZ(L.dim() - 1) / ZZ(2))

    nu_dict = dict((j, n_dict[j + 1] - 2 * m_dict[j + 1])
                   for j in range(s_min, s_max + 1))
    nu_dict[s_max + 1] = 0

    #print "n_dict = ", n_dict
    #print "m_dict = ", m_dict
    #print "nu_dict = ", nu_dict

    ## Step 3: Compute the e_j dictionary
    eps_dict = {}
    for j in range(s_min, s_max + 3):
        two_form = (diag_dict[j - 2] + diag_dict[j] +
                    dim2_dict[j]).scale_by_factor(2)
        j_form = (two_form + diag_dict[j - 1]).base_change_to(
            IntegerModRing(4))

        if j_form.dim() == 0:
            eps_dict[j] = 1
        else:
            iter_vec = [4] * j_form.dim()
            alpha = sum([True for x in mrange(iter_vec) if j_form(x) == 0])
            beta = sum([True for x in mrange(iter_vec) if j_form(x) == 2])
            if alpha > beta:
                eps_dict[j] = 1
            elif alpha == beta:
                eps_dict[j] = 0
            else:
                eps_dict[j] = -1

    #print "eps_dict = ", eps_dict

    ## Step 4: Compute the quantities nu, q, P, E for the local mass at 2
    nu = sum([j * n_dict[j] * (ZZ(n_dict[j] + 1) / ZZ(2) + \
              sum([n_dict[r]  for r in range(j+1, s_max+2)]))  for j in range(s_min+1, s_max+2)])
    q = sum([
        sgn(nu_dict[j - 1] * (n_dict[j] + sgn(nu_dict[j])))
        for j in range(s_min + 1, s_max + 2)
    ])
    P = prod([
        prod([1 - QQ(4)**(-i) for i in range(1, m_dict[j] + 1)])
        for j in range(s_min + 1, s_max + 2)
    ])
    E = prod([
        ZZ(1) / ZZ(2) * (1 + eps_dict[j] * QQ(2)**(-m_dict[j]))
        for j in range(s_min, s_max + 3)
    ])

    #print "\nFinal Summary:"
    #print "nu =", nu
    #print "q = ", q
    #print "P = ", P
    #print "E = ", E

    ## Step 5: Compute the local mass for the prime 2.
    mass_at_2 = QQ(2)**(nu - q) * P / E
    return mass_at_2
Example #25
0
def my_gen_lattice2(n=4, q=11, seed=None,
                quotient=None, dual=False, ntl=False, lattice=False, GuessStuff=True):
    """
    This is a modification of the code for the gen_lattice function from Sage
 
    Randomness can be set either with ``seed``, or by using
    :func:`sage.misc.randstate.set_random_seed`.
 
    INPUT:
 
    - ``type`` -- one of the following strings
        - ``'cyclotomic'`` -- Special case of ideal. Allows for
          efficient processing proposed by [LM2006]_.
    - ``n`` -- Determinant size, primal:`det(L) = q^n`, dual:`det(L) = q^{m-n}`.
      For ideal lattices this is also the degree of the quotient polynomial.
    - ``m`` -- Lattice dimension, `L \subseteq Z^m`.
    - ``q`` -- Coefficient size, `q-Z^m \subseteq L`.
    - ``t`` -- BKZ Block Size
    - ``seed`` -- Randomness seed.
    - ``quotient`` -- For the type ideal, this determines the quotient
      polynomial. Ignored for all other types.
    - ``dual`` -- Set this flag if you want a basis for `q-dual(L)`, for example
      for Regev's LWE bases [Reg2005]_.
    - ``ntl`` -- Set this flag if you want the lattice basis in NTL readable
      format.
    - ``lattice`` -- Set this flag if you want a
      :class:`FreeModule_submodule_with_basis_integer` object instead
      of an integer matrix representing the basis.
 
    OUTPUT: ``B`` a unique size-reduced triangular (primal: lower_left,
      dual: lower_right) basis of row vectors for the lattice in question.
 
    EXAMPLES:
 
 
 
    Cyclotomic bases with n=2^k are SWIFFT bases::
 
        sage: sage.crypto.gen_lattice(type='cyclotomic', seed=42)
        [11  0  0  0  0  0  0  0]
        [ 0 11  0  0  0  0  0  0]
        [ 0  0 11  0  0  0  0  0]
        [ 0  0  0 11  0  0  0  0]
        [ 4 -2 -3 -3  1  0  0  0]
        [ 3  4 -2 -3  0  1  0  0]
        [ 3  3  4 -2  0  0  1  0]
        [ 2  3  3  4  0  0  0  1]
 
    Dual modular bases are related to Regev's famous public-key
    encryption [Reg2005]_::
 
        sage: sage.crypto.gen_lattice(type='modular', m=10, seed=42, dual=True)
        [ 0  0  0  0  0  0  0  0  0 11]
        [ 0  0  0  0  0  0  0  0 11  0]
        [ 0  0  0  0  0  0  0 11  0  0]
        [ 0  0  0  0  0  0 11  0  0  0]
        [ 0  0  0  0  0 11  0  0  0  0]
        [ 0  0  0  0 11  0  0  0  0  0]
        [ 0  0  0  1 -5 -2 -1  1 -3  5]
        [ 0  0  1  0 -3  4  1  4 -3 -2]
        [ 0  1  0  0 -4  5 -3  3  5  3]
        [ 1  0  0  0 -2 -1  4  2  5  4]
 
 
    """
    from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
    from sage.matrix.constructor import identity_matrix, block_matrix
    from sage.matrix.matrix_space import MatrixSpace
    from sage.rings.integer_ring import IntegerRing
    from sage.modules.free_module_integer import IntegerLattice
       
    if seed is not None:
        from sage.misc.randstate import set_random_seed
        set_random_seed(seed)
 
 
    m=n+1
    ZZ = IntegerRing()
    ZZ_q = IntegerModRing(q)
 
 
 
    from sage.arith.all import euler_phi
    from sage.misc.functional import cyclotomic_polynomial
 
    # we assume that n+1 <= min( euler_phi^{-1}(n) ) <= 2*n
    found = False
    for k in range(2*n,n,-1):
        if euler_phi(k) == n:
            found = True
            break
        if not found:
            raise ValueError("cyclotomic bases require that n "
                                 "is an image of Euler's totient function")
    R = ZZ_q['x'].quotient(cyclotomic_polynomial(2*n, 'x'), 'x')
    g=x**(n/2)+1
    T=ZZ_q['x'].quotient(x**(n/2)+1)
 
   
    a_pol=R.random_element()

    s_pol=sample_noise(R)
    e_pol=sample_noise(R)
 
    s_pol2=T((s_pol))
    e_pol2=T((e_pol))
    print("s={0},e={1}".format(T(s_pol),T(e_pol)))

    
    Z_mat=e_pol2.matrix().augment(s_pol2.matrix())
    Z_mattop=Z_mat[0:1].augment(matrix(1,1,[ZZ.one()*-1]))
  
  
    b_pol=(a_pol*s_pol+e_pol)
    print("s_pol={0}\ne_pol={1}".format((s_pol2).list(),(e_pol2).list()))
    # Does a linear mapping change the shortest vector size for the rest?/
    a_pol=a_pol#*x_pol
    b_pol=b_pol#*x_pol

    a_pol2 = T(a_pol.list())# % S(g.list())
    b_pol2 = T((b_pol).list())# % S(g.list())
#    print("a={0}\nb={1}".format(a_pol2,b_pol2))
    A=identity_matrix(ZZ_q,n/2)
    A=A.stack(a_pol2.matrix())
    
    
    b_prime=b_pol2.matrix()[0:1]
    b_prime=b_prime - 11*A[8:9]
    A=A.stack(b_pol2.matrix()[0:1])

    
    
#    print("X=\n{0}".format(X))

#    A = A.stack(identity_matrix(ZZ_q, n/2))
 
    print("A=\n{0}\n".format(A))
    # switch from representatives 0,...,(q-1) to (1-q)/2,....,(q-1)/2
    def minrepnegative(a):
        if abs(a-q) < abs(a): return (a-q)*-1
        else: return a*-1
    def minrep(a):
        if abs(a-q) < abs(a): return (a-q)
        else: return a
    A_prime = A[(n/2):(n+1)].lift().apply_map(minrep)
#    b_neg= A[(n):(n+1)].lift().apply_map(minrepnegative)
    Z_fixed=Z_mattop.lift().apply_map(minrep)
    print("Z_fixed={0}\n||Z_fixed||={1}".format(Z_fixed,float(Z_fixed[0].norm())))
    print('Z_fixed*A={0}\n\n'.format(Z_fixed*A))

    print("z_fixed[0].norm()={0}".format(float(Z_fixed[0].norm())))
#    B=block_matrix([[ZZ(q),ZZ.zero()],[A_neg,ZZ.one()]], subdivide=False)
#    B = block_matrix([[ZZ.one(), -A_prime.transpose()],
#                     [ZZ.zero(), ZZ(q)]], subdivide=False)
    B = block_matrix([[ZZ(q), ZZ.zero()], [-A_prime, ZZ.one()]], subdivide=False)
#    for i in range(m//2):
#        B.swap_rows(i,m-i-1)
    #    print("{0}\n".format(A_neg))
 #   B=block_matrix([[ZZ(q), ZZ.zero(),ZZ.zero()],[ZZ.one(),A_neg,ZZ.zero() ],[ZZ.zero(),b_neg,ZZ.one()]],
                     #  subdivide=False)
    #print("B=\n{0}".format(B))
    print("B*A=\n{0}\n\n".format(B*A))
    #print("A=\n{0}\n".format(A))
    def remap(x):
        return minrep((x*251)%251)
    BL=B.BKZ(block_size=n/2.)
    y=(BL.solve_left(Z_fixed))#.apply_map(remap))

#   print("y*B={0}".format(y*B))
    print("y:=B.solve_left(Z_fixed)={0}".format(y))
#    BL=B.BKZ(block_size=n/2.)
    print(BL[0])
    print("shortest norm={0}".format(float(BL[0].norm())))
#    L = IntegerLattice(B)
#    p
#    v=L.shortest_vector()
#    print("L.shortest_vector={0}, norm={1}".format(v,float(v.norm())))
    if ntl and lattice:
        raise ValueError("Cannot specify ntl=True and lattice=True ")
    if ntl:
        return B._ntl_()
    elif lattice:
        from sage.modules.free_module_integer import IntegerLattice
        return IntegerLattice(B)
    else:
        return B
Example #26
0
def discrete_log_rho(a, base, ord=None, operation='*', hash_function=hash):
    """
    Pollard Rho algorithm for computing discrete logarithm in cyclic
    group of prime order.
    If the group order is very small it falls back to the baby step giant step
    algorithm.

    INPUT:

    - ``a`` -- a group element
    - ``base`` -- a group element
    - ``ord`` -- the order of ``base`` or ``None``, in this case we try
      to compute it
    - ``operation`` -- a string (default: ``'*'``) denoting whether we
      are in an additive group or a multiplicative one
    - ``hash_function`` -- having an efficient hash function is critical
      for this algorithm (see examples)

    OUTPUT: an integer `n` such that `a = base^n` (or `a = n*base`)

    ALGORITHM: Pollard rho for discrete logarithm, adapted from the
    article of Edlyn Teske, 'A space efficient algorithm for group
    structure computation'.

    EXAMPLES::

        sage: F.<a> = GF(2^13)
        sage: g = F.gen()
        sage: discrete_log_rho(g^1234, g)
        1234

        sage: F.<a> = GF(37^5)
        sage: E = EllipticCurve(F, [1,1])
        sage: G = (3*31*2^4)*E.lift_x(a)
        sage: discrete_log_rho(12345*G, G, ord=46591, operation='+')
        12345

    It also works with matrices::

        sage: A = matrix(GF(50021),[[10577,23999,28893],[14601,41019,30188],[3081,736,27092]])
        sage: discrete_log_rho(A^1234567, A)
        1234567

    Beware, the order must be prime::

        sage: I = IntegerModRing(171980)
        sage: discrete_log_rho(I(2), I(3))
        Traceback (most recent call last):
        ...
        ValueError: for Pollard rho algorithm the order of the group must be prime

    If it fails to find a suitable logarithm, it raises a ``ValueError``::

        sage: I = IntegerModRing(171980)
        sage: discrete_log_rho(I(31002),I(15501))
        Traceback (most recent call last):
        ...
        ValueError: Pollard rho algorithm failed to find a logarithm

    The main limitation on the hash function is that we don't want to have
    `hash(x*y) = hash(x) + hash(y)`::

        sage: I = IntegerModRing(next_prime(2^23))
        sage: def test():
        ....:     try:
        ....:          discrete_log_rho(I(123456),I(1),operation='+')
        ....:     except Exception:
        ....:          print("FAILURE")
        sage: test()  # random failure
        FAILURE

    If this happens, we can provide a better hash function::

        sage: discrete_log_rho(I(123456),I(1),operation='+', hash_function=lambda x: hash(x*x))
        123456

    AUTHOR:

    - Yann Laigle-Chapuy (2009-09-05)

    """
    from six.moves import range
    from sage.rings.integer import Integer
    from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
    from operator import mul, add, pow

    # should be reasonable choices
    partition_size = 20
    memory_size = 4

    if operation in addition_names:
        mult = add
        power = mul
        if ord is None:
            ord = base.additive_order()
    elif operation in multiplication_names:
        mult = mul
        power = pow
        if ord is None:
            ord = base.multiplicative_order()
    else:
        raise ValueError

    ord = Integer(ord)

    if not ord.is_prime():
        raise ValueError(
            "for Pollard rho algorithm the order of the group must be prime")

    # check if we need to set immutable before hashing
    mut = hasattr(base, 'set_immutable')

    isqrtord = ord.isqrt()

    if isqrtord < partition_size:  #setup to costly, use bsgs
        return bsgs(base, a, bounds=(0, ord), operation=operation)

    reset_bound = 8 * isqrtord  # we take some margin

    I = IntegerModRing(ord)

    for s in range(10):  # to avoid infinite loops
        # random walk function setup
        m = [I.random_element() for i in range(partition_size)]
        n = [I.random_element() for i in range(partition_size)]
        M = [
            mult(power(base, Integer(m[i])), power(a, Integer(n[i])))
            for i in range(partition_size)
        ]

        ax = I.random_element()
        x = power(base, Integer(ax))
        if mut:
            x.set_immutable()

        bx = I(0)

        sigma = [(0, None)] * memory_size
        H = {}  # memory
        i0 = 0
        nextsigma = 0
        for i in range(reset_bound):
            #random walk, we need an efficient hash
            s = hash_function(x) % partition_size
            (x, ax, bx) = (mult(M[s], x), ax + m[s], bx + n[s])
            if mut:
                x.set_immutable()
            # look for collisions
            if x in H:
                ay, by = H[x]
                if bx == by:
                    break
                else:
                    res = sage.rings.integer.Integer((ay - ax) / (bx - by))
                    if power(base, res) == a:
                        return res
                    else:
                        break
            # should we remember this value?
            elif i >= nextsigma:
                if sigma[i0][1] is not None:
                    H.pop(sigma[i0][1])
                sigma[i0] = (i, x)
                i0 = (i0 + 1) % memory_size
                nextsigma = 3 * sigma[i0][0]  #3 seems a good choice
                H[x] = (ax, bx)

    raise ValueError("Pollard rho algorithm failed to find a logarithm")
Example #27
0
    def padic_H_value(self, p, f, t, prec=None, cache_p=False):
        """
        Return the `p`-adic trace of Frobenius, computed using the
        Gross-Koblitz formula.

        If left unspecified, `prec` is set to the minimum `p`-adic precision
        needed to recover the Euler factor.

        If `cache_p` is True, then the function caches an intermediate
        result which depends only on `p` and `f`. This leads to a significant
        speedup when iterating over `t`.

        INPUT:

        - `p` -- a prime number

        - `f` -- an integer such that `q = p^f`

        - `t` -- a rational parameter

        - ``prec`` -- precision (optional)

        - ``cache_p`` - a boolean

        OUTPUT:

        an integer

        EXAMPLES:

        From Benasque report [Benasque2009]_, page 8::

            sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp
            sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4))
            sage: [H.padic_H_value(3,i,-1) for i in range(1,3)]
            [0, -12]
            sage: [H.padic_H_value(5,i,-1) for i in range(1,3)]
            [-4, 276]
            sage: [H.padic_H_value(7,i,-1) for i in range(1,3)]
            [0, -476]
            sage: [H.padic_H_value(11,i,-1) for i in range(1,3)]
            [0, -4972]

        From [Roberts2015]_ (but note conventions regarding `t`)::

            sage: H = Hyp(gamma_list=[-6,-1,4,3])
            sage: t = 189/125
            sage: H.padic_H_value(13,1,1/t)
            0

        TESTS:

        Check issue from :trac:`28404`::

            sage: H1 = Hyp(cyclotomic=([1,1,1],[6,2]))
            sage: H2 = Hyp(cyclotomic=([6,2],[1,1,1]))
            sage: [H1.padic_H_value(5,1,i) for i in range(2,5)]
            [1, -4, -4]
            sage: [H2.padic_H_value(5,1,i) for i in range(2,5)]
            [-4, 1, -4]

        Check for potential overflow::

            sage: H = Hyp(cyclotomic=[[10,6],[5,4]])
            sage: H.padic_H_value(101, 2, 2)
            -1560629

        REFERENCES:

        - [MagmaHGM]_
        """
        alpha = self._alpha
        beta = self._beta
        t = QQ(t)
        if 0 in alpha:
            return self._swap.padic_H_value(p, f, ~t, prec)
        q = p ** f
        if q > 2 ** 31:
            return ValueError("p^f cannot exceed 2^31")

        m = array.array('i', [0]) * int(q - 1)
        for b in beta:
            u = b * (q - 1)
            if u.is_integer(): m[u] += 1
        M = self.M_value()
        D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta)
        # also: D = (self.weight() + 1 - m[0]) // 2

        if prec is None:
            prec = ceil((self.weight() * f) / 2 + log(2*self.degree()+1, p))
        use_longs = (p ** prec < 2 ** 31)

        gamma = self._gamma_array
        if cache_p:
            try:
                trcoeffs = self._trace_coeffs[p, f]
            except KeyError:
                gtab_prec, gtab = self.gauss_table(p, f, prec)
                trcoeffs = hgm_coeffs(p, f, prec, gamma, m, D, gtab, gtab_prec, use_longs)
                self._trace_coeffs[p, f] = trcoeffs
        else:
            gtab = gauss_table(p, f, prec, use_longs)
            trcoeffs = hgm_coeffs(p, f, prec, gamma, m, D, gtab, prec, use_longs)
        sigma = trcoeffs[q-2]
        p_ring = sigma.parent()
        teich = p_ring.teichmuller(M/t)
        for i in range(q-3, -1, -1):
            sigma = sigma * teich + trcoeffs[i]
        resu = ZZ(-1) ** m[0] * sigma / (1 - q)
        return IntegerModRing(p**prec)(resu).lift_centered()
class ColoredPermutations(Parent, UniqueRepresentation):
    r"""
    The group of `m`-colored permutations on `\{1, 2, \ldots, n\}`.

    Let `S_n` be the symmetric group on `n` letters and `C_m` be the cyclic
    group of order `m`. The `m`-colored permutation group on `n` letters
    is given by `P_n^m = C_m \wr S_n`. This is also the complex reflection
    group `G(m, 1, n)`.

    We define our multiplication by

    .. MATH::

        ((s_1, \ldots s_n), \sigma) \cdot ((t_1, \ldots, t_n), \tau)
        = ((s_1 t_{\sigma(1)}, \ldots, s_n t_{\sigma(n)}), \tau \sigma).

    EXAMPLES::

        sage: C = ColoredPermutations(4, 3); C
        4-colored permutations of size 3
        sage: s1,s2,t = C.gens()
        sage: (s1, s2, t)
        ([[0, 0, 0], [2, 1, 3]], [[0, 0, 0], [1, 3, 2]], [[0, 0, 1], [1, 2, 3]])
        sage: s1*s2
        [[0, 0, 0], [3, 1, 2]]
        sage: s1*s2*s1 == s2*s1*s2
        True
        sage: t^4 == C.one()
        True
        sage: s2*t*s2
        [[0, 1, 0], [1, 2, 3]]

    We can also create a colored permutation by passing
    either a list of tuples consisting of ``(color, element)``::

        sage: x = C([(2,1), (3,3), (3,2)]); x
        [[2, 3, 3], [1, 3, 2]]

    or a list of colors and a permutation::

        sage: C([[3,3,1], [1,3,2]])
        [[3, 3, 1], [1, 3, 2]]

    There is also the natural lift from permutations::

        sage: P = Permutations(3)
        sage: C(P.an_element())
        [[0, 0, 0], [3, 1, 2]]

    REFERENCES:

    - :wikipedia:`Generalized_symmetric_group`
    - :wikipedia:`Complex_reflection_group`
    """
    def __init__(self, m, n):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: TestSuite(C).run()
            sage: C = ColoredPermutations(2, 3)
            sage: TestSuite(C).run()
            sage: C = ColoredPermutations(1, 3)
            sage: TestSuite(C).run()
        """
        if m <= 0:
            raise ValueError("m must be a positive integer")
        self._m = ZZ(m)
        self._n = ZZ(n)
        self._C = IntegerModRing(self._m)
        self._P = Permutations(self._n)

        if self._m == 1 or self._m == 2:
            from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups
            category = FiniteCoxeterGroups().Irreducible()
        else:
            from sage.categories.complex_reflection_groups import ComplexReflectionGroups
            category = ComplexReflectionGroups().Finite().Irreducible().WellGenerated()
        Parent.__init__(self, category=category)

    def _repr_(self):
        """
        Return a string representation of ``self``.

        EXAMPLES::

            sage: ColoredPermutations(4, 3)
            4-colored permutations of size 3
        """
        return "{}-colored permutations of size {}".format(self._m, self._n)

    @cached_method
    def index_set(self):
        """
        Return the index set of ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(3, 4)
            sage: C.index_set()
            (1, 2, 3, 4)

            sage: C = ColoredPermutations(1, 4)
            sage: C.index_set()
            (1, 2, 3)

        TESTS::

            sage: S = SignedPermutations(4)
            sage: S.index_set()
            (1, 2, 3, 4)
        """
        n = self._n
        if self._m != 1:
            n += 1
        return tuple(range(1, n))

    def coxeter_matrix(self):
        """
        Return the Coxeter matrix of ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(3, 4)
            sage: C.coxeter_matrix()
            [1 3 2 2]
            [3 1 3 2]
            [2 3 1 4]
            [2 2 4 1]

            sage: C = ColoredPermutations(1, 4)
            sage: C.coxeter_matrix()
            [1 3 2]
            [3 1 3]
            [2 3 1]

        TESTS::

            sage: S = SignedPermutations(4)
            sage: S.coxeter_matrix()
            [1 3 2 2]
            [3 1 3 2]
            [2 3 1 4]
            [2 2 4 1]
        """
        from sage.combinat.root_system.cartan_type import CartanType
        if self._m == 1:
            return CartanType(['A', self._n-1]).coxeter_matrix()
        return CartanType(['B', self._n]).coxeter_matrix()

    @cached_method
    def one(self):
        """
        Return the identity element of ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.one()
            [[0, 0, 0], [1, 2, 3]]
        """
        return self.element_class(self, [self._C.zero()] * self._n,
                                  self._P.identity())

    def simple_reflection(self, i):
        r"""
        Return the ``i``-th simple reflection of ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.gens()
            ([[0, 0, 0], [2, 1, 3]], [[0, 0, 0], [1, 3, 2]], [[0, 0, 1], [1, 2, 3]])
            sage: C.simple_reflection(2)
            [[0, 0, 0], [1, 3, 2]]
            sage: C.simple_reflection(3)
            [[0, 0, 1], [1, 2, 3]]

            sage: S = SignedPermutations(4)
            sage: S.simple_reflection(1)
            [2, 1, 3, 4]
            sage: S.simple_reflection(4)
            [1, 2, 3, -4]
        """
        if i not in self.index_set():
            raise ValueError("i must be in the index set")
        colors = [self._C.zero()] * self._n
        if i < self._n:
            p = list(range(1, self._n + 1))
            p[i - 1] = i + 1
            p[i] = i
            return self.element_class(self, colors, self._P(p))
        colors[-1] = self._C.one()
        return self.element_class(self, colors, self._P.identity())

    @cached_method
    def _inverse_simple_reflections(self):
        """
        Return the inverse of the simple reflections of ``self``.

        .. WARNING::

            This returns a ``dict`` that should not be mutated since
            the result is cached.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C._inverse_simple_reflections()
            {1: [[0, 0, 0], [2, 1, 3]],
             2: [[0, 0, 0], [1, 3, 2]],
             3: [[0, 0, 3], [1, 2, 3]]}
        """
        s = self.simple_reflections()
        return {i: ~s[i] for i in self.index_set()}

    @cached_method
    def gens(self):
        """
        Return the generators of ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.gens()
            ([[0, 0, 0], [2, 1, 3]],
             [[0, 0, 0], [1, 3, 2]],
             [[0, 0, 1], [1, 2, 3]])

            sage: S = SignedPermutations(4)
            sage: S.gens()
            ([2, 1, 3, 4], [1, 3, 2, 4], [1, 2, 4, 3], [1, 2, 3, -4])
        """
        return tuple(self.simple_reflection(i) for i in self.index_set())

    def matrix_group(self):
        """
        Return the matrix group corresponding to ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.matrix_group()
            Matrix group over Cyclotomic Field of order 4 and degree 2 with 3 generators (
            [0 1 0]  [1 0 0]  [    1     0     0]
            [1 0 0]  [0 0 1]  [    0     1     0]
            [0 0 1], [0 1 0], [    0     0 zeta4]
            )
        """
        from sage.groups.matrix_gps.finitely_generated import MatrixGroup
        return MatrixGroup([g.to_matrix() for g in self.gens()])

    def _element_constructor_(self, x):
        """
        Construct an element of ``self`` from ``x``.

        INPUT:

        Either a list of pairs (color, element)
        or a pair of lists (colors, elements).

        TESTS::

            sage: C = ColoredPermutations(4, 3)
            sage: x = C([(2,1), (3,3), (3,2)]); x
            [[2, 3, 3], [1, 3, 2]]
            sage: x == C([[2,3,3], [1,3,2]])
            True
        """
        if isinstance(x, list):
            if isinstance(x[0], tuple):
                c = []
                p = []
                for k in x:
                    if len(k) != 2:
                        raise ValueError("input must be pairs (color, element)")
                    c.append(self._C(k[0]))
                    p.append(k[1])
                return self.element_class(self, c, self._P(p))

            if len(x) != 2:
                raise ValueError("input must be a pair of a list of colors and a permutation")
            return self.element_class(self, [self._C(v) for v in x[0]], self._P(x[1]))

    def _coerce_map_from_(self, C):
        """
        Return a coerce map from ``C`` if it exists and ``None`` otherwise.

        EXAMPLES::

            sage: C = ColoredPermutations(2, 3)
            sage: S = SignedPermutations(3)
            sage: C.has_coerce_map_from(S)
            True

            sage: C = ColoredPermutations(4, 3)
            sage: C.has_coerce_map_from(S)
            False
            sage: S = SignedPermutations(4)
            sage: C.has_coerce_map_from(S)
            False

            sage: P = Permutations(3)
            sage: C.has_coerce_map_from(P)
            True
            sage: P = Permutations(4)
            sage: C.has_coerce_map_from(P)
            False
        """
        if isinstance(C, Permutations) and C.n == self._n:
            return lambda P, x: P.element_class(P, [P._C.zero()]*P._n, x)
        if self._m == 2 and isinstance(C, SignedPermutations) and C._n == self._n:
            return lambda P, x: P.element_class(P,
                                                [P._C.zero() if v == 1 else P._C.one()
                                                 for v in x._colors],
                                                x._perm)
        return super(ColoredPermutations, self)._coerce_map_from_(C)

    def __iter__(self):
        """
        Iterate over ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(2, 2)
            sage: [x for x in C]
            [[[0, 0], [1, 2]],
             [[0, 1], [1, 2]],
             [[1, 0], [1, 2]],
             [[1, 1], [1, 2]],
             [[0, 0], [2, 1]],
             [[0, 1], [2, 1]],
             [[1, 0], [2, 1]],
             [[1, 1], [2, 1]]]
        """
        for p in self._P:
            for c in itertools.product(self._C, repeat=self._n):
                yield self.element_class(self, c, p)

    def cardinality(self):
        """
        Return the cardinality of ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.cardinality()
            384
            sage: C.cardinality() == 4**3 * factorial(3)
            True
        """
        return self._m ** self._n * self._P.cardinality()

    order = cardinality

    def rank(self):
        """
        Return the rank of ``self``.

        The rank of a complex reflection group is equal to the dimension
        of the complex vector space the group acts on.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 12)
            sage: C.rank()
            12
            sage: C = ColoredPermutations(7, 4)
            sage: C.rank()
            4
            sage: C = ColoredPermutations(1, 4)
            sage: C.rank()
            3
        """
        if self._m == 1:
            return self._n - 1
        return self._n

    def degrees(self):
        """
        Return the degrees of ``self``.

        The degrees of a complex reflection group are the degrees of
        the fundamental invariants of the ring of polynomial invariants.

        If `m = 1`, then we are in the special case of the symmetric group
        and the degrees are `(2, 3, \ldots, n, n+1)`. Otherwise the degrees
        are `(m, 2m, \ldots, nm)`.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.degrees()
            (4, 8, 12)
            sage: S = ColoredPermutations(1, 3)
            sage: S.degrees()
            (2, 3)

        We now check that the product of the degrees is equal to the
        cardinality of ``self``::

            sage: prod(C.degrees()) == C.cardinality()
            True
            sage: prod(S.degrees()) == S.cardinality()
            True
        """
        # For the usual symmetric group (self._m=1) we need to start at 2
        start = 2 if self._m == 1 else 1
        return tuple(self._m * i for i in range(start, self._n + 1))

    def codegrees(self):
        r"""
        Return the codegrees of ``self``.

        Let `G` be a complex reflection group. The codegrees
        `d_1^* \leq d_2^* \leq \cdots \leq d_{\ell}^*` of `G` can be
        defined by:

        .. MATH::

            \prod_{i=1}^{\ell} (q - d_i^* - 1)
            = \sum_{g \in G} \det(g) q^{\dim(V^g)},

        where `V` is the natural complex vector space that `G` acts on
        and `\ell` is the :meth:`rank`.

        If `m = 1`, then we are in the special case of the symmetric group
        and the codegrees are `(n-2, n-3, \ldots 1, 0)`. Otherwise the degrees
        are `((n-1)m, (n-2)m, \ldots, m, 0)`.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.codegrees()
            (8, 4, 0)
            sage: S = ColoredPermutations(1, 3)
            sage: S.codegrees()
            (1, 0)

        TESTS:

        We check the polynomial identity::

            sage: R.<q> = ZZ[]
            sage: C = ColoredPermutations(3, 2)
            sage: f = prod(q - ds - 1 for ds in C.codegrees())
            sage: d = lambda x: sum(1 for e in x.to_matrix().eigenvalues() if e == 1)
            sage: g = sum(det(x.to_matrix()) * q**d(x) for x in C)
            sage: f == g
            True
        """
        # Special case for the usual symmetric group
        last = self._n-1 if self._m == 1 else self._n
        return tuple(self._m * i for i in reversed(range(last)))

    def number_of_reflection_hyperplanes(self):
        """
        Return the number of reflection hyperplanes of ``self``.

        The number of reflection hyperplanes of a complex reflection
        group is equal to the sum of the codegrees plus the rank.

        EXAMPLES::

            sage: C = ColoredPermutations(1, 2)
            sage: C.number_of_reflection_hyperplanes()
            1
            sage: C = ColoredPermutations(1, 3)
            sage: C.number_of_reflection_hyperplanes()
            3
            sage: C = ColoredPermutations(4, 12)
            sage: C.number_of_reflection_hyperplanes()
            276
        """
        return sum(self.codegrees()) + self.rank()

    def fixed_point_polynomial(self, q=None):
        r"""
        The fixed point polynomial of ``self``.

        The fixed point polynomial `f_G` of a complex reflection group `G`
        is counting the dimensions of fixed points subspaces:

        .. MATH::

            f_G(q) = \sum_{w \in W} q^{\dim V^w}.

        Furthermore, let `d_1, d_2, \ldots, d_{\ell}` be the degrees of `G`,
        where `\ell` is the :meth:`rank`. Then the fixed point polynomial
        is given by

        .. MATH::

            f_G(q) = \prod_{i=1}^{\ell} (q + d_i - 1).

        INPUT:

        - ``q`` -- (default: the generator of ``ZZ['q']``) the parameter `q`

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.fixed_point_polynomial()
            q^3 + 21*q^2 + 131*q + 231

            sage: S = ColoredPermutations(1, 3)
            sage: S.fixed_point_polynomial()
            q^2 + 3*q + 2

        TESTS:

        We check the against the degrees and codegrees::

            sage: R.<q> = ZZ[]
            sage: C = ColoredPermutations(4, 3)
            sage: C.fixed_point_polynomial(q) == prod(q + d - 1 for d in C.degrees())
            True
        """
        if q is None:
            q = PolynomialRing(ZZ, 'q').gen(0)
        return prod(q + d - 1 for d in self.degrees())

    def is_well_generated(self):
        """
        Return if ``self`` is a well-generated complex reflection group.

        A complex reflection group `G` is well-generated if it is
        generated by `\ell` reflections. Equivalently, `G` is well-generated
        if `d_i + d_i^* = d_{\ell}` for all `1 \leq i \leq \ell`.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.is_well_generated()
            True
            sage: C = ColoredPermutations(2, 8)
            sage: C.is_well_generated()
            True
            sage: C = ColoredPermutations(1, 4)
            sage: C.is_well_generated()
            True
        """
        deg = self.degrees()
        dstar = self.codegrees()
        return all(deg[-1] == d + dstar[i] for i, d in enumerate(deg))

    Element = ColoredPermutation
    def padic_H_value(self, p, f, t, prec=None):
        """
        Return the `p`-adic trace of Frobenius, computed using the
        Gross-Koblitz formula.

        If left unspecified, `prec` is set to the minimum `p`-adic precision
        needed to recover the Euler factor.

        INPUT:

        - `p` -- a prime number

        - `f` -- an integer such that `q = p^f`

        - `t` -- a rational parameter

        - ``prec`` -- precision (optional)

        OUTPUT:

        an integer

        EXAMPLES:

        From Benasque report [Benasque2009]_, page 8::

            sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp
            sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4))
            sage: [H.padic_H_value(3,i,-1) for i in range(1,3)]
            [0, -12]
            sage: [H.padic_H_value(5,i,-1) for i in range(1,3)]
            [-4, 276]
            sage: [H.padic_H_value(7,i,-1) for i in range(1,3)]
            [0, -476]
            sage: [H.padic_H_value(11,i,-1) for i in range(1,3)]
            [0, -4972]

        From [Roberts2015]_ (but note conventions regarding `t`)::

            sage: H = Hyp(gamma_list=[-6,-1,4,3])
            sage: t = 189/125
            sage: H.padic_H_value(13,1,1/t)
            0

        Check issue from :trac:`28404`::

            sage: H1 = Hyp(cyclotomic=([1,1,1],[6,2]))
            sage: H2 = Hyp(cyclotomic=([6,2],[1,1,1]))
            sage: [H1.padic_H_value(5,1,i) for i in range(2,5)]
            [1, -4, -4]
            sage: [H2.padic_H_value(5,1,i) for i in range(2,5)]
            [-4, 1, -4]

        REFERENCES:

        - [MagmaHGM]_
        """
        alpha = self._alpha
        beta = self._beta
        t = QQ(t)
        if 0 in alpha:
            return self._swap.padic_H_value(p, f, ~t, prec)
        gamma = self.gamma_array()
        q = p**f

        # m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)}
        m = array.array('i', [0] * (q - 1))
        for b in beta:
            u = b * (q - 1)
            if u.is_integer():
                m[u] += 1
        M = self.M_value()
        D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta)
        # also: D = (self.weight() + 1 - m[0]) // 2

        if prec is None:
            prec = (self.weight() * f) // 2 + ceil(log(self.degree(), p)) + 1
        # For some reason, working in Qp instead of Zp is much faster;
        # it appears to avoid some costly conversions.
        p_ring = Qp(p, prec=prec)
        teich = p_ring.teichmuller(M / t)

        gauss_table = [None] * (q - 1)
        for r in range(q - 1):
            if gauss_table[r] is None:
                gauss_table[r] = padic_gauss_sum(r,
                                                 p,
                                                 f,
                                                 prec,
                                                 factored=True,
                                                 algorithm='sage',
                                                 parent=p_ring)
                r1 = (r * p) % (q - 1)
                while r1 != r:
                    gauss_table[r1] = gauss_table[r]
                    r1 = (r1 * p) % (q - 1)

        sigma = p_ring.zero()
        u1 = p_ring.one()
        for r in range(q - 1):
            i = int(0)
            u = u1
            u1 *= teich
            for v, gv in gamma.items():
                r1 = (v * r) % (q - 1)
                i += gauss_table[r1][0] * gv
                u *= gauss_table[r1][1]**gv
            sigma += (-p)**(i // (p - 1)) * u << (f * (D + m[0] - m[r]))
        resu = ZZ(-1)**m[0] / (1 - q) * sigma
        return IntegerModRing(p**prec)(resu).lift_centered()
Example #30
0
def _is_a_splitting(S1, S2, n, return_automorphism=False):
    """
    Check wether ``(S1,S2)`` is a splitting of `\ZZ/n\ZZ`.

    A splitting of `R = \ZZ/n\ZZ` is a pair of subsets of `R` which is a
    partition of `R \\backslash \{0\}` and such that there exists an element `r`
    of `R` such that `r S_1 = S_2` and `r S_2 = S_1` (where `r S` is the
    point-wise multiplication of the elements of `S` by `r`).

    Splittings are useful for computing idempotents in the quotient
    ring `Q = GF(q)[x]/(x^n-1)`.

    INPUT:

    - ``S1, S2`` -- disjoint sublists partitioning ``[1, 2, ..., n-1]``

    - ``n`` (integer)

    - ``return_automorphism`` (boolean) -- whether to return the automorphism
      exchanging `S_1` and `S_2`.

    OUTPUT:

    If ``return_automorphism is False`` (default) the function returns boolean values.

    Otherwise, it returns a pair ``(b, r)`` where ``b`` is a boolean indicating
    whether `S1`, `S2` is a splitting of `n`, and `r` is such that `r S_1 = S_2`
    and `r S_2 = S_1` (if `b` is ``False``, `r` is equal to ``None``).

    EXAMPLES::

        sage: from sage.coding.code_constructions import _is_a_splitting
        sage: _is_a_splitting([1,2],[3,4],5)
        True
        sage: _is_a_splitting([1,2],[3,4],5,return_automorphism=True)
        (True, 4)

        sage: _is_a_splitting([1,3],[2,4,5,6],7)
        False
        sage: _is_a_splitting([1,3,4],[2,5,6],7)
        False

        sage: for P in SetPartitions(6,[3,3]):
        ....:     res,aut= _is_a_splitting(P[0],P[1],7,return_automorphism=True)
        ....:     if res:
        ....:         print((aut, P[0], P[1]))
        (6, {1, 2, 3}, {4, 5, 6})
        (3, {1, 2, 4}, {3, 5, 6})
        (6, {1, 3, 5}, {2, 4, 6})
        (6, {1, 4, 5}, {2, 3, 6})

    We illustrate now how to find idempotents in quotient rings::

        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: F = GF(q)
        sage: P.<x> = PolynomialRing(F,"x")
        sage: I = Ideal(P,[x^n-1])
        sage: Q.<x> = QuotientRing(P,I)
        sage: i1 = -sum([x^i for i in S1]); i1
        2*x^9 + 2*x^5 + 2*x^4 + 2*x^3 + 2*x
        sage: i2 = -sum([x^i for i in S2]); i2
        2*x^10 + 2*x^8 + 2*x^7 + 2*x^6 + 2*x^2
        sage: i1^2 == i1
        True
        sage: i2^2 == i2
        True
        sage: (1-i1)^2 == 1-i1
        True
        sage: (1-i2)^2 == 1-i2
        True

    We return to dealing with polynomials (rather than elements of
    quotient rings), so we can construct cyclic codes::

        sage: P.<x> = PolynomialRing(F,"x")
        sage: i1 = -sum([x^i for i in S1])
        sage: i2 = -sum([x^i for i in S2])
        sage: i1_sqrd = (i1^2).quo_rem(x^n-1)[1]
        sage: i1_sqrd  == i1
        True
        sage: i2_sqrd = (i2^2).quo_rem(x^n-1)[1]
        sage: i2_sqrd  == i2
        True
        sage: C1 = codes.CyclicCode(length = n, generator_pol = gcd(i1, x^n - 1))
        sage: C2 = codes.CyclicCode(length = n, generator_pol = gcd(1-i2, x^n - 1))
        sage: C1.dual_code().systematic_generator_matrix() == C2.systematic_generator_matrix()
        True

    This is a special case of Theorem 6.4.3 in [HP2003]_.
    """
    R = IntegerModRing(n)
    S1 = set(R(x) for x in S1)
    S2 = set(R(x) for x in S2)

    # we first check whether (S1,S2) is a partition of R - {0}
    if (len(S1) + len(S2) != n-1 or len(S1) != len(S2) or
        R.zero() in S1 or R.zero() in S2 or not S1.isdisjoint(S2)):
        if return_automorphism:
            return False, None
        else:
            return False

    # now that we know that (S1,S2) is a partition, we look for an invertible
    # element b that maps S1 to S2 by multiplication
    for b in range(2,n):
        if GCD(b,n) == 1 and all(b*x in S2 for x in S1):
            if return_automorphism:
                return True, b
            else:
                return True
    if return_automorphism:
        return False, None
    else:
        return False
    def padic_H_value(self, p, f, t, prec=20):
        """
        Return the `p`-adic trace of Frobenius, computed using the
        Gross-Koblitz formula.

        INPUT:

        - `p` -- a prime number

        - `f` -- an integer such that `q = p^f`

        - `t` -- a rational parameter

        - ``prec`` -- precision (optional, default 20)

        OUTPUT:

        an integer

        EXAMPLES:

        From Benasque report [Benasque2009]_, page 8::

            sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp
            sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4))
            sage: [H.padic_H_value(3,i,-1) for i in range(1,3)]
            [0, -12]
            sage: [H.padic_H_value(5,i,-1) for i in range(1,3)]
            [-4, 276]
            sage: [H.padic_H_value(7,i,-1) for i in range(1,3)]
            [0, -476]
            sage: [H.padic_H_value(11,i,-1) for i in range(1,3)]
            [0, -4972]

        From [Roberts2015]_ (but note conventions regarding `t`)::

            sage: H = Hyp(gamma_list=[-6,-1,4,3])
            sage: t = 189/125
            sage: H.padic_H_value(13,1,1/t)
            0

        REFERENCES:

        - [MagmaHGM]_
        """
        alpha = self._alpha
        beta = self._beta
        if 0 in alpha:
            H = self.swap_alpha_beta()
            return (H.padic_H_value(p, f, ~t, prec))
        t = QQ(t)
        gamma = self.gamma_array()
        q = p**f

        m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)}
        M = self.M_value()
        D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta)
        # also: D = (self.weight() + 1 - m[0]) // 2

        gauss_table = [
            padic_gauss_sum(r, p, f, prec, factored=True) for r in range(q - 1)
        ]

        p_ring = Zp(p, prec=prec)
        teich = p_ring.teichmuller(M / t)
        sigma = sum(q**(D + m[0] - m[r]) *
                    (-p)**(sum(gauss_table[(v * r) % (q - 1)][0] * gv
                               for v, gv in gamma.items()) // (p - 1)) *
                    prod(gauss_table[(v * r) % (q - 1)][1]**gv
                         for v, gv in gamma.items()) * teich**r
                    for r in range(q - 1))
        resu = ZZ(-1)**m[0] / (1 - q) * sigma
        return IntegerModRing(p**prec)(resu).lift_centered()