Пример #1
0
    def __init__(self, E, A, prec=53):
        r"""
        Class for the Gross-Zagier L-series.

        This is attached to a pair `(E,A)` where `E` is an elliptic curve over
        `\QQ` and `A` is an ideal class in an imaginary quadratic number field.

        For the exact definition, in the more general setting of modular forms
        instead of elliptic curves, see section IV of [GrossZagier]_.

        INPUT:

        - ``E`` -- an elliptic curve over `\QQ`

        - ``A`` -- an ideal class in an imaginary quadratic number field

        - ``prec`` -- an integer (default 53) giving the required precision

        EXAMPLES::

            sage: e = EllipticCurve('37a')
            sage: K.<a> = QuadraticField(-40)
            sage: A = K.class_group().gen(0)
            sage: from sage.modular.modform.l_series_gross_zagier import GrossZagierLseries
            sage: G = GrossZagierLseries(e, A)

        TESTS::

            sage: K.<b> = QuadraticField(131)
            sage: A = K.class_group().one()
            sage: G = GrossZagierLseries(e, A)
            Traceback (most recent call last):
            ...
            ValueError: A is not an ideal class in an imaginary quadratic field
        """
        self._E = E
        self._N = N = E.conductor()
        self._A = A
        ideal = A.ideal()
        K = A.gens()[0].parent()
        D = K.disc()
        if not (K.degree() == 2 and D < 0):
            raise ValueError("A is not an ideal class in an"
                             " imaginary quadratic field")
        Q = ideal.quadratic_form().reduced_form()
        epsilon = -kronecker_character(D)(N)
        self._dokchister = Dokchitser(N**2 * D**2, [0, 0, 1, 1],
                                      weight=2,
                                      eps=epsilon,
                                      prec=prec)
        self._nterms = nterms = Integer(self._dokchister.gp()('cflength()'))
        if nterms > 1e6:
            # just takes way to long
            raise ValueError("Too many terms: {}".format(nterms))
        zeta_ord = ideal.number_field().zeta_order()
        an_list = gross_zagier_L_series(E.anlist(nterms + 1), Q, N, zeta_ord)
        self._dokchister.gp().set('a', an_list[1:])
        self._dokchister.init_coeffs('a[k]', 1)
Пример #2
0
    def __init__(self, E, A, prec=53):
        r"""
        Class for the Gross-Zagier L-series.

        This is attached to a pair `(E,A)` where `E` is an elliptic curve over
        `\QQ` and `A` is an ideal class in an imaginary quadratic number field.

        For the exact definition, in the more general setting of modular forms
        instead of elliptic curves, see section IV of [GrossZagier]_.

        INPUT:

        - ``E`` -- an elliptic curve over `\QQ`

        - ``A`` -- an ideal class in an imaginary quadratic number field

        - ``prec`` -- an integer (default 53) giving the required precision

        EXAMPLES::

            sage: e = EllipticCurve('37a')
            sage: K.<a> = QuadraticField(-40)
            sage: A = K.class_group().gen(0)
            sage: from sage.modular.modform.l_series_gross_zagier import GrossZagierLseries
            sage: G = GrossZagierLseries(e, A)

        TESTS::

            sage: K.<b> = QuadraticField(131)
            sage: A = K.class_group().one()
            sage: G = GrossZagierLseries(e, A)
            Traceback (most recent call last):
            ...
            ValueError: A is not an ideal class in an imaginary quadratic field
        """
        self._E = E
        self._N = N = E.conductor()
        self._A = A
        ideal = A.ideal()
        K = A.gens()[0].parent()
        D = K.disc()
        if not(K.degree() == 2 and D < 0):
            raise ValueError("A is not an ideal class in an"
                             " imaginary quadratic field")
        Q = ideal.quadratic_form().reduced_form()
        epsilon = - kronecker_character(D)(N)
        self._dokchister = Dokchitser(N ** 2 * D ** 2,
                                      [0, 0, 1, 1],
                                      weight=2, eps=epsilon, prec=prec)
        self._nterms = nterms = Integer(self._dokchister.num_coeffs())
        if nterms > 1e6:
            # just takes way to long
            raise ValueError("Too many terms: {}".format(nterms))
        zeta_ord = ideal.number_field().zeta_order()
        an_list = gross_zagier_L_series(E.anlist(nterms + 1), Q, N, zeta_ord)
        self._dokchister.gp().set('a', an_list[1:])
        self._dokchister.init_coeffs('a[k]', 1)
