Esempio n. 1
0
    def __init__(self,
                 conductor,
                 gammaV,
                 weight,
                 eps,
                 poles=None,
                 residues='automatic',
                 prec=53,
                 init=None):
        """
        Initialization of Dokchitser calculator EXAMPLES::

            sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
            sage: L.num_coeffs()
            4
        """
        self.conductor = conductor
        self.gammaV = gammaV
        self.weight = weight
        self.eps = eps
        self.poles = poles if poles is not None else []
        self.residues = residues
        self.prec = prec
        self.__CC = ComplexField(self.prec)
        self.__RR = self.__CC._real_field()
        self.__initialized = False
        if init is not None:
            self.init_coeffs(init)
Esempio n. 2
0
def zeta_symmetric(s):
    r"""
    Completed function `\xi(s)` that satisfies
    `\xi(s) = \xi(1-s)` and has zeros at the same points as the
    Riemann zeta function.

    INPUT:


    -  ``s`` - real or complex number


    If s is a real number the computation is done using the MPFR
    library. When the input is not real, the computation is done using
    the PARI C library.

    More precisely,

    .. math::

                xi(s) = \gamma(s/2 + 1) * (s-1) * \pi^{-s/2} * \zeta(s).



    EXAMPLES::

        sage: zeta_symmetric(0.7)
        0.497580414651127
        sage: zeta_symmetric(1-0.7)
        0.497580414651127
        sage: RR = RealField(200)
        sage: zeta_symmetric(RR(0.7))
        0.49758041465112690357779107525638385212657443284080589766062
        sage: C.<i> = ComplexField()
        sage: zeta_symmetric(0.5 + i*14.0)
        0.000201294444235258 + 1.49077798716757e-19*I
        sage: zeta_symmetric(0.5 + i*14.1)
        0.0000489893483255687 + 4.40457132572236e-20*I
        sage: zeta_symmetric(0.5 + i*14.2)
        -0.0000868931282620101 + 7.11507675693612e-20*I

    REFERENCE:

    - I copied the definition of xi from
      http://web.viu.ca/pughg/RiemannZeta/RiemannZetaLong.html
    """
    if not (is_ComplexNumber(s) or is_RealNumber(s)):
        s = ComplexField()(s)

    R = s.parent()
    if s == 1:  # deal with poles, hopefully
        return R(0.5)

    return (s / 2 + 1).gamma() * (s - 1) * (R.pi() ** (-s / 2)) * s.zeta()
Esempio n. 3
0
def zeta_symmetric(s):
    r"""
    Completed function `\xi(s)` that satisfies
    `\xi(s) = \xi(1-s)` and has zeros at the same points as the
    Riemann zeta function.

    INPUT:


    -  ``s`` - real or complex number


    If s is a real number the computation is done using the MPFR
    library. When the input is not real, the computation is done using
    the PARI C library.

    More precisely,

    .. MATH::

                xi(s) = \gamma(s/2 + 1) * (s-1) * \pi^{-s/2} * \zeta(s).



    EXAMPLES::

        sage: zeta_symmetric(0.7)
        0.497580414651127
        sage: zeta_symmetric(1-0.7)
        0.497580414651127
        sage: RR = RealField(200)
        sage: zeta_symmetric(RR(0.7))
        0.49758041465112690357779107525638385212657443284080589766062
        sage: C.<i> = ComplexField()
        sage: zeta_symmetric(0.5 + i*14.0)
        0.000201294444235258 + 1.49077798716757e-19*I
        sage: zeta_symmetric(0.5 + i*14.1)
        0.0000489893483255687 + 4.40457132572236e-20*I
        sage: zeta_symmetric(0.5 + i*14.2)
        -0.0000868931282620101 + 7.11507675693612e-20*I

    REFERENCE:

    - I copied the definition of xi from
      http://web.viu.ca/pughg/RiemannZeta/RiemannZetaLong.html
    """
    if not (is_ComplexNumber(s) or is_RealNumber(s)):
        s = ComplexField()(s)

    R = s.parent()
    if s == 1:  # deal with poles, hopefully
        return R(0.5)

    return (s / 2 + 1).gamma() * (s - 1) * (R.pi()**(-s / 2)) * s.zeta()
Esempio n. 4
0
    def _evalf_(self, x, y, parent=None, algorithm='mpmath'):
        """
        EXAMPLES::

            sage: gamma_inc_lower(3,2.)
            0.646647167633873
            sage: gamma_inc_lower(3,2).n(200)
            0.646647167633873081060005050275155...
            sage: gamma_inc_lower(0,2.)
            +infinity
        """
        R = parent or s_parent(x)
        # C is the complex version of R
        # prec is the precision of R
        if R is float:
            prec = 53
            C = complex
        else:
            try:
                prec = R.precision()
            except AttributeError:
                prec = 53
            try:
                C = R.complex_field()
            except AttributeError:
                C = R
        if algorithm == 'pari':
            try:
                v = ComplexField(prec)(x).gamma() - ComplexField(prec)(
                    x).gamma_inc(y)
            except AttributeError:
                if not (is_ComplexNumber(x)):
                    if is_ComplexNumber(y):
                        C = y.parent()
                    else:
                        C = ComplexField()
                        x = C(x)
            v = ComplexField(prec)(x).gamma() - ComplexField(prec)(
                x).gamma_inc(y)
        else:
            import mpmath
            v = ComplexField(prec)(mpmath_utils.call(mpmath.gammainc,
                                                     x,
                                                     0,
                                                     y,
                                                     parent=R))
        if v.is_real():
            return R(v)
        else:
            return C(v)
Esempio n. 5
0
def _do_sqrt(x, prec=None, extend=True, all=False):
    r"""
        Used internally to compute the square root of x.
        
        INPUT:
        
        -  ``x`` - a number
        
        -  ``prec`` - None (default) or a positive integer
           (bits of precision) If not None, then compute the square root
           numerically to prec bits of precision.
        
        -  ``extend`` - bool (default: True); this is a place
           holder, and is always ignored since in the symbolic ring everything
           has a square root.
        
        -  ``extend`` - bool (default: True); whether to extend
           the base ring to find roots. The extend parameter is ignored if
           prec is a positive integer.
        
        -  ``all`` - bool (default: False); whether to return
           a list of all the square roots of x.
        
        
        EXAMPLES::
        
            sage: from sage.functions.other import _do_sqrt
            sage: _do_sqrt(3)
            sqrt(3)
            sage: _do_sqrt(3,prec=10)
            1.7
            sage: _do_sqrt(3,prec=100)
            1.7320508075688772935274463415
            sage: _do_sqrt(3,all=True)
            [sqrt(3), -sqrt(3)]
        
        Note that the extend parameter is ignored in the symbolic ring::
        
            sage: _do_sqrt(3,extend=False)
            sqrt(3)
        """
    from sage.rings.all import RealField, ComplexField
    if prec:
        if x >= 0:
            return RealField(prec)(x).sqrt(all=all)
        else:
            return ComplexField(prec)(x).sqrt(all=all)
    if x == -1:
        from sage.symbolic.pynac import I
        z = I
    else:
        z = SR(x)**one_half

    if all:
        if z:
            return [z, -z]
        else:
            return [z]
    return z
    def map_to_complex_numbers(self, z, prec=None):
        """
        Evaluate ``self`` at a point `z \in X_0(N)` where `z` is given by
        a representative in the upper half plane, returning a point in
        the complex numbers.

        All computations are done with ``prec`` bits
        of precision.  If ``prec`` is not given, use the precision of `z`.
        Use self(z) to compute the image of z on the Weierstrass equation
        of the curve.

        EXAMPLES::

            sage: E = EllipticCurve('37a'); phi = E.modular_parametrization()
            sage: tau = (sqrt(7)*I - 17)/74
            sage: z = phi.map_to_complex_numbers(tau); z
            0.929592715285395 - 1.22569469099340*I
            sage: E.elliptic_exponential(z)
            (...e-16 - ...e-16*I : ...e-16 + ...e-16*I : 1.00000000000000)
            sage: phi(tau)
            (...e-16 - ...e-16*I : ...e-16 + ...e-16*I : 1.00000000000000)
        """
        if prec is None:
            try:
                prec = z.parent().prec()
            except AttributeError:
                prec = 53
        CC = ComplexField(prec)
        if z in QQ:
            raise NotImplementedError
        z = CC(z)
        if z.imag() <= 0:
            raise ValueError("Point must be in the upper half plane")
        # TODO: for very small imaginary part, maybe try to transform under
        # \Gamma_0(N) to a better representative?
        q = (2 * CC.gen() * CC.pi() * z).exp()
        #  nterms'th term is less than 2**-(prec+10) (c.f. eclib code)
        nterms = (-(prec + 10) / q.abs().log2()).ceil()
        # Use Horner's rule to sum the integral of the form
        enumerated_an = list(enumerate(self._E.anlist(nterms)))[1:]
        lattice_point = 0
        for n, an in reversed(enumerated_an):
            lattice_point += an / n
            lattice_point *= q
        return lattice_point
Esempio n. 7
0
    def _evalf_(self, x, parent_d=None):
        """
        EXAMPLES::

            sage: arg(0.0)
            0.000000000000000
            sage: arg(3.0)
            0.000000000000000
            sage: arg(3.00000000000000000000000000)
            0.00000000000000000000000000
            sage: arg(3.00000000000000000000000000).prec()
            90
            sage: arg(ComplexIntervalField(90)(3)).prec()
            90
            sage: arg(ComplexIntervalField(90)(3)).parent()
            Real Interval Field with 90 bits of precision
            sage: arg(3.0r)
            0.000000000000000
            sage: arg(RDF(3))
            0.0
            sage: arg(RDF(3)).parent()
            Real Double Field
            sage: arg(-2.5)
            3.14159265358979
            sage: arg(2.0+3*i)
            0.982793723247329
        """
        try:
            return x.arg()
        except AttributeError:
            pass
        # try to find a parent that support .arg()
        if parent_d is None:
            parent_d = parent(x)
        try:
            parent_d = parent_d.complex_field()
        except AttributeError:
            from sage.rings.complex_field import ComplexField
            try:
                parent_d = ComplexField(x.prec())
            except AttributeError:
                parent_d = ComplexField()

        return parent_d(x).arg()
Esempio n. 8
0
    def _evalf_(self, x, y, parent=None, algorithm='mpmath'):
        """
        EXAMPLES::

            sage: gamma_inc_lower(3,2.)
            0.646647167633873
            sage: gamma_inc_lower(3,2).n(200)
            0.646647167633873081060005050275155...
            sage: gamma_inc_lower(0,2.)
            +infinity
        """
        R = parent or s_parent(x)
        # C is the complex version of R
        # prec is the precision of R
        if R is float:
            prec = 53
            C = complex
        else:
            try:
                prec = R.precision()
            except AttributeError:
                prec = 53
            try:
                C = R.complex_field()
            except AttributeError:
                C = R
        if algorithm == 'pari':
            try:
                v = ComplexField(prec)(x).gamma() - ComplexField(prec)(x).gamma_inc(y)
            except AttributeError:
                if not (is_ComplexNumber(x)):
                    if is_ComplexNumber(y):
                        C = y.parent()
                    else:
                        C = ComplexField()
                        x = C(x)
            v = ComplexField(prec)(x).gamma() - ComplexField(prec)(x).gamma_inc(y)
        else:
            import mpmath
            v = ComplexField(prec)(mpmath_utils.call(mpmath.gammainc, x, 0, y, parent=R))
        if v.is_real():
            return R(v)
        else:
            return C(v)
