Esempio n. 1
0
def padic_gauss_sum(a,
                    p,
                    f,
                    prec=20,
                    factored=False,
                    algorithm='pari',
                    parent=None):
    # Copied from Sage
    from sage.rings.padics.factory import Zp
    from sage.rings.all import PolynomialRing

    q = p**f
    a = a % (q - 1)
    if parent is None:
        R = Zp(p, prec)
    else:
        R = parent
    out = -R.one()
    if a != 0:
        t = R(1 / (q - 1))
        for i in range(f):
            out *= (a * t).gamma(algorithm)
            a = (a * p) % (q - 1)
    s = sum(a.digits(base=p))
    if factored:
        return (s, out)
    X = PolynomialRing(R, name='X').gen()
    pi = R.ext(X**(p - 1) + p, names='pi').gen()
    out *= pi**s
    return out
Esempio n. 2
0
    def integer_ring(self, print_mode=None):
        r"""
        Returns the integer ring of ``self``, possibly with
        ``print_mode`` changed.

        INPUT:

        - ``print_mode`` - a dictionary containing print options.
          Defaults to the same options as this ring.

        OUTPUT:

        - The ring of integral elements in ``self``.

        EXAMPLES::

            sage: K = Qp(5, print_mode='digits')
            sage: R = K.integer_ring(); repr(R(1/3))[3:]
            '31313131313131313132'
            sage: S = K.integer_ring({'max_ram_terms':4}); repr(S(1/3))[3:]
            '3132'
        """
        if not self.is_field() and print_mode is None:
            return self
        from sage.rings.padics.factory import Zp
        return Zp(self.prime(),
                  self.precision_cap(),
                  self._prec_type(),
                  print_mode=self._modified_print_mode(print_mode),
                  names=self._uniformizer_print())
Esempio n. 3
0
def logp_gam(p, p_prec):
    """
    Returns the (integral) power series log_p(1+z) / log_p(1+p)) where the denominator is computed with some accuracy.
    """
    L = logp(p, p_prec)
    ZZp = Zp(p, 2 * p_prec)
    loggam = ZZ(ZZp(1 + p).log(0))
    return ps_normalize(L / loggam, p, p_prec)
Esempio n. 4
0
def _torsion_poly(ell, P=None):
    """
    Computes the ell-th gauss period. If `P` is given, it must be a
    polynomial ring into which te result is coerced.

    This is my favourite equality:
    
    sage: all(_torsion_poly(n)(I) == I^n*lucas_number2(n,1,-1) for n in range(1,10))
    True
    """
    if P is None:
        P, R, = PolynomialRing(ZZ, 'x'), ZZ, 
    elif P.characteristic() == 0:
        R = ZZ
    else:
        R = Zp(P.characteristic(), prec=1, type='capped-rel')
    
    t = [1, 0]
    for k in range(1, ell/2 + 1):
        m = R(ell - 2*k + 2) * R(ell - 2*k + 1) / (R(ell - k) * R(k))
        t.append(-t[-2] * m)
        t.append(0)

    return P(list(reversed(t))).shift(ell % 2 - 1)