Пример #3
0
 def dokchitser(self, prec):
     # NOTE: In order to get the Dokchitser parameters of an L-function,
     # it is useful to know that
     #
     #         gamma(s) = 2^s*gamma(s/2)*gamma((s+1)/2) / (2*sqrt(pi))
     #
     conductor = self.level()**10
     gammaV = [-1,-1,-1,0,0,0,0,1]
     weight = 4
     eps = self.epsilon()
     poles = []
     residues = []
     
     from sage.lfunctions.dokchitser import Dokchitser
     L = Dokchitser(conductor = conductor,
                    gammaV = gammaV,
                    weight = weight,
                    eps = eps,
                    poles = poles, residues=[])
     #s = 'v=%s; a(k)=if(k>%s,0,v[k])'%(self.dirichlet_series_coeffs(prec), prec)
     s = 'v=%s; a(k)=v[k]'%(self.dirichlet_series_coeffs(prec))
     L.init_coeffs('a(k)', pari_precode=s)
     return L
Пример #4
0
    def dokchitser(self, prec):
        # NOTE: In order to get the Dokchitser parameters of an L-function,
        # it is useful to know that
        #
        #         gamma(s) = 2^s*gamma(s/2)*gamma((s+1)/2) / (2*sqrt(pi))
        #
        conductor = self.level()**10
        gammaV = [-1, -1, -1, 0, 0, 0, 0, 1]
        weight = 4
        eps = self.epsilon()
        poles = []
        residues = []

        from sage.lfunctions.dokchitser import Dokchitser
        L = Dokchitser(conductor=conductor,
                       gammaV=gammaV,
                       weight=weight,
                       eps=eps,
                       poles=poles,
                       residues=[])
        #s = 'v=%s; a(k)=if(k>%s,0,v[k])'%(self.dirichlet_series_coeffs(prec), prec)
        s = 'v=%s; a(k)=v[k]' % (self.dirichlet_series_coeffs(prec))
        L.init_coeffs('a(k)', pari_precode=s)
        return L