Esempio n. 9
0
    def __init__(self, lfun, prec=None):
        """
        Initialization of the L-function from a PARI L-function.

        INPUT:

        - lfun -- a PARI :pari:`lfun` object or an instance of :class:`lfun_generic`
        - prec -- integer (default: 53) number of *bits* of precision

        EXAMPLES::

            sage: from sage.lfunctions.pari import lfun_generic, LFunction
            sage: lf = lfun_generic(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], v=pari('k->vector(k,n,1)'))
            sage: L = LFunction(lf)
            sage: L.num_coeffs()
            4
        """
        if isinstance(lfun, lfun_generic):
            # preparation using motivic data
            self._L = lfun.__pari__()
            if prec is None:
                prec = lfun.prec
        elif isinstance(lfun, Gen):
            # already some PARI lfun
            self._L = lfun
        else:
            # create a PARI lfunction from other input data
            self._L = pari.lfuncreate(lfun)

        self._conductor = ZZ(self._L[4])  # needs check
        self._weight = ZZ(self._L[3])  # needs check
        if prec is None:
            self.prec = 53
        else:
            self.prec = PyNumber_Index(prec)
        self._RR = RealField(self.prec)
        self._CC = ComplexField(self.prec)
        # Complex field used for inputs, which ensures exact 1-to-1
        # conversion to/from PARI. Since PARI objects have a precision
        # in machine words (not bits), this is typically higher. For
        # example, the default of 53 bits of precision would become 64.
        self._CCin = ComplexField(pari.bitprecision(self._RR(1)))
Esempio n. 10
0
    def _evalf_(self, x, y, parent=None):
        """
        EXAMPLES::

            sage: gamma_inc(0,2)
            -Ei(-2)
            sage: gamma_inc(0,2.)
            0.0489005107080611
            sage: gamma_inc(3,2).n()
            1.35335283236613
        """
        try:
            return x.gamma_inc(y)
        except AttributeError:
            if not (is_ComplexNumber(x)):
                if is_ComplexNumber(y):
                    C = y.parent()
                else:
                    C = ComplexField()
                    x = C(x)
            return x.gamma_inc(y)
Esempio n. 11
0
    def __init__(self, conductor, gammaV, weight, eps, \
                       poles=[], residues='automatic', prec=53,
                       init=None):
        """
        Initialization of Dokchitser calculator EXAMPLES::

            sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
            sage: L.num_coeffs()
            4
        """
        self.conductor = conductor
        self.gammaV = gammaV
        self.weight = weight
        self.eps = eps
        self.poles = poles
        self.residues = residues
        self.prec = prec
        self.__CC = ComplexField(self.prec)
        self.__RR = self.__CC._real_field()
        self.__initialized = False
        if init is not None:
            self.init_coeffs(init)
Esempio n. 12
0
    def _evalf_(self, x, y, parent=None, algorithm='pari'):
        """
        EXAMPLES::

            sage: gamma_inc(0,2)
            -Ei(-2)
            sage: gamma_inc(0,2.)
            0.0489005107080611
            sage: gamma_inc(0,2).n(algorithm='pari')
            0.0489005107080611
            sage: gamma_inc(0,2).n(200)
            0.048900510708061119567239835228...
            sage: gamma_inc(3,2).n()
            1.35335283236613

        TESTS:

        Check that :trac:`7099` is fixed::

            sage: R = RealField(1024)
            sage: gamma(R(9), R(10^-3))  # rel tol 1e-308
            40319.99999999999999999999999999988898884344822911869926361916294165058203634104838326009191542490601781777105678829520585311300510347676330951251563007679436243294653538925717144381702105700908686088851362675381239820118402497959018315224423868693918493033078310647199219674433536605771315869983788442389633
            sage: numerical_approx(gamma(9, 10^(-3)) - gamma(9), digits=40)  # abs tol 1e-36
            -1.110111598370794007949063502542063148294e-28

        Check that :trac:`17328` is fixed::

            sage: gamma_inc(float(-1), float(-1))
            (-0.8231640121031085+3.141592653589793j)
            sage: gamma_inc(RR(-1), RR(-1))
            -0.823164012103109 + 3.14159265358979*I
            sage: gamma_inc(-1, float(-log(3))) - gamma_inc(-1, float(-log(2)))  # abs tol 1e-15
            (1.2730972164471142+0j)

        Check that :trac:`17130` is fixed::

            sage: r = gamma_inc(float(0), float(1)); r
            0.21938393439552029
            sage: type(r)
            <... 'float'>
        """
        R = parent or s_parent(x)
        # C is the complex version of R
        # prec is the precision of R
        if R is float:
            prec = 53
            C = complex
        else:
            try:
                prec = R.precision()
            except AttributeError:
                prec = 53
            try:
                C = R.complex_field()
            except AttributeError:
                C = R

        if algorithm == 'pari':
            v = ComplexField(prec)(x).gamma_inc(y)
        else:
            import mpmath
            v = ComplexField(prec)(mpmath_utils.call(mpmath.gammainc, x, y, parent=R))
        if v.is_real():
            return R(v)
        else:
            return C(v)
Esempio n. 13
0
    def _evalf_(self, x, y, parent=None, algorithm='pari'):
        """
        EXAMPLES::

            sage: gamma_inc(0,2)
            -Ei(-2)
            sage: gamma_inc(0,2.)
            0.0489005107080611
            sage: gamma_inc(0,2).n(algorithm='pari')
            0.0489005107080611
            sage: gamma_inc(0,2).n(200)
            0.048900510708061119567239835228...
            sage: gamma_inc(3,2).n()
            1.35335283236613

        TESTS:

        Check that :trac:`7099` is fixed::

            sage: R = RealField(1024)
            sage: gamma(R(9), R(10^-3))  # rel tol 1e-308
            40319.99999999999999999999999999988898884344822911869926361916294165058203634104838326009191542490601781777105678829520585311300510347676330951251563007679436243294653538925717144381702105700908686088851362675381239820118402497959018315224423868693918493033078310647199219674433536605771315869983788442389633
            sage: numerical_approx(gamma(9, 10^(-3)) - gamma(9), digits=40)  # abs tol 1e-36
            -1.110111598370794007949063502542063148294e-28

        Check that :trac:`17328` is fixed::

            sage: gamma_inc(float(-1), float(-1))
            (-0.8231640121031085+3.141592653589793j)
            sage: gamma_inc(RR(-1), RR(-1))
            -0.823164012103109 + 3.14159265358979*I
            sage: gamma_inc(-1, float(-log(3))) - gamma_inc(-1, float(-log(2)))  # abs tol 1e-15
            (1.2730972164471142+0j)

        Check that :trac:`17130` is fixed::

            sage: r = gamma_inc(float(0), float(1)); r
            0.21938393439552029
            sage: type(r)
            <... 'float'>
        """
        R = parent or s_parent(x)
        # C is the complex version of R
        # prec is the precision of R
        if R is float:
            prec = 53
            C = complex
        else:
            try:
                prec = R.precision()
            except AttributeError:
                prec = 53
            try:
                C = R.complex_field()
            except AttributeError:
                C = R

        if algorithm == 'pari':
            v = ComplexField(prec)(x).gamma_inc(y)
        else:
            import mpmath
            v = ComplexField(prec)(mpmath_utils.call(mpmath.gammainc,
                                                     x,
                                                     y,
                                                     parent=R))
        if v.is_real():
            return R(v)
        else:
            return C(v)
Esempio n. 14
0
    def _coerce_map_from_(self, P):
        r"""
        Return whether ``P`` coerces into this symbolic subring.

        INPUT:

        - ``P`` -- a parent.

        OUTPUT:

        A boolean or ``None``.

        TESTS::

            sage: from sage.symbolic.subring import GenericSymbolicSubring
            sage: GenericSymbolicSubring(vars=tuple()).has_coerce_map_from(SR)  # indirect doctest  # not tested see #19231
            False

        ::
            sage: from sage.symbolic.subring import SymbolicSubring
            sage: C = SymbolicSubring(no_variables=True)
            sage: C.has_coerce_map_from(ZZ)  # indirect doctest
            True
            sage: C.has_coerce_map_from(QQ)  # indirect doctest
            True
            sage: C.has_coerce_map_from(RR)  # indirect doctest
            True
            sage: C.has_coerce_map_from(RIF)  # indirect doctest
            True
            sage: C.has_coerce_map_from(CC)  # indirect doctest
            True
            sage: C.has_coerce_map_from(CIF)  # indirect doctest
            True
            sage: C.has_coerce_map_from(AA)  # indirect doctest
            True
            sage: C.has_coerce_map_from(QQbar)  # indirect doctest
            True
            sage: C.has_coerce_map_from(SR)  # indirect doctest
            False
        """
        if P == SR:
            # Workaround; can be deleted once #19231 is fixed
            return False

        from sage.rings.real_mpfr import mpfr_prec_min
        from sage.rings.all import (ComplexField, RLF, CLF, AA, QQbar,
                                    InfinityRing)
        from sage.rings.real_mpfi import is_RealIntervalField
        from sage.rings.complex_interval_field import is_ComplexIntervalField

        if isinstance(P, type):
            return SR._coerce_map_from_(P)

        elif RLF.has_coerce_map_from(P) or \
             CLF.has_coerce_map_from(P) or \
             AA.has_coerce_map_from(P) or \
             QQbar.has_coerce_map_from(P):
            return True

        elif (P is InfinityRing or is_RealIntervalField(P)
              or is_ComplexIntervalField(P)):
            return True

        elif ComplexField(mpfr_prec_min()).has_coerce_map_from(P):
            return P not in (RLF, CLF, AA, QQbar)
