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
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)
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