Пример #5
0
class GrossZagierLseries(SageObject):

    def __init__(self, E, A, prec=53):
        r"""
        Class for the Gross-Zagier L-series.

        This is attached to a pair `(E,A)` where `E` is an elliptic curve over
        `\QQ` and `A` is an ideal class in an imaginary quadratic number field.

        For the exact definition, in the more general setting of modular forms
        instead of elliptic curves, see section IV of [GrossZagier]_.

        INPUT:

        - ``E`` -- an elliptic curve over `\QQ`

        - ``A`` -- an ideal class in an imaginary quadratic number field

        - ``prec`` -- an integer (default 53) giving the required precision

        EXAMPLES::

            sage: e = EllipticCurve('37a')
            sage: K.<a> = QuadraticField(-40)
            sage: A = K.class_group().gen(0)
            sage: from sage.modular.modform.l_series_gross_zagier import GrossZagierLseries
            sage: G = GrossZagierLseries(e, A)

        TESTS::

            sage: K.<b> = QuadraticField(131)
            sage: A = K.class_group().one()
            sage: G = GrossZagierLseries(e, A)
            Traceback (most recent call last):
            ...
            ValueError: A is not an ideal class in an imaginary quadratic field
        """
        self._E = E
        self._N = N = E.conductor()
        self._A = A
        ideal = A.ideal()
        K = A.gens()[0].parent()
        D = K.disc()
        if not(K.degree() == 2 and D < 0):
            raise ValueError("A is not an ideal class in an"
                             " imaginary quadratic field")
        Q = ideal.quadratic_form().reduced_form()
        epsilon = - kronecker_character(D)(N)
        self._dokchister = Dokchitser(N ** 2 * D ** 2,
                                      [0, 0, 1, 1],
                                      weight=2, eps=epsilon, prec=prec)
        self._nterms = nterms = Integer(self._dokchister.num_coeffs())
        if nterms > 1e6:
            # just takes way to long
            raise ValueError("Too many terms: {}".format(nterms))
        zeta_ord = ideal.number_field().zeta_order()
        an_list = gross_zagier_L_series(E.anlist(nterms + 1), Q, N, zeta_ord)
        self._dokchister.gp().set('a', an_list[1:])
        self._dokchister.init_coeffs('a[k]', 1)

    def __call__(self, s, der=0):
        r"""
        Return the value at `s`.

        INPUT:

        - `s` -- complex number

        - ``der`` -- ? (default 0)

        EXAMPLES::

            sage: e = EllipticCurve('37a')
            sage: K.<a> = QuadraticField(-40)
            sage: A = K.class_group().gen(0)
            sage: from sage.modular.modform.l_series_gross_zagier import GrossZagierLseries
            sage: G = GrossZagierLseries(e, A)
            sage: G(3)
            -0.272946890617590
        """
        return self._dokchister(s, der)

    def taylor_series(self, s=1, series_prec=6, var='z'):
        r"""
        Return the Taylor series at `s`.

        INPUT:

        - `s` -- complex number (default 1)
        - ``series_prec`` -- number of terms (default 6) in the Taylor series
        - ``var`` -- variable (default 'z')

        EXAMPLES::

            sage: e = EllipticCurve('37a')
            sage: K.<a> = QuadraticField(-40)
            sage: A = K.class_group().gen(0)
            sage: from sage.modular.modform.l_series_gross_zagier import GrossZagierLseries
            sage: G = GrossZagierLseries(e, A)
            sage: G.taylor_series(2,3)
            -0.613002046122894 + 0.490374999263514*z - 0.122903033710382*z^2 + O(z^3)
        """
        return self._dokchister.taylor_series(s, series_prec, var)

    def _repr_(self):
        """
        Return the string representation.

        EXAMPLES::

            sage: e = EllipticCurve('37a')
            sage: K.<a> = QuadraticField(-40)
            sage: A = K.class_group().gen(0)
            sage: from sage.modular.modform.l_series_gross_zagier import GrossZagierLseries
            sage: GrossZagierLseries(e, A)
            Gross Zagier L-series attached to Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field with ideal class Fractional ideal class (2, 1/2*a)
        """
        msg = "Gross Zagier L-series attached to {} with ideal class {}"
        return msg.format(self._E, self._A)