Esempio n. 5
0
def gauss_sum(a, p, f, prec=20, factored=False, algorithm='pari', parent=None):
    r"""
    Return the Gauss sum `g_q(a)` as a `p`-adic number.

    The Gauss sum `g_q(a)` is defined by

    .. MATH::

        g_q(a)= \sum_{u\in F_q^*} \omega(u)^{-a} \zeta_q^u,

    where `q = p^f`, `\omega` is the Teichmüller character and
    `\zeta_q` is some arbitrary choice of primitive `q`-th root of
    unity. The computation is adapted from the main theorem in Alain
    Robert's paper *The Gross-Koblitz formula revisited*,
    Rend. Sem. Mat. Univ. Padova 105 (2001), 157--170.

    Let `p` be a prime, `f` a positive integer, `q=p^f`, and `\pi` be
    the unique root of `f(x) = x^{p-1}+p` congruent to `\zeta_p - 1` modulo
    `(\zeta_p - 1)^2`. Let `0\leq a < q-1`. Then the
    Gross-Koblitz formula gives us the value of the Gauss sum `g_q(a)`
    as a product of `p`-adic Gamma functions as follows:

    .. MATH::

        g_q(a) = -\pi^s \prod_{0\leq i < f} \Gamma_p(a^{(i)}/(q-1)),

    where `s` is the sum of the digits of `a` in base `p` and the
    `a^{(i)}` have `p`-adic expansions obtained from cyclic
    permutations of that of `a`.

    INPUT:

    - ``a`` -- integer

    - ``p`` -- prime

    - ``f`` -- positive integer

    - ``prec`` -- positive integer (optional, 20 by default)

    - ``factored`` - boolean (optional, False by default)

    - ``algorithm`` - flag passed to p-adic Gamma function (optional, "pari" by default)

    OUTPUT:

    If ``factored`` is ``False``, returns a `p`-adic number in an Eisenstein extension of `\QQ_p`.
    This number has the form `pi^e * z` where `pi` is as above, `e` is some nonnegative
    integer, and `z` is an element of `\ZZ_p`; if ``factored`` is ``True``, the pair `(e,z)`
    is returned instead, and the Eisenstein extension is not formed.

    .. NOTE::

        This is based on GP code written by Adriana Salerno.

    EXAMPLES:

    In this example, we verify that `g_3(0) = -1`::

        sage: from sage.rings.padics.misc import gauss_sum
        sage: -gauss_sum(0,3,1)
        1 + O(pi^40)

    Next, we verify that `g_5(a) g_5(-a) = 5 (-1)^a`::

        sage: from sage.rings.padics.misc import gauss_sum
        sage: gauss_sum(2,5,1)^2-5
        O(pi^84)
        sage: gauss_sum(1,5,1)*gauss_sum(3,5,1)+5
        O(pi^84)

    Finally, we compute a non-trivial value::

        sage: from sage.rings.padics.misc import gauss_sum
        sage: gauss_sum(2,13,2)
        6*pi^2 + 7*pi^14 + 11*pi^26 + 3*pi^62 + 6*pi^74 + 3*pi^86 + 5*pi^98 +
        pi^110 + 7*pi^134 + 9*pi^146 + 4*pi^158 + 6*pi^170 + 4*pi^194 +
        pi^206 + 6*pi^218 + 9*pi^230 + O(pi^242)
        sage: gauss_sum(2,13,2,prec=5,factored=True)
        (2, 6 + 6*13 + 10*13^2 + O(13^5))

    .. SEEALSO::

        - :func:`sage.arith.misc.gauss_sum` for general finite fields
        - :meth:`sage.modular.dirichlet.DirichletCharacter.gauss_sum`
          for prime finite fields
        - :meth:`sage.modular.dirichlet.DirichletCharacter.gauss_sum_numerical`
          for prime finite fields
    """
    from sage.rings.padics.factory import Zp
    from sage.rings.all import PolynomialRing

    q = p**f
    a = a % (q - 1)
    if parent is None:
        R = Zp(p, prec)
    else:
        R = parent
    out = -R.one()
    if a != 0:
        t = R(1 / (q - 1))
        for i in range(f):
            out *= (a * t).gamma(algorithm)
            a = (a * p) % (q - 1)
    s = sum(a.digits(base=p))
    if factored:
        return s, out
    X = PolynomialRing(R, name='X').gen()
    pi = R.ext(X**(p - 1) + p, names='pi').gen()
    out *= pi**s
    return out