Esempio n. 15
0
def hilbert_class_polynomial(D, algorithm=None):
    r"""
    Return the Hilbert class polynomial for discriminant `D`.

    INPUT:

    - ``D`` (int) -- a negative integer congruent to 0 or 1 modulo 4.

    - ``algorithm`` (string, default None).

    OUTPUT:

    (integer polynomial) The Hilbert class polynomial for the
    discriminant `D`.

    ALGORITHM:

    - If ``algorithm`` = "arb" (default): Use Arb's implementation which uses complex interval arithmetic.

    - If ``algorithm`` = "sage": Use complex approximations to the roots.

    - If ``algorithm`` = "magma": Call the appropriate Magma function (if available).

    AUTHORS:

    - Sage implementation originally by Eduardo Ocampo Alvarez and
      AndreyTimofeev

    - Sage implementation corrected by John Cremona (using corrected precision bounds from Andreas Enge)

    - Magma implementation by David Kohel

    EXAMPLES::

        sage: hilbert_class_polynomial(-4)
        x - 1728
        sage: hilbert_class_polynomial(-7)
        x + 3375
        sage: hilbert_class_polynomial(-23)
        x^3 + 3491750*x^2 - 5151296875*x + 12771880859375
        sage: hilbert_class_polynomial(-37*4)
        x^2 - 39660183801072000*x - 7898242515936467904000000
        sage: hilbert_class_polynomial(-37*4, algorithm="magma") # optional - magma
        x^2 - 39660183801072000*x - 7898242515936467904000000
        sage: hilbert_class_polynomial(-163)
        x + 262537412640768000
        sage: hilbert_class_polynomial(-163, algorithm="sage")
        x + 262537412640768000
        sage: hilbert_class_polynomial(-163, algorithm="magma") # optional - magma
        x + 262537412640768000

    TESTS::

        sage: all([hilbert_class_polynomial(d, algorithm="arb") == \
        ....:      hilbert_class_polynomial(d, algorithm="sage") \
        ....:        for d in range(-1,-100,-1) if d%4 in [0,1]])
        True

    """
    if algorithm is None:
        algorithm = "arb"

    D = Integer(D)
    if D >= 0:
        raise ValueError("D (=%s) must be negative" % D)
    if not (D % 4 in [0, 1]):
        raise ValueError("D (=%s) must be a discriminant" % D)

    if algorithm == "arb":
        import sage.libs.arb.arith
        return sage.libs.arb.arith.hilbert_class_polynomial(D)

    if algorithm == "magma":
        magma.eval("R<x> := PolynomialRing(IntegerRing())")
        f = str(magma.eval("HilbertClassPolynomial(%s)" % D))
        return IntegerRing()['x'](f)

    if algorithm != "sage":
        raise ValueError("%s is not a valid algorithm" % algorithm)

    from sage.quadratic_forms.binary_qf import BinaryQF_reduced_representatives
    from sage.rings.all import RR, ComplexField
    from sage.functions.all import elliptic_j

    # get all primitive reduced quadratic forms, (necessary to exclude
    # imprimitive forms when D is not a fundamental discriminant):

    rqf = BinaryQF_reduced_representatives(D, primitive_only=True)

    # compute needed precision
    #
    # NB: [https://arxiv.org/abs/0802.0979v1], quoting Enge (2006), is
    # incorrect.  Enge writes (2009-04-20 email to John Cremona) "The
    # source is my paper on class polynomials
    # [https://hal.inria.fr/inria-00001040] It was pointed out to me by
    # the referee after ANTS that the constant given there was
    # wrong. The final version contains a corrected constant on p.7
    # which is consistent with your example. It says:

    # "The logarithm of the absolute value of the coefficient in front
    # of X^j is bounded above by
    #
    # log (2*k_2) * h + pi * sqrt(|D|) * sum (1/A_i)
    #
    # independently of j", where k_2 \approx 10.163.

    h = len(rqf)  # class number
    c1 = 3.05682737291380  # log(2*10.63)
    c2 = sum([1 / RR(qf[0]) for qf in rqf], RR(0))
    prec = c2 * RR(3.142) * RR(D).abs().sqrt() + h * c1  # bound on log
    prec = prec * 1.45  # bound on log_2 (1/log(2) = 1.44..)
    prec = 10 + prec.ceil()  # allow for rounding error

    # set appropriate precision for further computing

    Dsqrt = D.sqrt(prec=prec)
    R = ComplexField(prec)['t']
    t = R.gen()
    pol = R(1)
    for qf in rqf:
        a, b, c = list(qf)
        tau = (b + Dsqrt) / (a << 1)
        pol *= (t - elliptic_j(tau))

    coeffs = [cof.real().round() for cof in pol.coefficients(sparse=False)]
    return IntegerRing()['x'](coeffs)
Esempio n. 16
0
File: cm.py Progetto: mcognetta/sage
def hilbert_class_polynomial(D, algorithm=None):
    r"""
    Returns the Hilbert class polynomial for discriminant `D`.

    INPUT:

    - ``D`` (int) -- a negative integer congruent to 0 or 1 modulo 4.

    - ``algorithm`` (string, default None).

    OUTPUT:

    (integer polynomial) The Hilbert class polynomial for the
    discriminant `D`.

    ALGORITHM:

    - If ``algorithm`` = "arb" (default): Use Arb's implementation which uses complex interval arithmetic.

    - If ``algorithm`` = "sage": Use complex approximations to the roots.

    - If ``algorithm`` = "magma": Call the appropriate Magma function (if available).

    AUTHORS:

    - Sage implementation originally by Eduardo Ocampo Alvarez and
      AndreyTimofeev

    - Sage implementation corrected by John Cremona (using corrected precision bounds from Andreas Enge)

    - Magma implementation by David Kohel

    EXAMPLES::

        sage: hilbert_class_polynomial(-4)
        x - 1728
        sage: hilbert_class_polynomial(-7)
        x + 3375
        sage: hilbert_class_polynomial(-23)
        x^3 + 3491750*x^2 - 5151296875*x + 12771880859375
        sage: hilbert_class_polynomial(-37*4)
        x^2 - 39660183801072000*x - 7898242515936467904000000
        sage: hilbert_class_polynomial(-37*4, algorithm="magma") # optional - magma
        x^2 - 39660183801072000*x - 7898242515936467904000000
        sage: hilbert_class_polynomial(-163)
        x + 262537412640768000
        sage: hilbert_class_polynomial(-163, algorithm="sage")
        x + 262537412640768000
        sage: hilbert_class_polynomial(-163, algorithm="magma") # optional - magma
        x + 262537412640768000

    TESTS::

        sage: all([hilbert_class_polynomial(d, algorithm="arb") == \
        ....:      hilbert_class_polynomial(d, algorithm="sage") \
        ....:        for d in range(-1,-100,-1) if d%4 in [0,1]])
        True

    """
    if algorithm is None:
        algorithm = "arb"

    D = Integer(D)
    if D >= 0:
        raise ValueError("D (=%s) must be negative"%D)
    if not (D%4 in [0,1]):
         raise ValueError("D (=%s) must be a discriminant"%D)

    if algorithm == "arb":
        import sage.libs.arb.arith
        return sage.libs.arb.arith.hilbert_class_polynomial(D)

    if algorithm == "magma":
        magma.eval("R<x> := PolynomialRing(IntegerRing())")
        f = str(magma.eval("HilbertClassPolynomial(%s)"%D))
        return IntegerRing()['x'](f)

    if algorithm != "sage":
        raise ValueError("%s is not a valid algorithm"%algorithm)

    from sage.quadratic_forms.binary_qf import BinaryQF_reduced_representatives
    from sage.rings.all import RR, ZZ, ComplexField
    from sage.functions.all import elliptic_j

    # get all primitive reduced quadratic forms, (necessary to exclude
    # imprimitive forms when D is not a fundamental discriminant):

    rqf = BinaryQF_reduced_representatives(D, primitive_only=True)

    # compute needed precision
    #
    # NB: [http://arxiv.org/abs/0802.0979v1], quoting Enge (2006), is
    # incorrect.  Enge writes (2009-04-20 email to John Cremona) "The
    # source is my paper on class polynomials
    # [http://hal.inria.fr/inria-00001040] It was pointed out to me by
    # the referee after ANTS that the constant given there was
    # wrong. The final version contains a corrected constant on p.7
    # which is consistent with your example. It says:

    # "The logarithm of the absolute value of the coefficient in front
    # of X^j is bounded above by
    #
    # log (2*k_2) * h + pi * sqrt(|D|) * sum (1/A_i)
    #
    # independently of j", where k_2 \approx 10.163.

    h = len(rqf) # class number
    c1 = 3.05682737291380 # log(2*10.63)
    c2 = sum([1/RR(qf[0]) for qf in rqf], RR(0))
    prec =  c2*RR(3.142)*RR(D).abs().sqrt() + h*c1  # bound on log
    prec = prec * 1.45   # bound on log_2 (1/log(2) = 1.44..)
    prec = 10 + prec.ceil()  # allow for rounding error

    # set appropriate precision for further computing

    Dsqrt = D.sqrt(prec=prec)
    R = ComplexField(prec)['t']
    t = R.gen()
    pol = R(1)
    for qf in rqf:
        a, b, c = list(qf)
        tau = (b+Dsqrt)/(a<<1)
        pol *=  (t - elliptic_j(tau))

    coeffs = [cof.real().round() for cof in pol.coefficients(sparse=False)]
    return IntegerRing()['x'](coeffs)