Пример #6
0
    def lseries(self,
                num_prec=None,
                max_imaginary_part=0,
                max_asymp_coeffs=40):
        r"""
        Return the L-series of ``self`` if ``self`` is modular and holomorphic.
        Note: This relies on the (pari) based function ``Dokchitser``.

        INPUT:

        - ``num_prec``           -- An integer denoting the to-be-used numerical precision.
                                    If integer ``num_prec=None`` (default) the default
                                    numerical precision of the parent of ``self`` is used.

        - ``max_imaginary_part`` -- A real number (default: 0), indicating up to which
                                    imaginary part the L-series is going to be studied.

        - ``max_asymp_coeffs``   -- An integer (default: 40).

        OUTPUT:

        An interface to Tim Dokchitser's program for computing L-series, namely
        the series given by the Fourier coefficients of ``self``.

        EXAMPLES::

            sage: from sage.modular.modform.eis_series import eisenstein_series_lseries
            sage: from sage.modular.modform_hecketriangle.space import ModularForms
            sage: f = ModularForms(n=3, k=4).E4()/240
            sage: L = f.lseries()
            sage: L
            L-series associated to the modular form 1/240 + q + 9*q^2 + 28*q^3 + 73*q^4 + O(q^5)
            sage: L.conductor
            1
            sage: L(1).prec()
            53
            sage: L.check_functional_equation() < 2^(-50)
            True
            sage: L(1)
            -0.0304484570583...
            sage: abs(L(1) - eisenstein_series_lseries(4)(1)) < 2^(-53)
            True
            sage: L.derivative(1, 1)
            -0.0504570844798...
            sage: L.derivative(1, 2)/2
            -0.0350657360354...
            sage: L.taylor_series(1, 3)
            -0.0304484570583... - 0.0504570844798...*z - 0.0350657360354...*z^2 + O(z^3)
            sage: coeffs = f.q_expansion_vector(min_exp=0, max_exp=20, fix_d=True)
            sage: sum([coeffs[k]*k^(-10) for k in range(1,len(coeffs))]).n(53)
            1.00935215408...
            sage: L(10)
            1.00935215649...

            sage: f = ModularForms(n=6, k=4).E4()
            sage: L = f.lseries(num_prec=200)
            sage: L.conductor
            3
            sage: L.check_functional_equation() < 2^(-180)
            True
            sage: L(1)
            -2.92305187760575399490414692523085855811204642031749788...
            sage: L(1).prec()
            200
            sage: coeffs = f.q_expansion_vector(min_exp=0, max_exp=20, fix_d=True)
            sage: sum([coeffs[k]*k^(-10) for k in range(1,len(coeffs))]).n(53)
            24.2281438789...
            sage: L(10).n(53)
            24.2281439447...

            sage: f = ModularForms(n=8, k=6, ep=-1).E6()
            sage: L = f.lseries()
            sage: L.check_functional_equation() < 2^(-45)
            True
            sage: L.taylor_series(3, 3)
            0.000000000000... + 0.867197036668...*z + 0.261129628199...*z^2 + O(z^3)
            sage: coeffs = f.q_expansion_vector(min_exp=0, max_exp=20, fix_d=True)
            sage: sum([coeffs[k]*k^(-10) for k in range(1,len(coeffs))]).n(53)
            -13.0290002560...
            sage: L(10).n(53)
            -13.0290184579...

            sage: f = (ModularForms(n=17, k=24).Delta()^2)    # long time
            sage: L = f.lseries()    # long time
            sage: L.check_functional_equation() < 2^(-50)    # long time
            True
            sage: L.taylor_series(12, 3)    # long time
            0.000683924755280... - 0.000875942285963...*z + 0.000647618966023...*z^2 + O(z^3)
            sage: coeffs = f.q_expansion_vector(min_exp=0, max_exp=20, fix_d=True)    # long time
            sage: sum([coeffs[k]*k^(-30) for k in range(1,len(coeffs))]).n(53)    # long time
            9.31562890589...e-10
            sage: L(30).n(53)    # long time
            9.31562890589...e-10

            sage: f = ModularForms(n=infinity, k=2, ep=-1).f_i()
            sage: L = f.lseries()
            sage: L.check_functional_equation() < 2^(-50)
            True
            sage: L.taylor_series(1, 3)
            0.000000000000... + 5.76543616701...*z + 9.92776715593...*z^2 + O(z^3)
            sage: coeffs = f.q_expansion_vector(min_exp=0, max_exp=20, fix_d=True)
            sage: sum([coeffs[k]*k^(-10) for k in range(1,len(coeffs))]).n(53)
            -23.9781792831...
            sage: L(10).n(53)
            -23.9781792831...
        """

        from sage.rings.all import ZZ
        from sage.symbolic.all import pi
        from sage.functions.other import sqrt
        from sage.lfunctions.dokchitser import Dokchitser

        if (not (self.is_modular() and self.is_holomorphic())
                or self.weight() == 0):
            raise NotImplementedError(
                "L-series are only implemented for non-trivial holomorphic modular forms."
            )

        if (num_prec is None):
            num_prec = self.parent().default_num_prec()

        conductor = self.group().lam()**2
        if (self.group().is_arithmetic()):
            conductor = ZZ(conductor)
        else:
            conductor = conductor.n(num_prec)

        gammaV = [0, 1]
        weight = self.weight()
        eps = self.ep()

        # L^*(s) = cor_factor * (2*pi)^(-s)gamma(s)*L(f,s),
        cor_factor = (2 * sqrt(pi)).n(num_prec)

        if (self.is_cuspidal()):
            poles = []
            residues = []
        else:
            poles = [weight]
            val_inf = self.q_expansion_fixed_d(prec=1, d_num_prec=num_prec)[0]
            residue = eps * val_inf * cor_factor

            # (pari) BUG?
            # The residue of the above L^*(s) differs by a factor -1 from
            # the residue pari expects (?!?).
            residue *= -1

            residues = [residue]

        L = Dokchitser(conductor=conductor,
                       gammaV=gammaV,
                       weight=weight,
                       eps=eps,
                       poles=poles,
                       residues=residues,
                       prec=num_prec)

        # TODO for later: Figure out the correct coefficient growth and do L.set_coeff_growth(...)

        # num_coeffs = L.num_coeffs()
        num_coeffs = L.num_coeffs(1.2)
        coeff_vector = [
            coeff for coeff in self.q_expansion_vector(
                min_exp=0, max_exp=num_coeffs + 1, fix_d=True)
        ]
        pari_precode = "coeff = {};".format(coeff_vector)

        L.init_coeffs(v="coeff[k+1]",
                      pari_precode=pari_precode,
                      max_imaginary_part=max_imaginary_part,
                      max_asymp_coeffs=max_asymp_coeffs)
        L.check_functional_equation()
        L.rename("L-series associated to the {} form {}".format(
            "cusp" if self.is_cuspidal() else "modular", self))

        return L