Esempio n. 6
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 = {}
Esempio n. 7
0
def gauss_sum(a, p, f, prec=20, factored=False, algorithm='pari', parent=None):
    r"""
    Return the Gauss sum `g_q(a)` as a `p`-adic number.

    The Gauss sum `g_q(a)` is defined by

    .. MATH::

        g_q(a)= \sum_{u\in F_q^*} \omega(u)^{-a} \zeta_q^u,

    where `q = p^f`, `\omega` is the Teichmüller character and
    `\zeta_q` is some arbitrary choice of primitive `q`-th root of
    unity. The computation is adapted from the main theorem in Alain
    Robert's paper *The Gross-Koblitz formula revisited*,
    Rend. Sem. Mat. Univ. Padova 105 (2001), 157--170.

    Let `p` be a prime, `f` a positive integer, `q=p^f`, and `\pi` be
    the unique root of `f(x) = x^{p-1}+p` congruent to `\zeta_p - 1` modulo
    `(\zeta_p - 1)^2`. Let `0\leq a < q-1`. Then the
    Gross-Koblitz formula gives us the value of the Gauss sum `g_q(a)`
    as a product of `p`-adic Gamma functions as follows:

    .. MATH::

        g_q(a) = -\pi^s \prod_{0\leq i < f} \Gamma_p(a^{(i)}/(q-1)),

    where `s` is the sum of the digits of `a` in base `p` and the
    `a^{(i)}` have `p`-adic expansions obtained from cyclic
    permutations of that of `a`.

    INPUT:

    - ``a`` -- integer

    - ``p`` -- prime

    - ``f`` -- positive integer

    - ``prec`` -- positive integer (optional, 20 by default)

    - ``factored`` - boolean (optional, False by default)

    - ``algorithm`` - flag passed to p-adic Gamma function (optional, "pari" by default)

    OUTPUT:

    If ``factored`` is ``False``, returns a `p`-adic number in an Eisenstein extension of `\QQ_p`.
    This number has the form `pi^e * z` where `pi` is as above, `e` is some nonnegative
    integer, and `z` is an element of `\ZZ_p`; if ``factored`` is ``True``, the pair `(e,z)`
    is returned instead, and the Eisenstein extension is not formed.

    .. NOTE::

        This is based on GP code written by Adriana Salerno.

    EXAMPLES:

    In this example, we verify that `g_3(0) = -1`::

        sage: from sage.rings.padics.misc import gauss_sum
        sage: -gauss_sum(0,3,1)
        1 + O(pi^40)

    Next, we verify that `g_5(a) g_5(-a) = 5 (-1)^a`::

        sage: from sage.rings.padics.misc import gauss_sum
        sage: gauss_sum(2,5,1)^2-5
        O(pi^84)
        sage: gauss_sum(1,5,1)*gauss_sum(3,5,1)+5
        O(pi^84)

    Finally, we compute a non-trivial value::

        sage: from sage.rings.padics.misc import gauss_sum
        sage: gauss_sum(2,13,2)
        6*pi^2 + 7*pi^14 + 11*pi^26 + 3*pi^62 + 6*pi^74 + 3*pi^86 + 5*pi^98 +
        pi^110 + 7*pi^134 + 9*pi^146 + 4*pi^158 + 6*pi^170 + 4*pi^194 +
        pi^206 + 6*pi^218 + 9*pi^230 + O(pi^242)
        sage: gauss_sum(2,13,2,prec=5,factored=True)
        (2, 6 + 6*13 + 10*13^2 + O(13^5))

    .. SEEALSO::

        - :func:`sage.arith.misc.gauss_sum` for general finite fields
        - :meth:`sage.modular.dirichlet.DirichletCharacter.gauss_sum`
          for prime finite fields
        - :meth:`sage.modular.dirichlet.DirichletCharacter.gauss_sum_numerical`
          for prime finite fields
    """
    from sage.rings.padics.factory import Zp
    from sage.rings.all import PolynomialRing

    q = p**f
    a = a % (q-1)
    if parent is None:
        R = Zp(p, prec)
    else:
        R = parent
    out = -R.one()
    if a != 0:
        t = R(1/(q-1))
        for i in range(f):
            out *= (a*t).gamma(algorithm)
            a = (a*p) % (q-1)
    s = sum(a.digits(base=p))
    if factored:
        return(s, out)
    X = PolynomialRing(R, name='X').gen()
    pi = R.ext(X**(p - 1) + p, names='pi').gen()
    out *= pi**s
    return out
    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()