Esempio n. 17
0
class Dokchitser(SageObject):
    r"""
    Dokchitser's `L`-functions Calculator

    Create a Dokchitser `L`-series with

    Dokchitser(conductor, gammaV, weight, eps, poles, residues, init,
    prec)

    where

    - ``conductor`` - integer, the conductor

    - ``gammaV`` - list of Gamma-factor parameters, e.g. [0] for
      Riemann zeta, [0,1] for ell.curves, (see examples).

    - ``weight`` - positive real number, usually an integer e.g. 1 for
      Riemann zeta, 2 for `H^1` of curves/`\QQ`

    - ``eps`` - complex number; sign in functional equation

    - ``poles`` - (default: []) list of points where `L^*(s)` has
      (simple) poles; only poles with `Re(s)>weight/2` should be
      included

    - ``residues`` - vector of residues of `L^*(s)` in those poles or
      set residues='automatic' (default value)

    - ``prec`` - integer (default: 53) number of *bits* of precision

    RIEMANN ZETA FUNCTION:

    We compute with the Riemann Zeta function.

    ::

        sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
        sage: L
        Dokchitser L-series of conductor 1 and weight 1
        sage: L(1)
        Traceback (most recent call last):
        ...
        ArithmeticError
        sage: L(2)
        1.64493406684823
        sage: L(2, 1.1)
        1.64493406684823
        sage: L.derivative(2)
        -0.937548254315844
        sage: h = RR('0.0000000000001')
        sage: (zeta(2+h) - zeta(2.))/h
        -0.937028232783632
        sage: L.taylor_series(2, k=5)
        1.64493406684823 - 0.937548254315844*z + 0.994640117149451*z^2 - 1.00002430047384*z^3 + 1.00006193307...*z^4 + O(z^5)

    RANK 1 ELLIPTIC CURVE:

    We compute with the `L`-series of a rank `1`
    curve.

    ::

        sage: E = EllipticCurve('37a')
        sage: L = E.lseries().dokchitser(); L
        Dokchitser L-function associated to Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
        sage: L(1)
        0.000000000000000
        sage: L.derivative(1)
        0.305999773834052
        sage: L.derivative(1,2)
        0.373095594536324
        sage: L.num_coeffs()
        48
        sage: L.taylor_series(1,4)
        0.000000000000000 + 0.305999773834052*z + 0.186547797268162*z^2 - 0.136791463097188*z^3 + O(z^4)
        sage: L.check_functional_equation()
        6.11218974700000e-18                            # 32-bit
        6.04442711160669e-18                            # 64-bit

    RANK 2 ELLIPTIC CURVE:

    We compute the leading coefficient and Taylor expansion of the
    `L`-series of a rank `2` curve.

    ::

        sage: E = EllipticCurve('389a')
        sage: L = E.lseries().dokchitser()
        sage: L.num_coeffs ()
        156
        sage: L.derivative(1,E.rank())
        1.51863300057685
        sage: L.taylor_series(1,4)
        -1.27685190980159e-23 + (7.23588070754027e-24)*z + 0.759316500288427*z^2 - 0.430302337583362*z^3 + O(z^4)  # 32-bit
        -2.72911738151096e-23 + (1.54658247036311e-23)*z + 0.759316500288427*z^2 - 0.430302337583362*z^3 + O(z^4)  # 64-bit

    RAMANUJAN DELTA L-FUNCTION:

    The coefficients are given by Ramanujan's tau function::

        sage: L = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
        sage: pari_precode = 'tau(n)=(5*sigma(n,3)+7*sigma(n,5))*n/12 - 35*sum(k=1,n-1,(6*k-4*(n-k))*sigma(k,3)*sigma(n-k,5))'
        sage: L.init_coeffs('tau(k)', pari_precode=pari_precode)

    We redefine the default bound on the coefficients: Deligne's
    estimate on tau(n) is better than the default
    coefgrow(n)=`(4n)^{11/2}` (by a factor 1024), so
    re-defining coefgrow() improves efficiency (slightly faster).

    ::

        sage: L.num_coeffs()
        12
        sage: L.set_coeff_growth('2*n^(11/2)')
        sage: L.num_coeffs()
        11

    Now we're ready to evaluate, etc.

    ::

        sage: L(1)
        0.0374412812685155
        sage: L(1, 1.1)
        0.0374412812685155
        sage: L.taylor_series(1,3)
        0.0374412812685155 + 0.0709221123619322*z + 0.0380744761270520*z^2 + O(z^3)
    """
    def __init__(self, conductor, gammaV, weight, eps, \
                       poles=[], residues='automatic', prec=53,
                       init=None):
        """
        Initialization of Dokchitser calculator EXAMPLES::

            sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
            sage: L.num_coeffs()
            4
        """
        self.conductor = conductor
        self.gammaV = gammaV
        self.weight = weight
        self.eps    = eps
        self.poles  = poles
        self.residues = residues
        self.prec   = prec
        self.__CC   = ComplexField(self.prec)
        self.__RR   = self.__CC._real_field()
        if not init is None:
            self.init_coeffs(init)
            self.__init = init
        else:
            self.__init = False

    def __reduce__(self):
        D = copy.copy(self.__dict__)
        if '_Dokchitser__gp' in D:
            del D['_Dokchitser__gp']
        return reduce_load_dokchitser, (D, )

    def _repr_(self):
        z = "Dokchitser L-series of conductor %s and weight %s"%(
                   self.conductor, self.weight)
        return z

    def __del__(self):
        self.gp().quit()

    def gp(self):
        """
        Return the gp interpreter that is used to implement this Dokchitser
        L-function.

        EXAMPLES::

            sage: E = EllipticCurve('11a')
            sage: L = E.lseries().dokchitser()
            sage: L(2)
            0.546048036215014
            sage: L.gp()
            PARI/GP interpreter
        """
        try:
            return self.__gp
        except AttributeError:
            logfile = None
            # For debugging
            import os
            from sage.env import DOT_SAGE
            logfile = os.path.join(DOT_SAGE, 'dokchitser.log')
            g = sage.interfaces.gp.Gp(script_subdirectory='dokchitser', logfile=logfile)
            g.read('computel.gp')
            self.__gp = g
            self._gp_eval('default(realprecision, %s)'%(self.prec//3 + 2))
            self._gp_eval('conductor = %s'%self.conductor)
            self._gp_eval('gammaV = %s'%self.gammaV)
            self._gp_eval('weight = %s'%self.weight)
            self._gp_eval('sgn = %s'%self.eps)
            self._gp_eval('Lpoles = %s'%self.poles)
            self._gp_eval('Lresidues = %s'%self.residues)
            g._dokchitser = True
            return g

    def _gp_eval(self, s):
        try:
            t = self.gp().eval(s)
        except (RuntimeError, TypeError):
            raise RuntimeError("Unable to create L-series, due to precision or other limits in PARI.")
        if '***' in t:
            raise RuntimeError("Unable to create L-series, due to precision or other limits in PARI.")
        return t

    def __check_init(self):
        if not self.__init:
            raise ValueError("you must call init_coeffs on the L-function first")

    def num_coeffs(self, T=1):
        """
        Return number of coefficients `a_n` that are needed in
        order to perform most relevant `L`-function computations to
        the desired precision.

        EXAMPLES::

            sage: E = EllipticCurve('11a')
            sage: L = E.lseries().dokchitser()
            sage: L.num_coeffs()
            26
            sage: E = EllipticCurve('5077a')
            sage: L = E.lseries().dokchitser()
            sage: L.num_coeffs()
            568
            sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
            sage: L.num_coeffs()
            4
        """
        return Integer(self.gp().eval('cflength(%s)'%T))

    def init_coeffs(self, v, cutoff=1,
                             w=None,
                             pari_precode='',
                             max_imaginary_part=0,
                             max_asymp_coeffs=40):
        """
        Set the coefficients `a_n` of the `L`-series. If
        `L(s)` is not equal to its dual, pass the coefficients of
        the dual as the second optional argument.

        INPUT:


        -  ``v`` - list of complex numbers or string (pari
           function of k)

        -  ``cutoff`` - real number = 1 (default: 1)

        -  ``w`` - list of complex numbers or string (pari
           function of k)

        -  ``pari_precode`` - some code to execute in pari
           before calling initLdata

        -  ``max_imaginary_part`` - (default: 0): redefine if
           you want to compute L(s) for s having large imaginary part,

        -  ``max_asymp_coeffs`` - (default: 40): at most this
           many terms are generated in asymptotic series for phi(t) and
           G(s,t).


        EXAMPLES::

            sage: L = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
            sage: pari_precode = 'tau(n)=(5*sigma(n,3)+7*sigma(n,5))*n/12 - 35*sum(k=1,n-1,(6*k-4*(n-k))*sigma(k,3)*sigma(n-k,5))'
            sage: L.init_coeffs('tau(k)', pari_precode=pari_precode)

        Evaluate the resulting L-function at a point, and compare with the answer that
        one gets "by definition" (of L-function attached to a modular form)::

            sage: L(14)
            0.998583063162746
            sage: a = delta_qexp(1000)
            sage: sum(a[n]/float(n)^14 for n in range(1,1000))
            0.9985830631627459

        Illustrate that one can give a list of complex numbers for v
        (see :trac:`10937`)::

            sage: L2 = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
            sage: L2.init_coeffs(list(delta_qexp(1000))[1:])
            sage: L2(14)
            0.998583063162746

        TESTS:

        Verify that setting the `w` parameter does not raise an error
        (see :trac:`10937`).  Note that the meaning of `w` does not seem to
        be documented anywhere in Dokchitser's package yet, so there is
        no claim that the example below is meaningful! ::

            sage: L2 = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
            sage: L2.init_coeffs(list(delta_qexp(1000))[1:], w=[1..1000])
        """
        if isinstance(v, tuple) and w is None:
            v, cutoff, w, pari_precode, max_imaginary_part, max_asymp_coeffs = v

        self.__init = (v, cutoff, w, pari_precode, max_imaginary_part, max_asymp_coeffs)
        gp = self.gp()
        if pari_precode != '':
            self._gp_eval(pari_precode)
        RR = self.__CC._real_field()
        cutoff = RR(cutoff)
        if isinstance(v, str):
            if w is None:
                self._gp_eval('initLdata("%s", %s)'%(v, cutoff))
                return
            self._gp_eval('initLdata("%s",%s,"%s")'%(v,cutoff,w))
            return
        if not isinstance(v, (list, tuple)):
            raise TypeError("v (=%s) must be a list, tuple, or string"%v)
        CC = self.__CC
        v = ','.join([CC(a)._pari_init_() for a in v])
        self._gp_eval('Avec = [%s]'%v)
        if w is None:
            self._gp_eval('initLdata("Avec[k]", %s)'%cutoff)
            return
        w = ','.join([CC(a)._pari_init_() for a in w])
        self._gp_eval('Bvec = [%s]'%w)
        self._gp_eval('initLdata("Avec[k]",%s,"Bvec[k]")'%cutoff)

    def __to_CC(self, s):
        s = s.replace('.E','.0E').replace(' ','')
        return self.__CC(sage_eval(s, locals={'I':self.__CC.gen(0)}))

    def _clear_value_cache(self):
        del self.__values

    def __call__(self, s, c=None):
        r"""
        INPUT:

        -  ``s`` - complex number

        .. note::

           Evaluation of the function takes a long time, so each
           evaluation is cached. Call ``self._clear_value_cache()`` to
           clear the evaluation cache.

        EXAMPLES::

            sage: E = EllipticCurve('5077a')
            sage: L = E.lseries().dokchitser(100)
            sage: L(1)
            0.00000000000000000000000000000
            sage: L(1+I)
            -1.3085436607849493358323930438 + 0.81298000036784359634835412129*I
        """
        self.__check_init()
        s = self.__CC(s)
        try:
            return self.__values[s]
        except AttributeError:
            self.__values = {}
        except KeyError:
            pass
        z = self.gp().eval('L(%s)'%s)
        if 'pole' in z:
            print(z)
            raise ArithmeticError
        elif '***' in z:
            print(z)
            raise RuntimeError
        elif 'Warning' in z:
            i = z.rfind('\n')
            msg = z[:i].replace('digits','decimal digits')
            verbose(msg, level=-1)
            ans = self.__to_CC(z[i+1:])
            self.__values[s] = ans
            return ans
        ans = self.__to_CC(z)
        self.__values[s] = ans
        return ans

    def derivative(self, s, k=1):
        r"""
        Return the `k`-th derivative of the `L`-series at
        `s`.

        .. warning::

           If `k` is greater than the order of vanishing of
           `L` at `s` you may get nonsense.

        EXAMPLES::

            sage: E = EllipticCurve('389a')
            sage: L = E.lseries().dokchitser()
            sage: L.derivative(1,E.rank())
            1.51863300057685
        """
        self.__check_init()
        s = self.__CC(s)
        k = Integer(k)
        z = self.gp().eval('L(%s,,%s)'%(s,k))
        if 'pole' in z:
            raise ArithmeticError(z)
        elif 'Warning' in z:
            i = z.rfind('\n')
            msg = z[:i].replace('digits','decimal digits')
            verbose(msg, level=-1)
            return self.__CC(z[i:])
        return self.__CC(z)


    def taylor_series(self, a=0, k=6, var='z'):
        r"""
        Return the first `k` terms of the Taylor series expansion
        of the `L`-series about `a`.

        This is returned as a series in ``var``, where you
        should view ``var`` as equal to `s-a`. Thus
        this function returns the formal power series whose coefficients
        are `L^{(n)}(a)/n!`.

        INPUT:


        -  ``a`` - complex number (default: 0); point about
           which to expand

        -  ``k`` - integer (default: 6), series is
           `O(``var``^k)`

        -  ``var`` - string (default: 'z'), variable of power
           series


        EXAMPLES::

            sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
            sage: L.taylor_series(2, 3)
            1.64493406684823 - 0.937548254315844*z + 0.994640117149451*z^2 + O(z^3)
            sage: E = EllipticCurve('37a')
            sage: L = E.lseries().dokchitser()
            sage: L.taylor_series(1)
            0.000000000000000 + 0.305999773834052*z + 0.186547797268162*z^2 - 0.136791463097188*z^3 + 0.0161066468496401*z^4 + 0.0185955175398802*z^5 + O(z^6)

        We compute a Taylor series where each coefficient is to high
        precision.

        ::

            sage: E = EllipticCurve('389a')
            sage: L = E.lseries().dokchitser(200)
            sage: L.taylor_series(1,3)
            -9.094...e-82 + (5.1538...e-82)*z + 0.75931650028842677023019260789472201907809751649492435158581*z^2 + O(z^3)
        """
        self.__check_init()
        a = self.__CC(a)
        k = Integer(k)
        try:
            z = self.gp()('Vec(Lseries(%s,,%s))'%(a,k-1))
        except TypeError as msg:
            raise RuntimeError("%s\nUnable to compute Taylor expansion (try lowering the number of terms)"%msg)
        r = repr(z)
        if 'pole' in r:
            raise ArithmeticError(r)
        elif 'Warning' in r:
            i = r.rfind('\n')
            msg = r[:i].replace('digits','decimal digits')
            verbose(msg, level=-1)
        v = list(z)
        K = self.__CC
        v = [K(repr(x)) for x in v]
        R = self.__CC[[var]]
        return R(v,len(v))

    def check_functional_equation(self, T=1.2):
        r"""
        Verifies how well numerically the functional equation is satisfied,
        and also determines the residues if ``self.poles !=
        []`` and residues='automatic'.

        More specifically: for `T>1` (default 1.2),
        ``self.check_functional_equation(T)`` should ideally
        return 0 (to the current precision).


        -  if what this function returns does not look like 0 at all,
           probably the functional equation is wrong (i.e. some of the
           parameters gammaV, conductor etc., or the coefficients are wrong),

        -  if checkfeq(T) is to be used, more coefficients have to be
           generated (approximately T times more), e.g. call cflength(1.3),
           initLdata("a(k)",1.3), checkfeq(1.3)

        -  T=1 always (!) returns 0, so T has to be away from 1

        -  default value `T=1.2` seems to give a reasonable
           balance

        -  if you don't have to verify the functional equation or the
           L-values, call num_coeffs(1) and initLdata("a(k)",1), you need
           slightly less coefficients.


        EXAMPLES::

            sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
            sage: L.check_functional_equation()
            -1.35525271600000e-20                        # 32-bit
            -2.71050543121376e-20                        # 64-bit

        If we choose the sign in functional equation for the
        `\zeta` function incorrectly, the functional equation
        doesn't check out.

        ::

            sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=-11, poles=[1], residues=[-1], init='1')
            sage: L.check_functional_equation()
            -9.73967861488124
        """
        self.__check_init()
        z = self.gp().eval('checkfeq(%s)'%T).replace(' ','')
        return self.__CC(z)

    def set_coeff_growth(self, coefgrow):
        r"""
        You might have to redefine the coefficient growth function if the
        `a_n` of the `L`-series are not given by the
        following PARI function::

                        coefgrow(n) = if(length(Lpoles),
                                          1.5*n^(vecmax(real(Lpoles))-1),
                                          sqrt(4*n)^(weight-1));


        INPUT:


        -  ``coefgrow`` - string that evaluates to a PARI
           function of n that defines a coefgrow function.


        EXAMPLE::

            sage: L = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
            sage: pari_precode = 'tau(n)=(5*sigma(n,3)+7*sigma(n,5))*n/12 - 35*sum(k=1,n-1,(6*k-4*(n-k))*sigma(k,3)*sigma(n-k,5))'
            sage: L.init_coeffs('tau(k)', pari_precode=pari_precode)
            sage: L.set_coeff_growth('2*n^(11/2)')
            sage: L(1)
            0.0374412812685155
        """
        if not isinstance(coefgrow, str):
            raise TypeError("coefgrow must be a string")
        g = self.gp()
        g.eval('coefgrow(n) = %s'%(coefgrow.replace('\n',' ')))
Esempio n. 18
0
class Dokchitser(SageObject):
    r"""
    Dokchitser's `L`-functions Calculator

    Create a Dokchitser `L`-series with

    Dokchitser(conductor, gammaV, weight, eps, poles, residues, init,
    prec)

    where

    - ``conductor`` - integer, the conductor

    - ``gammaV`` - list of Gamma-factor parameters, e.g. [0] for
      Riemann zeta, [0,1] for ell.curves, (see examples).

    - ``weight`` - positive real number, usually an integer e.g. 1 for
      Riemann zeta, 2 for `H^1` of curves/`\QQ`

    - ``eps`` - complex number; sign in functional equation

    - ``poles`` - (default: []) list of points where `L^*(s)` has
      (simple) poles; only poles with `Re(s)>weight/2` should be
      included

    - ``residues`` - vector of residues of `L^*(s)` in those poles or
      set residues='automatic' (default value)

    - ``prec`` - integer (default: 53) number of *bits* of precision

    RIEMANN ZETA FUNCTION:

    We compute with the Riemann Zeta function.

    ::

        sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
        sage: L
        Dokchitser L-series of conductor 1 and weight 1
        sage: L(1)
        Traceback (most recent call last):
        ...
        ArithmeticError
        sage: L(2)
        1.64493406684823
        sage: L(2, 1.1)
        1.64493406684823
        sage: L.derivative(2)
        -0.937548254315844
        sage: h = RR('0.0000000000001')
        sage: (zeta(2+h) - zeta(2.))/h
        -0.937028232783632
        sage: L.taylor_series(2, k=5)
        1.64493406684823 - 0.937548254315844*z + 0.994640117149451*z^2 - 1.00002430047384*z^3 + 1.00006193307...*z^4 + O(z^5)

    RANK 1 ELLIPTIC CURVE:

    We compute with the `L`-series of a rank `1`
    curve.

    ::

        sage: E = EllipticCurve('37a')
        sage: L = E.lseries().dokchitser(); L
        Dokchitser L-function associated to Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
        sage: L(1)
        0.000000000000000
        sage: L.derivative(1)
        0.305999773834052
        sage: L.derivative(1,2)
        0.373095594536324
        sage: L.num_coeffs()
        48
        sage: L.taylor_series(1,4)
        0.000000000000000 + 0.305999773834052*z + 0.186547797268162*z^2 - 0.136791463097188*z^3 + O(z^4)
        sage: L.check_functional_equation()
        6.11218974700000e-18                            # 32-bit
        6.04442711160669e-18                            # 64-bit

    RANK 2 ELLIPTIC CURVE:

    We compute the leading coefficient and Taylor expansion of the
    `L`-series of a rank `2` curve.

    ::

        sage: E = EllipticCurve('389a')
        sage: L = E.lseries().dokchitser()
        sage: L.num_coeffs ()
        156
        sage: L.derivative(1,E.rank())
        1.51863300057685
        sage: L.taylor_series(1,4)
        -1.27685190980159e-23 + (7.23588070754027e-24)*z + 0.759316500288427*z^2 - 0.430302337583362*z^3 + O(z^4)  # 32-bit
        -2.72911738151096e-23 + (1.54658247036311e-23)*z + 0.759316500288427*z^2 - 0.430302337583362*z^3 + O(z^4)  # 64-bit

    RAMANUJAN DELTA L-FUNCTION:

    The coefficients are given by Ramanujan's tau function::

        sage: L = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
        sage: pari_precode = 'tau(n)=(5*sigma(n,3)+7*sigma(n,5))*n/12 - 35*sum(k=1,n-1,(6*k-4*(n-k))*sigma(k,3)*sigma(n-k,5))'
        sage: L.init_coeffs('tau(k)', pari_precode=pari_precode)

    We redefine the default bound on the coefficients: Deligne's
    estimate on tau(n) is better than the default
    coefgrow(n)=`(4n)^{11/2}` (by a factor 1024), so
    re-defining coefgrow() improves efficiency (slightly faster).

    ::

        sage: L.num_coeffs()
        12
        sage: L.set_coeff_growth('2*n^(11/2)')
        sage: L.num_coeffs()
        11

    Now we're ready to evaluate, etc.

    ::

        sage: L(1)
        0.0374412812685155
        sage: L(1, 1.1)
        0.0374412812685155
        sage: L.taylor_series(1,3)
        0.0374412812685155 + 0.0709221123619322*z + 0.0380744761270520*z^2 + O(z^3)
    """
    def __init__(self, conductor, gammaV, weight, eps, \
                       poles=[], residues='automatic', prec=53,
                       init=None):
        """
        Initialization of Dokchitser calculator EXAMPLES::

            sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
            sage: L.num_coeffs()
            4
        """
        self.conductor = conductor
        self.gammaV = gammaV
        self.weight = weight
        self.eps    = eps
        self.poles  = poles
        self.residues = residues
        self.prec   = prec
        self.__CC   = ComplexField(self.prec)
        self.__RR   = self.__CC._real_field()
        if not init is None:
            self.init_coeffs(init)
            self.__init = init
        else:
            self.__init = False

    def __reduce__(self):
        D = copy.copy(self.__dict__)
        if '_Dokchitser__gp' in D:
            del D['_Dokchitser__gp']
        return reduce_load_dokchitser, (D, )

    def _repr_(self):
        z = "Dokchitser L-series of conductor %s and weight %s"%(
                   self.conductor, self.weight)
        return z

    def __del__(self):
        self.gp().quit()

    def gp(self):
        """
        Return the gp interpreter that is used to implement this Dokchitser
        L-function.

        EXAMPLES::

            sage: E = EllipticCurve('11a')
            sage: L = E.lseries().dokchitser()
            sage: L(2)
            0.546048036215014
            sage: L.gp()
            PARI/GP interpreter
        """
        try:
            return self.__gp
        except AttributeError:
            logfile = None
            # For debugging
            import os
            from sage.env import DOT_SAGE
            logfile = os.path.join(DOT_SAGE, 'dokchitser.log')
            g = sage.interfaces.gp.Gp(script_subdirectory='dokchitser', logfile=logfile)
            g.read('computel.gp')
            self.__gp = g
            self._gp_eval('default(realprecision, %s)'%(self.prec//3 + 2))
            self._gp_eval('conductor = %s'%self.conductor)
            self._gp_eval('gammaV = %s'%self.gammaV)
            self._gp_eval('weight = %s'%self.weight)
            self._gp_eval('sgn = %s'%self.eps)
            self._gp_eval('Lpoles = %s'%self.poles)
            self._gp_eval('Lresidues = %s'%self.residues)
            g._dokchitser = True
            return g

    def _gp_eval(self, s):
        try:
            t = self.gp().eval(s)
        except (RuntimeError, TypeError):
            raise RuntimeError("Unable to create L-series, due to precision or other limits in PARI.")
        if '***' in t:
            raise RuntimeError("Unable to create L-series, due to precision or other limits in PARI.")
        return t

    def __check_init(self):
        if not self.__init:
            raise ValueError("you must call init_coeffs on the L-function first")

    def num_coeffs(self, T=1):
        """
        Return number of coefficients `a_n` that are needed in
        order to perform most relevant `L`-function computations to
        the desired precision.

        EXAMPLES::

            sage: E = EllipticCurve('11a')
            sage: L = E.lseries().dokchitser()
            sage: L.num_coeffs()
            26
            sage: E = EllipticCurve('5077a')
            sage: L = E.lseries().dokchitser()
            sage: L.num_coeffs()
            568
            sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
            sage: L.num_coeffs()
            4
        """
        return Integer(self.gp().eval('cflength(%s)'%T))

    def init_coeffs(self, v, cutoff=1,
                             w=None,
                             pari_precode='',
                             max_imaginary_part=0,
                             max_asymp_coeffs=40):
        """
        Set the coefficients `a_n` of the `L`-series. If
        `L(s)` is not equal to its dual, pass the coefficients of
        the dual as the second optional argument.

        INPUT:


        -  ``v`` - list of complex numbers or string (pari
           function of k)

        -  ``cutoff`` - real number = 1 (default: 1)

        -  ``w`` - list of complex numbers or string (pari
           function of k)

        -  ``pari_precode`` - some code to execute in pari
           before calling initLdata

        -  ``max_imaginary_part`` - (default: 0): redefine if
           you want to compute L(s) for s having large imaginary part,

        -  ``max_asymp_coeffs`` - (default: 40): at most this
           many terms are generated in asymptotic series for phi(t) and
           G(s,t).


        EXAMPLES::

            sage: L = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
            sage: pari_precode = 'tau(n)=(5*sigma(n,3)+7*sigma(n,5))*n/12 - 35*sum(k=1,n-1,(6*k-4*(n-k))*sigma(k,3)*sigma(n-k,5))'
            sage: L.init_coeffs('tau(k)', pari_precode=pari_precode)

        Evaluate the resulting L-function at a point, and compare with the answer that
        one gets "by definition" (of L-function attached to a modular form)::

            sage: L(14)
            0.998583063162746
            sage: a = delta_qexp(1000)
            sage: sum(a[n]/float(n)^14 for n in range(1,1000))
            0.9985830631627459

        Illustrate that one can give a list of complex numbers for v
        (see :trac:`10937`)::

            sage: L2 = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
            sage: L2.init_coeffs(list(delta_qexp(1000))[1:])
            sage: L2(14)
            0.998583063162746

        TESTS:

        Verify that setting the `w` parameter does not raise an error
        (see :trac:`10937`).  Note that the meaning of `w` does not seem to
        be documented anywhere in Dokchitser's package yet, so there is
        no claim that the example below is meaningful! ::

            sage: L2 = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
            sage: L2.init_coeffs(list(delta_qexp(1000))[1:], w=[1..1000])
        """
        if isinstance(v, tuple) and w is None:
            v, cutoff, w, pari_precode, max_imaginary_part, max_asymp_coeffs = v

        self.__init = (v, cutoff, w, pari_precode, max_imaginary_part, max_asymp_coeffs)
        gp = self.gp()
        if pari_precode != '':
            self._gp_eval(pari_precode)
        RR = self.__CC._real_field()
        cutoff = RR(cutoff)
        if isinstance(v, str):
            if w is None:
                self._gp_eval('initLdata("%s", %s)'%(v, cutoff))
                return
            self._gp_eval('initLdata("%s",%s,"%s")'%(v,cutoff,w))
            return
        if not isinstance(v, (list, tuple)):
            raise TypeError("v (=%s) must be a list, tuple, or string"%v)
        CC = self.__CC
        v = ','.join([CC(a)._pari_init_() for a in v])
        self._gp_eval('Avec = [%s]'%v)
        if w is None:
            self._gp_eval('initLdata("Avec[k]", %s)'%cutoff)
            return
        w = ','.join([CC(a)._pari_init_() for a in w])
        self._gp_eval('Bvec = [%s]'%w)
        self._gp_eval('initLdata("Avec[k]",%s,"Bvec[k]")'%cutoff)

    def __to_CC(self, s):
        s = s.replace('.E','.0E').replace(' ','')
        return self.__CC(sage_eval(s, locals={'I':self.__CC.gen(0)}))

    def _clear_value_cache(self):
        del self.__values

    def __call__(self, s, c=None):
        r"""
        INPUT:

        -  ``s`` - complex number

        .. note::

           Evaluation of the function takes a long time, so each
           evaluation is cached. Call ``self._clear_value_cache()`` to
           clear the evaluation cache.

        EXAMPLES::

            sage: E = EllipticCurve('5077a')
            sage: L = E.lseries().dokchitser(100)
            sage: L(1)
            0.00000000000000000000000000000
            sage: L(1+I)
            -1.3085436607849493358323930438 + 0.81298000036784359634835412129*I
        """
        self.__check_init()
        s = self.__CC(s)
        try:
            return self.__values[s]
        except AttributeError:
            self.__values = {}
        except KeyError:
            pass
        z = self.gp().eval('L(%s)'%s)
        if 'pole' in z:
            print(z)
            raise ArithmeticError
        elif '***' in z:
            print(z)
            raise RuntimeError
        elif 'Warning' in z:
            i = z.rfind('\n')
            msg = z[:i].replace('digits','decimal digits')
            verbose(msg, level=-1)
            ans = self.__to_CC(z[i+1:])
            self.__values[s] = ans
            return ans
        ans = self.__to_CC(z)
        self.__values[s] = ans
        return ans

    def derivative(self, s, k=1):
        r"""
        Return the `k`-th derivative of the `L`-series at
        `s`.

        .. warning::

           If `k` is greater than the order of vanishing of
           `L` at `s` you may get nonsense.

        EXAMPLES::

            sage: E = EllipticCurve('389a')
            sage: L = E.lseries().dokchitser()
            sage: L.derivative(1,E.rank())
            1.51863300057685
        """
        self.__check_init()
        s = self.__CC(s)
        k = Integer(k)
        z = self.gp().eval('L(%s,,%s)'%(s,k))
        if 'pole' in z:
            raise ArithmeticError(z)
        elif 'Warning' in z:
            i = z.rfind('\n')
            msg = z[:i].replace('digits','decimal digits')
            verbose(msg, level=-1)
            return self.__CC(z[i:])
        return self.__CC(z)


    def taylor_series(self, a=0, k=6, var='z'):
        r"""
        Return the first `k` terms of the Taylor series expansion
        of the `L`-series about `a`.

        This is returned as a series in ``var``, where you
        should view ``var`` as equal to `s-a`. Thus
        this function returns the formal power series whose coefficients
        are `L^{(n)}(a)/n!`.

        INPUT:


        -  ``a`` - complex number (default: 0); point about
           which to expand

        -  ``k`` - integer (default: 6), series is
           `O(``var``^k)`

        -  ``var`` - string (default: 'z'), variable of power
           series


        EXAMPLES::

            sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
            sage: L.taylor_series(2, 3)
            1.64493406684823 - 0.937548254315844*z + 0.994640117149451*z^2 + O(z^3)
            sage: E = EllipticCurve('37a')
            sage: L = E.lseries().dokchitser()
            sage: L.taylor_series(1)
            0.000000000000000 + 0.305999773834052*z + 0.186547797268162*z^2 - 0.136791463097188*z^3 + 0.0161066468496401*z^4 + 0.0185955175398802*z^5 + O(z^6)

        We compute a Taylor series where each coefficient is to high
        precision.

        ::

            sage: E = EllipticCurve('389a')
            sage: L = E.lseries().dokchitser(200)
            sage: L.taylor_series(1,3)
            -9.094...e-82 + (5.1538...e-82)*z + 0.75931650028842677023019260789472201907809751649492435158581*z^2 + O(z^3)
        """
        self.__check_init()
        a = self.__CC(a)
        k = Integer(k)
        try:
            z = self.gp()('Vec(Lseries(%s,,%s))'%(a,k-1))
        except TypeError as msg:
            raise RuntimeError("%s\nUnable to compute Taylor expansion (try lowering the number of terms)"%msg)
        r = repr(z)
        if 'pole' in r:
            raise ArithmeticError(r)
        elif 'Warning' in r:
            i = r.rfind('\n')
            msg = r[:i].replace('digits','decimal digits')
            verbose(msg, level=-1)
        v = list(z)
        K = self.__CC
        v = [K(repr(x)) for x in v]
        R = self.__CC[[var]]
        return R(v,len(v))

    def check_functional_equation(self, T=1.2):
        r"""
        Verifies how well numerically the functional equation is satisfied,
        and also determines the residues if ``self.poles !=
        []`` and residues='automatic'.

        More specifically: for `T>1` (default 1.2),
        ``self.check_functional_equation(T)`` should ideally
        return 0 (to the current precision).


        -  if what this function returns does not look like 0 at all,
           probably the functional equation is wrong (i.e. some of the
           parameters gammaV, conductor etc., or the coefficients are wrong),

        -  if checkfeq(T) is to be used, more coefficients have to be
           generated (approximately T times more), e.g. call cflength(1.3),
           initLdata("a(k)",1.3), checkfeq(1.3)

        -  T=1 always (!) returns 0, so T has to be away from 1

        -  default value `T=1.2` seems to give a reasonable
           balance

        -  if you don't have to verify the functional equation or the
           L-values, call num_coeffs(1) and initLdata("a(k)",1), you need
           slightly less coefficients.


        EXAMPLES::

            sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
            sage: L.check_functional_equation()
            -1.35525271600000e-20                        # 32-bit
            -2.71050543121376e-20                        # 64-bit

        If we choose the sign in functional equation for the
        `\zeta` function incorrectly, the functional equation
        doesn't check out.

        ::

            sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=-11, poles=[1], residues=[-1], init='1')
            sage: L.check_functional_equation()
            -9.73967861488124
        """
        self.__check_init()
        z = self.gp().eval('checkfeq(%s)'%T).replace(' ','')
        return self.__CC(z)

    def set_coeff_growth(self, coefgrow):
        r"""
        You might have to redefine the coefficient growth function if the
        `a_n` of the `L`-series are not given by the
        following PARI function::

                        coefgrow(n) = if(length(Lpoles),
                                          1.5*n^(vecmax(real(Lpoles))-1),
                                          sqrt(4*n)^(weight-1));


        INPUT:


        -  ``coefgrow`` - string that evaluates to a PARI
           function of n that defines a coefgrow function.


        EXAMPLES::

            sage: L = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
            sage: pari_precode = 'tau(n)=(5*sigma(n,3)+7*sigma(n,5))*n/12 - 35*sum(k=1,n-1,(6*k-4*(n-k))*sigma(k,3)*sigma(n-k,5))'
            sage: L.init_coeffs('tau(k)', pari_precode=pari_precode)
            sage: L.set_coeff_growth('2*n^(11/2)')
            sage: L(1)
            0.0374412812685155
        """
        if not isinstance(coefgrow, str):
            raise TypeError("coefgrow must be a string")
        g = self.gp()
        g.eval('coefgrow(n) = %s'%(coefgrow.replace('\n',' ')))
Esempio n. 19
0
"""
Complex Elliptic Curve L-series

"""

from sage.structure.sage_object import SageObject
from sage.rings.all import (RealField, RationalField, ComplexField)
from math import sqrt, exp, ceil
import sage.functions.transcendental as transcendental
R = RealField()
Q = RationalField()
C = ComplexField()
import sage.misc.all as misc


class Lseries_ell(SageObject):
    """
    An elliptic curve $L$-series.

    EXAMPLES:
    
    """
    def __init__(self, E):
        """
        Create an elliptic curve $L$-series.

        EXAMPLES:
            sage: EllipticCurve([1..5]).lseries()
            Complex L-series of the Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
        """
        self.__E = E
Esempio n. 20
0
class Dokchitser(SageObject):
    r"""
    Dokchitser's `L`-functions Calculator

    Create a Dokchitser `L`-series with

    Dokchitser(conductor, gammaV, weight, eps, poles, residues, init,
    prec)

    where

    - ``conductor`` -- integer, the conductor

    - ``gammaV`` -- list of Gamma-factor parameters, e.g. [0] for
      Riemann zeta, [0,1] for ell.curves, (see examples).

    - ``weight`` -- positive real number, usually an integer e.g. 1 for
      Riemann zeta, 2 for `H^1` of curves/`\QQ`

    - ``eps`` -- complex number; sign in functional equation

    - ``poles`` -- (default: []) list of points where `L^*(s)` has
      (simple) poles; only poles with `Re(s)>weight/2` should be
      included

    - ``residues`` -- vector of residues of `L^*(s)` in those poles or
      set residues='automatic' (default value)

    - ``prec`` -- integer (default: 53) number of *bits* of precision

    RIEMANN ZETA FUNCTION:

    We compute with the Riemann Zeta function. ::

        sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
        sage: L
        Dokchitser L-series of conductor 1 and weight 1
        sage: L(1)
        Traceback (most recent call last):
        ...
        ArithmeticError
        sage: L(2)
        1.64493406684823
        sage: L(2, 1.1)
        1.64493406684823
        sage: L.derivative(2)
        -0.937548254315844
        sage: h = RR('0.0000000000001')
        sage: (zeta(2+h) - zeta(2.))/h
        -0.937028232783632
        sage: L.taylor_series(2, k=5)
        1.64493406684823 - 0.937548254315844*z + 0.994640117149451*z^2 - 1.00002430047384*z^3 + 1.00006193307...*z^4 + O(z^5)

    RANK 1 ELLIPTIC CURVE:

    We compute with the `L`-series of a rank `1` curve. ::

        sage: E = EllipticCurve('37a')
        sage: L = E.lseries().dokchitser(algorithm='gp'); L
        Dokchitser L-function associated to Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
        sage: L(1)
        0.000000000000000
        sage: L.derivative(1)
        0.305999773834052
        sage: L.derivative(1,2)
        0.373095594536324
        sage: L.num_coeffs()
        48
        sage: L.taylor_series(1,4)
        0.000000000000000 + 0.305999773834052*z + 0.186547797268162*z^2 - 0.136791463097188*z^3 + O(z^4)
        sage: L.check_functional_equation()  # abs tol 1e-19
        6.04442711160669e-18

    RANK 2 ELLIPTIC CURVE:

    We compute the leading coefficient and Taylor expansion of the
    `L`-series of a rank `2` elliptic curve. ::

        sage: E = EllipticCurve('389a')
        sage: L = E.lseries().dokchitser(algorithm='gp')
        sage: L.num_coeffs()
        156
        sage: L.derivative(1,E.rank())
        1.51863300057685
        sage: L.taylor_series(1,4)
        -1.27685190980159e-23 + (7.23588070754027e-24)*z + 0.759316500288427*z^2 - 0.430302337583362*z^3 + O(z^4)  # 32-bit
        -2.72911738151096e-23 + (1.54658247036311e-23)*z + 0.759316500288427*z^2 - 0.430302337583362*z^3 + O(z^4)  # 64-bit

    NUMBER FIELD:

    We compute with the Dedekind zeta function of a number field. ::

        sage: x = var('x')
        sage: K = NumberField(x**4 - x**2 - 1,'a')
        sage: L = K.zeta_function(algorithm='gp')
        sage: L.conductor
        400
        sage: L.num_coeffs()
        264
        sage: L(2)
        1.10398438736918
        sage: L.taylor_series(2,3)
        1.10398438736918 - 0.215822638498759*z + 0.279836437522536*z^2 + O(z^3)

    RAMANUJAN DELTA L-FUNCTION:

    The coefficients are given by Ramanujan's tau function::

        sage: L = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
        sage: pari_precode = 'tau(n)=(5*sigma(n,3)+7*sigma(n,5))*n/12 - 35*sum(k=1,n-1,(6*k-4*(n-k))*sigma(k,3)*sigma(n-k,5))'
        sage: L.init_coeffs('tau(k)', pari_precode=pari_precode)

    We redefine the default bound on the coefficients: Deligne's
    estimate on tau(n) is better than the default
    coefgrow(n)=`(4n)^{11/2}` (by a factor 1024), so
    re-defining coefgrow() improves efficiency (slightly faster). ::

        sage: L.num_coeffs()
        12
        sage: L.set_coeff_growth('2*n^(11/2)')
        sage: L.num_coeffs()
        11

    Now we're ready to evaluate, etc. ::

        sage: L(1)
        0.0374412812685155
        sage: L(1, 1.1)
        0.0374412812685155
        sage: L.taylor_series(1,3)
        0.0374412812685155 + 0.0709221123619322*z + 0.0380744761270520*z^2 + O(z^3)
    """

    __gp = None
    __globals = set()
    # set of global variables defined in a run of the
    # computel.gp script that are replaced by indexed copies
    # in the computel.gp.template

    __globals_re = None
    __instance = 0  # Monotonically increasing unique instance ID
    __n_instances = 0  # Number of currently allocated instances
    __template_filename = os.path.join(SAGE_EXTCODE, 'pari', 'dokchitser',
                                       'computel.gp.template')
    __init = False

    def __new__(cls, *args, **kwargs):
        inst = super(Dokchitser, cls).__new__(cls, *args, **kwargs)
        inst.__instance = cls.__instance
        cls.__n_instances += 1
        cls.__instance += 1
        return inst

    def __init__(self,
                 conductor,
                 gammaV,
                 weight,
                 eps,
                 poles=None,
                 residues='automatic',
                 prec=53,
                 init=None):
        """
        Initialization of Dokchitser calculator EXAMPLES::

            sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
            sage: L.num_coeffs()
            4
        """
        self.conductor = conductor
        self.gammaV = gammaV
        self.weight = weight
        self.eps = eps
        self.poles = poles if poles is not None else []
        self.residues = residues
        self.prec = prec
        self.__CC = ComplexField(self.prec)
        self.__RR = self.__CC._real_field()
        self.__initialized = False
        if init is not None:
            self.init_coeffs(init)

    def __reduce__(self):
        D = copy.copy(self.__dict__)
        if '_Dokchitser__gp' in D:
            del D['_Dokchitser__gp']
        return reduce_load_dokchitser, (D, )

    def _repr_(self):
        return "Dokchitser L-series of conductor %s and weight %s" % (
            self.conductor, self.weight)

    def __del__(self):
        self._teardown_gp(self.__instance)

    def gp(self):
        """
        Return the gp interpreter that is used to implement this Dokchitser
        L-function.

        EXAMPLES::

            sage: E = EllipticCurve('11a')
            sage: L = E.lseries().dokchitser(algorithm='gp')
            sage: L(2)
            0.546048036215014
            sage: L.gp()
            PARI/GP interpreter
        """
        if self.__gp is None:
            self._instantiate_gp()
        elif self.__initialized:
            return self.__gp

        self.__initialized = True

        with open(self.__template_filename) as tf:
            template = string.Template(tf.read())
        tmp_script = os.path.join(SAGE_TMP, 'computel_%s.gp' % self.__instance)
        with open(tmp_script, 'w') as f:
            f.write(template.substitute(i=str(self.__instance)))

        try:
            self.__gp.read(tmp_script)
        finally:
            os.unlink(tmp_script)

        self._gp_eval('default(realprecision, %s)' % (self.prec // 3 + 2))
        self._gp_set_inst('conductor', self.conductor)
        self._gp_set_inst('gammaV', self.gammaV)
        self._gp_set_inst('weight', self.weight)
        self._gp_set_inst('sgn', self.eps)
        self._gp_set_inst('Lpoles', self.poles)
        self._gp_set_inst('Lresidues', self.residues)
        return self.__gp

    @classmethod
    def _instantiate_gp(cls):
        from sage.env import DOT_SAGE
        logfile = os.path.join(DOT_SAGE, 'dokchitser.log')
        cls.__gp = sage.interfaces.gp.Gp(script_subdirectory='dokchitser',
                                         logfile=logfile)
        # Read the script template and parse out all indexed global variables
        # (easy because they all end in "_$i" and there's nothing else in the
        # script that uses $)
        global_re = re.compile(r'([a-zA-Z0-9]+)_\$i')
        with open(cls.__template_filename) as f:
            for line in f:
                for m in global_re.finditer(line):
                    cls.__globals.add(m.group(1))

        cls.__globals_re = re.compile(
            '([^a-zA-Z0-9_]|^)(%s)([^a-zA-Z0-9_]|$)' % '|'.join(cls.__globals))
        return

    @classmethod
    def _teardown_gp(cls, instance=None):
        cls.__n_instances -= 1
        if cls.__n_instances == 0:
            cls.__gp.quit()
        elif instance is not None:
            # Clean up all global variables created by this instance
            for varname in cls.__globals:
                cls.__gp.eval('kill(%s_%s)' % (varname, instance))

    def _gp_call_inst(self, func, *args):
        """
        Call the specified PARI function in the GP interpreter, with the
        instance number of this `Dokchitser` instance automatically appended.

        For example, ``self._gp_call_inst('L', 1)`` is equivalent to
        ``self.gp().eval('L_N(1)')`` where ``N`` is ``self.__instance``.
        """

        cmd = '%s_%d(%s)' % (func, self.__instance, ','.join(
            str(a) for a in args))
        return self._gp_eval(cmd)

    def _gp_set_inst(self, varname, value):
        """
        Like ``_gp_call_inst`` but sets the variable given by ``varname`` to
        the given value, appending ``_N`` to the variable name.

        If ``varname`` is a function (e.g. ``'func(n)'``) then this sets
        ``func_N(n)``).
        """

        if '(' in varname:
            funcname, args = varname.split('(', 1)
            varname = '%s_%s(%s' % (funcname, self.__instance, args)
        else:
            varname = '%s_%s' % (varname, self.__instance)

        cmd = '%s = %s' % (varname, value)
        return self._gp_eval(cmd)

    def _gp_eval(self, s):
        try:
            t = self.gp().eval(s)
        except (RuntimeError, TypeError):
            raise RuntimeError(
                "Unable to create L-series, due to precision or other limits in PARI."
            )
        if not self.__init and '***' in t:
            # After init_coeffs is called, future calls to this method should
            # return the full output for further parsing
            raise RuntimeError(
                "Unable to create L-series, due to precision or other limits in PARI."
            )
        return t

    def __check_init(self):
        if not self.__init:
            raise ValueError(
                "you must call init_coeffs on the L-function first")

    def num_coeffs(self, T=1):
        """
        Return number of coefficients `a_n` that are needed in
        order to perform most relevant `L`-function computations to
        the desired precision.

        EXAMPLES::

            sage: E = EllipticCurve('11a')
            sage: L = E.lseries().dokchitser(algorithm='gp')
            sage: L.num_coeffs()
            26
            sage: E = EllipticCurve('5077a')
            sage: L = E.lseries().dokchitser(algorithm='gp')
            sage: L.num_coeffs()
            568
            sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
            sage: L.num_coeffs()
            4

        Verify that ``num_coeffs`` works with non-real spectral
        parameters, e.g. for the L-function of the level 10 Maass form
        with eigenvalue 2.7341055592527126::

            sage: ev = 2.7341055592527126
            sage: L = Dokchitser(conductor=10, gammaV=[ev*i, -ev*i],weight=2,eps=1)
            sage: L.num_coeffs()
            26
        """
        return Integer(self._gp_call_inst('cflength', T))

    def init_coeffs(self,
                    v,
                    cutoff=1,
                    w=None,
                    pari_precode='',
                    max_imaginary_part=0,
                    max_asymp_coeffs=40):
        """
        Set the coefficients `a_n` of the `L`-series.

        If `L(s)` is not equal to its dual, pass the coefficients of
        the dual as the second optional argument.

        INPUT:

        -  ``v`` -- list of complex numbers or string (pari function of k)

        -  ``cutoff`` -- real number = 1 (default: 1)

        -  ``w`` -- list of complex numbers or string (pari function of k)

        -  ``pari_precode`` -- some code to execute in pari
           before calling initLdata

        -  ``max_imaginary_part`` -- (default: 0): redefine if
           you want to compute L(s) for s having large imaginary part,

        -  ``max_asymp_coeffs`` -- (default: 40): at most this
           many terms are generated in asymptotic series for phi(t) and
           G(s,t).

        EXAMPLES::

            sage: L = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
            sage: pari_precode = 'tau(n)=(5*sigma(n,3)+7*sigma(n,5))*n/12 - 35*sum(k=1,n-1,(6*k-4*(n-k))*sigma(k,3)*sigma(n-k,5))'
            sage: L.init_coeffs('tau(k)', pari_precode=pari_precode)

        Evaluate the resulting L-function at a point, and compare with
        the answer that one gets "by definition" (of L-function
        attached to a modular form)::

            sage: L(14)
            0.998583063162746
            sage: a = delta_qexp(1000)
            sage: sum(a[n]/float(n)^14 for n in range(1,1000))
            0.9985830631627459

        Illustrate that one can give a list of complex numbers for v
        (see :trac:`10937`)::

            sage: L2 = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
            sage: L2.init_coeffs(list(delta_qexp(1000))[1:])
            sage: L2(14)
            0.998583063162746

        TESTS:

        Verify that setting the `w` parameter does not raise an error
        (see :trac:`10937`).  Note that the meaning of `w` does not seem to
        be documented anywhere in Dokchitser's package yet, so there is
        no claim that the example below is meaningful! ::

            sage: L2 = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
            sage: L2.init_coeffs(list(delta_qexp(1000))[1:], w=[1..1000])
        """
        if isinstance(v, tuple) and w is None:
            v, cutoff, w, pari_precode, max_imaginary_part, max_asymp_coeffs = v

        if pari_precode:
            # Must have __globals_re instantiated
            if self.__gp is None:
                self._instantiate_gp()

            def repl(m):
                return '%s%s_%d%s' % (m.group(1), m.group(2), self.__instance,
                                      m.group(3))

            # If any of the pre-code contains references to some of the
            # templated global variables we must replace those as well
            pari_precode = self.__globals_re.sub(repl, pari_precode)

        if pari_precode != '':
            self._gp_eval(pari_precode)
        RR = self.__CC._real_field()
        cutoff = RR(cutoff)
        if isinstance(v, str):
            if w is None:
                self._gp_call_inst('initLdata', '"%s"' % v, cutoff)
            else:
                self._gp_call_inst('initLdata', '"%s"' % v, cutoff, '"%s"' % w)
        elif not isinstance(v, (list, tuple)):
            raise TypeError("v (=%s) must be a list, tuple, or string" % v)
        else:
            CC = self.__CC
            v = ','.join([CC(a)._pari_init_() for a in v])
            self._gp_eval('Avec = [%s]' % v)
            if w is None:
                self._gp_call_inst('initLdata', '"Avec[k]"', cutoff)
            else:
                w = ','.join([CC(a)._pari_init_() for a in w])
                self._gp_eval('Bvec = [%s]' % w)
                self._gp_call_inst('initLdata', '"Avec[k]"', cutoff,
                                   '"Bvec[k]"')
        self.__init = (v, cutoff, w, pari_precode, max_imaginary_part,
                       max_asymp_coeffs)

    def __to_CC(self, s):
        s = s.replace('.E', '.0E').replace(' ', '')
        return self.__CC(sage_eval(s, locals={'I': self.__CC.gen(0)}))

    def _clear_value_cache(self):
        del self.__values

    def __call__(self, s, c=None):
        r"""
        INPUT:

        -  ``s`` -- complex number

        .. NOTE::

           Evaluation of the function takes a long time, so each
           evaluation is cached. Call ``self._clear_value_cache()`` to
           clear the evaluation cache.

        EXAMPLES::

            sage: E = EllipticCurve('5077a')
            sage: L = E.lseries().dokchitser(100, algorithm='gp')
            sage: L(1)
            0.00000000000000000000000000000
            sage: L(1+I)
            -1.3085436607849493358323930438 + 0.81298000036784359634835412129*I
        """
        self.__check_init()
        s = self.__CC(s)
        try:
            return self.__values[s]
        except AttributeError:
            self.__values = {}
        except KeyError:
            pass
        z = self._gp_call_inst('L', s)
        if 'pole' in z:
            print(z)
            raise ArithmeticError
        elif '***' in z:
            print(z)
            raise RuntimeError
        elif 'Warning' in z:
            i = z.rfind('\n')
            msg = z[:i].replace('digits', 'decimal digits')
            verbose(msg, level=-1)
            ans = self.__to_CC(z[i + 1:])
            self.__values[s] = ans
            return ans
        ans = self.__to_CC(z)
        self.__values[s] = ans
        return ans

    def derivative(self, s, k=1):
        r"""
        Return the `k`-th derivative of the `L`-series at `s`.

        .. WARNING::

           If `k` is greater than the order of vanishing of
           `L` at `s` you may get nonsense.

        EXAMPLES::

            sage: E = EllipticCurve('389a')
            sage: L = E.lseries().dokchitser(algorithm='gp')
            sage: L.derivative(1,E.rank())
            1.51863300057685
        """
        self.__check_init()
        s = self.__CC(s)
        k = Integer(k)
        z = self._gp_call_inst('L', s, '', k)
        if 'pole' in z:
            raise ArithmeticError(z)
        elif 'Warning' in z:
            i = z.rfind('\n')
            msg = z[:i].replace('digits', 'decimal digits')
            verbose(msg, level=-1)
            return self.__CC(z[i:])
        return self.__CC(z)

    def taylor_series(self, a=0, k=6, var='z'):
        r"""
        Return the first `k` terms of the Taylor series expansion
        of the `L`-series about `a`.

        This is returned as a series in ``var``, where you
        should view ``var`` as equal to `s-a`. Thus
        this function returns the formal power series whose coefficients
        are `L^{(n)}(a)/n!`.

        INPUT:

        -  ``a`` -- complex number (default: 0); point about
           which to expand

        -  ``k`` -- integer (default: 6), series is
           `O(``var``^k)`

        -  ``var`` -- string (default: 'z'), variable of power
           series

        EXAMPLES::

            sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
            sage: L.taylor_series(2, 3)
            1.64493406684823 - 0.937548254315844*z + 0.994640117149451*z^2 + O(z^3)
            sage: E = EllipticCurve('37a')
            sage: L = E.lseries().dokchitser(algorithm='gp')
            sage: L.taylor_series(1)
            0.000000000000000 + 0.305999773834052*z + 0.186547797268162*z^2 - 0.136791463097188*z^3 + 0.0161066468496401*z^4 + 0.0185955175398802*z^5 + O(z^6)

        We compute a Taylor series where each coefficient is to high
        precision. ::

            sage: E = EllipticCurve('389a')
            sage: L = E.lseries().dokchitser(200, algorithm='gp')
            sage: L.taylor_series(1,3)
            ...e-82 + (...e-82)*z + 0.75931650028842677023019260789472201907809751649492435158581*z^2 + O(z^3)

        Check that :trac:`25402` is fixed::

            sage: L = EllipticCurve("24a1").modular_form().lseries()
            sage: L.taylor_series(-1, 3)
            0.000000000000000 - 0.702565506265199*z + 0.638929001045535*z^2 + O(z^3)

        Check that :trac:`25965` is fixed::

            sage: L2 = EllipticCurve("37a1").modular_form().lseries(); L2
            L-series associated to the cusp form q - 2*q^2 - 3*q^3 + 2*q^4 - 2*q^5 + O(q^6)
            sage: L2.taylor_series(0,4)
            0.000000000000000 - 0.357620466127498*z + 0.273373112603865*z^2 + 0.303362857047671*z^3 + O(z^4)
            sage: L2.taylor_series(0,1)
            O(z^1)
            sage: L2(0)
            0.000000000000000
        """
        self.__check_init()
        a = self.__CC(a)
        k = Integer(k)
        try:
            z = self._gp_call_inst('Lseries', a, '', k - 1)
            z = self.gp()('Vecrev(Pol(%s))' % z)
        except TypeError as msg:
            raise RuntimeError(
                "%s\nUnable to compute Taylor expansion (try lowering the number of terms)"
                % msg)
        r = repr(z)
        if 'pole' in r:
            raise ArithmeticError(r)
        elif 'Warning' in r:
            i = r.rfind('\n')
            msg = r[:i].replace('digits', 'decimal digits')
            verbose(msg, level=-1)
        v = list(z)
        K = self.__CC
        v = [K(repr(x)) for x in v]
        R = self.__CC[[var]]
        return R(v, k)

    def check_functional_equation(self, T=1.2):
        r"""
        Verifies how well numerically the functional equation is satisfied,
        and also determines the residues if ``self.poles !=
        []`` and residues='automatic'.

        More specifically: for `T>1` (default 1.2),
        ``self.check_functional_equation(T)`` should ideally
        return 0 (to the current precision).

        -  if what this function returns does not look like 0 at all,
           probably the functional equation is wrong (i.e. some of the
           parameters gammaV, conductor etc., or the coefficients are wrong),

        -  if checkfeq(T) is to be used, more coefficients have to be
           generated (approximately T times more), e.g. call cflength(1.3),
           initLdata("a(k)",1.3), checkfeq(1.3)

        -  T=1 always (!) returns 0, so T has to be away from 1

        -  default value `T=1.2` seems to give a reasonable
           balance

        -  if you don't have to verify the functional equation or the
           L-values, call num_coeffs(1) and initLdata("a(k)",1), you need
           slightly less coefficients.

        EXAMPLES::

            sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
            sage: L.check_functional_equation()  # abs tol 1e-19
            -2.71050543121376e-20

        If we choose the sign in functional equation for the
        `\zeta` function incorrectly, the functional equation
        doesn't check out. ::

            sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=-11, poles=[1], residues=[-1], init='1')
            sage: L.check_functional_equation()
            -9.73967861488124
        """
        self.__check_init()
        z = self._gp_call_inst('checkfeq', T)
        z = z.replace(' ', '')
        return self.__CC(z)

    def set_coeff_growth(self, coefgrow):
        r"""
        You might have to redefine the coefficient growth function if the
        `a_n` of the `L`-series are not given by the
        following PARI function::

                        coefgrow(n) = if(length(Lpoles),
                                          1.5*n^(vecmax(real(Lpoles))-1),
                                          sqrt(4*n)^(weight-1));


        INPUT:

        -  ``coefgrow`` -- string that evaluates to a PARI
           function of n that defines a coefgrow function.

        EXAMPLES::

            sage: L = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
            sage: pari_precode = 'tau(n)=(5*sigma(n,3)+7*sigma(n,5))*n/12 - 35*sum(k=1,n-1,(6*k-4*(n-k))*sigma(k,3)*sigma(n-k,5))'
            sage: L.init_coeffs('tau(k)', pari_precode=pari_precode)
            sage: L.set_coeff_growth('2*n^(11/2)')
            sage: L(1)
            0.0374412812685155
        """
        if not isinstance(coefgrow, str):
            raise TypeError("coefgrow must be a string")

        self._gp_set_inst('coefgrow(n)', coefgrow.replace('\n', ' '))