Пример #7
0
    def lseries(self, num_prec=None, max_imaginary_part=0, max_asymp_coeffs=40):
        r"""
        Return the L-series of ``self`` if ``self`` is modular and holomorphic.
        Note: This relies on the (pari) based function ``Dokchitser``.

        INPUT:

        - ``num_prec``           -- An integer denoting the to-be-used numerical precision.
                                    If integer ``num_prec=None`` (default) the default
                                    numerical precision of the parent of ``self`` is used.

        - ``max_imaginary_part`` -- A real number (default: 0), indicating up to which
                                    imaginary part the L-series is going to be studied.

        - ``max_asymp_coeffs``   -- An integer (default: 40).

        OUTPUT:

        An interface to Tim Dokchitser's program for computing L-series, namely
        the series given by the Fourier coefficients of ``self``.

        EXAMPLES::

            sage: from sage.modular.modform.eis_series import eisenstein_series_lseries
            sage: from sage.modular.modform_hecketriangle.space import ModularForms
            sage: f = ModularForms(n=3, k=4).E4()/240
            sage: L = f.lseries()
            sage: L
            L-series associated to the modular form 1/240 + q + 9*q^2 + 28*q^3 + 73*q^4 + O(q^5)
            sage: L.conductor
            1
            sage: L(1).prec()
            53
            sage: L.check_functional_equation() < 2^(-50)
            True
            sage: L(1)
            -0.0304484570583...
            sage: abs(L(1) - eisenstein_series_lseries(4)(1)) < 2^(-53)
            True
            sage: L.derivative(1, 1)
            -0.0504570844798...
            sage: L.derivative(1, 2)/2
            -0.0350657360354...
            sage: L.taylor_series(1, 3)
            -0.0304484570583... - 0.0504570844798...*z - 0.0350657360354...*z^2 + O(z^3)
            sage: coeffs = f.q_expansion_vector(min_exp=0, max_exp=20, fix_d=True)
            sage: sum([coeffs[k]*k^(-10) for k in range(1,len(coeffs))]).n(53)
            1.00935215408...
            sage: L(10)
            1.00935215649...

            sage: f = ModularForms(n=6, k=4).E4()
            sage: L = f.lseries(num_prec=200)
            sage: L.conductor
            3
            sage: L.check_functional_equation() < 2^(-180)
            True
            sage: L(1)
            -2.92305187760575399490414692523085855811204642031749788...
            sage: L(1).prec()
            200
            sage: coeffs = f.q_expansion_vector(min_exp=0, max_exp=20, fix_d=True)
            sage: sum([coeffs[k]*k^(-10) for k in range(1,len(coeffs))]).n(53)
            24.2281438789...
            sage: L(10).n(53)
            24.2281439447...

            sage: f = ModularForms(n=8, k=6, ep=-1).E6()
            sage: L = f.lseries()
            sage: L.check_functional_equation() < 2^(-45)
            True
            sage: L.taylor_series(3, 3)
            0.000000000000... + 0.867197036668...*z + 0.261129628199...*z^2 + O(z^3)
            sage: coeffs = f.q_expansion_vector(min_exp=0, max_exp=20, fix_d=True)
            sage: sum([coeffs[k]*k^(-10) for k in range(1,len(coeffs))]).n(53)
            -13.0290002560...
            sage: L(10).n(53)
            -13.0290184579...

            sage: f = (ModularForms(n=17, k=24).Delta()^2)    # long time
            sage: L = f.lseries()    # long time
            sage: L.check_functional_equation() < 2^(-50)    # long time
            True
            sage: L.taylor_series(12, 3)    # long time
            0.000683924755280... - 0.000875942285963...*z + 0.000647618966023...*z^2 + O(z^3)
            sage: coeffs = f.q_expansion_vector(min_exp=0, max_exp=20, fix_d=True)    # long time
            sage: sum([coeffs[k]*k^(-30) for k in range(1,len(coeffs))]).n(53)    # long time
            9.31562890589...e-10
            sage: L(30).n(53)    # long time
            9.31562890589...e-10

            sage: f = ModularForms(n=infinity, k=2, ep=-1).f_i()
            sage: L = f.lseries()
            sage: L.check_functional_equation() < 2^(-50)
            True
            sage: L.taylor_series(1, 3)
            0.000000000000... + 5.76543616701...*z + 9.92776715593...*z^2 + O(z^3)
            sage: coeffs = f.q_expansion_vector(min_exp=0, max_exp=20, fix_d=True)
            sage: sum([coeffs[k]*k^(-10) for k in range(1,len(coeffs))]).n(53)
            -23.9781792831...
            sage: L(10).n(53)
            -23.9781792831...
        """

        from sage.rings.all import ZZ
        from sage.symbolic.all import pi
        from sage.functions.other import sqrt
        from sage.lfunctions.dokchitser import Dokchitser

        if (not (self.is_modular() and self.is_holomorphic()) or self.weight() == 0):
            raise NotImplementedError("L-series are only implemented for non-trivial holomorphic modular forms.")

        if (num_prec is None):
            num_prec = self.parent().default_num_prec()

        conductor = self.group().lam()**2
        if (self.group().is_arithmetic()):
            conductor = ZZ(conductor)
        else:
            conductor = conductor.n(num_prec)

        gammaV = [0, 1]
        weight = self.weight()
        eps = self.ep()

        # L^*(s) = cor_factor * (2*pi)^(-s)gamma(s)*L(f,s),
        cor_factor = (2*sqrt(pi)).n(num_prec)

        if (self.is_cuspidal()):
            poles = []
            residues = []
        else:
            poles = [ weight ]
            val_inf = self.q_expansion_fixed_d(prec=1, d_num_prec=num_prec)[0]
            residue = eps * val_inf * cor_factor

            # (pari) BUG?
            # The residue of the above L^*(s) differs by a factor -1 from
            # the residue pari expects (?!?).
            residue *= -1

            residues = [ residue ]

        L = Dokchitser(conductor = conductor,
                          gammaV = gammaV,
                          weight = weight,
                             eps = eps,
                           poles = poles,
                        residues = residues,
                            prec = num_prec)

        # TODO for later: Figure out the correct coefficient growth and do L.set_coeff_growth(...)

        # num_coeffs = L.num_coeffs()
        num_coeffs = L.num_coeffs(1.2)
        coeff_vector = [coeff for coeff in self.q_expansion_vector(min_exp=0, max_exp=num_coeffs + 1, fix_d=True)]
        pari_precode = "coeff = {};".format(coeff_vector)

        L.init_coeffs(v = "coeff[k+1]", pari_precode = pari_precode, max_imaginary_part = max_imaginary_part, max_asymp_coeffs = max_asymp_coeffs)
        L.check_functional_equation()
        L.rename("L-series associated to the {} form {}".format("cusp" if self.is_cuspidal() else "modular", self))

        return L