def lseries_dokchitser(E, prec=53): """ Return the Dokchitser L-series object associated to the elliptic curve E, which may be defined over the rational numbers or a number field. Also prec is the number of bits of precision to which evaluation of the L-series occurs. INPUT: - E -- elliptic curve over a number field (or QQ) - prec -- integer (default: 53) precision in *bits* OUTPUT: - Dokchitser L-function object EXAMPLES:: A curve over Q(sqrt(5)), for which we have an optimized implementation:: sage: from psage.ellcurve.lseries.lseries_nf import lseries_dokchitser sage: K.<a> = NumberField(x^2-x-1); E = EllipticCurve([0,-a,a,0,0]) sage: L = lseries_dokchitser(E); L Dokchitser L-function of Elliptic Curve defined by y^2 + a*y = x^3 + (-a)*x^2 over Number Field in a with defining polynomial x^2 - x - 1 sage: L(1) 0.422214159001667 sage: L.taylor_series(1,5) 0.422214159001667 + 0.575883864741340*z - 0.102163426876721*z^2 - 0.158119743123727*z^3 + 0.120350687595265*z^4 + O(z^5) Higher precision:: sage: L = lseries_dokchitser(E, 200) sage: L(1) 0.42221415900166715092967967717023093014455137669360598558872 A curve over Q(i):: sage: K.<i> = NumberField(x^2 + 1) sage: E = EllipticCurve(K, [1,0]) sage: E.conductor().norm() 256 sage: L = lseries_dokchitser(E, 10) sage: L.taylor_series(1,5) 0.86 + 0.58*z - 0.62*z^2 + 0.19*z^3 + 0.18*z^4 + O(z^5) More examples:: sage: lseries_dokchitser(EllipticCurve([0,-1,1,0,0]), 10)(1) 0.25 sage: K.<i> = NumberField(x^2+1) sage: lseries_dokchitser(EllipticCurve(K, [0,-1,1,0,0]), 10)(1) 0.37 sage: K.<a> = NumberField(x^2-x-1) sage: lseries_dokchitser(EllipticCurve(K, [0,-1,1,0,0]), 10)(1) 0.72 sage: E = EllipticCurve([0,-1,1,0,0]) sage: E.quadratic_twist(2).rank() 1 sage: K.<d> = NumberField(x^2-2) sage: L = lseries_dokchitser(EllipticCurve(K, [0,-1,1,0,0]), 10) sage: L(1) 0 sage: L.taylor_series(1, 5) 0.58*z + 0.20*z^2 - 0.50*z^3 + 0.28*z^4 + O(z^5) You can use this function as an algorithm to compute the sign of the functional equation (global root number):: sage: E = EllipticCurve([1..5]) sage: E.root_number() -1 sage: L = lseries_dokchitser(E,32); L Dokchitser L-function of Elliptic Curve defined by y^2 + x*y = x^3 - x^2 + 4*x + 3 over Rational Field sage: L.eps -1 Over QQ, this isn't so useful (since Sage has a root_number method), but over number fields it is very useful:: sage: K.<a> = NumberField(x^2 - x - 1) sage: E1=EllipticCurve([0,-a-1,1,a,0]); E0 = EllipticCurve([0,-a,a,0,0]) sage: lseries_dokchitser(E1, 16).eps -1 sage: E1.rank() 1 sage: lseries_dokchitser(E0, 16).eps 1 sage: E0.rank() 0 """ # The code assumes in various places that we have a global minimal model, # for example, in anlist_sqrt5 above. E = E.global_minimal_model() # Check that we're over a number field. K = E.base_field() if not is_NumberField(K): raise TypeError("base field must be a number field") # Compute norm of the conductor -- awkward because QQ elements have no norm method (they should). N = E.conductor() if K != QQ: N = N.norm() # We guess the sign epsilon in the functional equation to be +1 # first. If our guess is wrong then we just choose the other # possibility. epsilon = 1 # Define the Dokchitser L-function object with all parameters set: L = Dokchitser(conductor=N * K.discriminant()**2, gammaV=[0] * K.degree() + [1] * K.degree(), weight=2, eps=epsilon, poles=[], prec=prec) # Find out how many coefficients of the Dirichlet series are needed # to compute to the requested precision. n = L.num_coeffs() # print "num coeffs = %s"%n # Compute the Dirichlet series coefficients coeffs = anlist(E, n)[1:] # Define a string that when evaluated in PARI defines a function # a(k), which returns the Dirichlet coefficient a_k. s = 'v=%s; a(k)=v[k];' % coeffs # Actually tell the L-series / PARI about the coefficients. L.init_coeffs('a(k)', pari_precode=s) # Test that the functional equation is satisfied. This will very, # very, very likely if we chose the sign of the functional # equation incorrectly, or made any mistake in computing the # Dirichlet series coefficients. tiny = max(1e-8, old_div(1.0, 2**(prec - 1))) if abs(L.check_functional_equation()) > tiny: # The test failed, so we try the other choice of functional equation. epsilon *= -1 L.eps = epsilon # It is not necessary to recreate L -- just tell PARI the different sign. L._gp_eval('sgn = %s' % epsilon) # Once again, verify that the functional equation is # satisfied. If it is, then we've got it. If it isn't, then # there is definitely some other subtle bug, probably in computed # the Dirichlet series coefficients. if abs(L.check_functional_equation()) > tiny: raise RuntimeError( "Functional equation not numerically satisfied for either choice of sign" ) L.rename('Dokchitser L-function of %s' % E) return L
def lseries_dokchitser(E, prec=53): """ Return the Dokchitser L-series object associated to the elliptic curve E, which may be defined over the rational numbers or a number field. Also prec is the number of bits of precision to which evaluation of the L-series occurs. INPUT: - E -- elliptic curve over a number field (or QQ) - prec -- integer (default: 53) precision in *bits* OUTPUT: - Dokchitser L-function object EXAMPLES:: A curve over Q(sqrt(5)), for which we have an optimized implementation:: sage: from psage.ellcurve.lseries.lseries_nf import lseries_dokchitser sage: K.<a> = NumberField(x^2-x-1); E = EllipticCurve([0,-a,a,0,0]) sage: L = lseries_dokchitser(E); L Dokchitser L-function of Elliptic Curve defined by y^2 + a*y = x^3 + (-a)*x^2 over Number Field in a with defining polynomial x^2 - x - 1 sage: L(1) 0.422214159001667 sage: L.taylor_series(1,5) 0.422214159001667 + 0.575883864741340*z - 0.102163426876721*z^2 - 0.158119743123727*z^3 + 0.120350687595265*z^4 + O(z^5) Higher precision:: sage: L = lseries_dokchitser(E, 200) sage: L(1) 0.42221415900166715092967967717023093014455137669360598558872 A curve over Q(i):: sage: K.<i> = NumberField(x^2 + 1) sage: E = EllipticCurve(K, [1,0]) sage: E.conductor().norm() 256 sage: L = lseries_dokchitser(E, 10) sage: L.taylor_series(1,5) 0.86 + 0.58*z - 0.62*z^2 + 0.19*z^3 + 0.18*z^4 + O(z^5) More examples:: sage: lseries_dokchitser(EllipticCurve([0,-1,1,0,0]), 10)(1) 0.25 sage: K.<i> = NumberField(x^2+1) sage: lseries_dokchitser(EllipticCurve(K, [0,-1,1,0,0]), 10)(1) 0.37 sage: K.<a> = NumberField(x^2-x-1) sage: lseries_dokchitser(EllipticCurve(K, [0,-1,1,0,0]), 10)(1) 0.72 sage: E = EllipticCurve([0,-1,1,0,0]) sage: E.quadratic_twist(2).rank() 1 sage: K.<d> = NumberField(x^2-2) sage: L = lseries_dokchitser(EllipticCurve(K, [0,-1,1,0,0]), 10) sage: L(1) 0 sage: L.taylor_series(1, 5) 0.58*z + 0.20*z^2 - 0.50*z^3 + 0.28*z^4 + O(z^5) You can use this function as an algorithm to compute the sign of the functional equation (global root number):: sage: E = EllipticCurve([1..5]) sage: E.root_number() -1 sage: L = lseries_dokchitser(E,32); L Dokchitser L-function of Elliptic Curve defined by y^2 + x*y = x^3 - x^2 + 4*x + 3 over Rational Field sage: L.eps -1 Over QQ, this isn't so useful (since Sage has a root_number method), but over number fields it is very useful:: sage: K.<a> = NumberField(x^2 - x - 1) sage: E1=EllipticCurve([0,-a-1,1,a,0]); E0 = EllipticCurve([0,-a,a,0,0]) sage: lseries_dokchitser(E1, 16).eps -1 sage: E1.rank() 1 sage: lseries_dokchitser(E0, 16).eps 1 sage: E0.rank() 0 """ # The code asssumes in various places that we have a global minimal model, # for example, in anlist_sqrt5 above. E = E.global_minimal_model() # Check that we're over a number field. K = E.base_field() if not is_NumberField(K): raise TypeError, "base field must be a number field" # Compute norm of the conductor -- awkward because QQ elements have no norm method (they should). N = E.conductor() if K != QQ: N = N.norm() # We guess the sign epsilon in the functional equation to be +1 # first. If our guess is wrong then we just choose the other # possibility. epsilon = 1 # Define the Dokchitser L-function object with all parameters set: L = Dokchitser(conductor = N * K.discriminant()**2, gammaV = [0]*K.degree() + [1]*K.degree(), weight = 2, eps = epsilon, poles = [], prec = prec) # Find out how many coefficients of the Dirichlet series are needed # to compute to the requested precision. n = L.num_coeffs() # print "num coeffs = %s"%n # Compute the Dirichlet series coefficients coeffs = anlist(E, n)[1:] # Define a string that when evaluated in PARI defines a function # a(k), which returns the Dirichlet coefficient a_k. s = 'v=%s; a(k)=v[k];'%coeffs # Actually tell the L-series / PARI about the coefficients. L.init_coeffs('a(k)', pari_precode = s) # Test that the functional equation is satisfied. This will very, # very, very likely if we chose the sign of the functional # equation incorrectly, or made any mistake in computing the # Dirichlet series coefficients. tiny = max(1e-8, 1.0/2**(prec-1)) if abs(L.check_functional_equation()) > tiny: # The test failed, so we try the other choice of functional equation. epsilon *= -1 L.eps = epsilon # It is not necessary to recreate L -- just tell PARI the different sign. L._gp_eval('sgn = %s'%epsilon) # Once again, verify that the functional equation is # satisfied. If it is, then we've got it. If it isn't, then # there is definitely some other subtle bug, probably in computed # the Dirichlet series coefficients. if abs(L.check_functional_equation()) > tiny: raise RuntimeError, "Functional equation not numerically satisfied for either choice of sign" L.rename('Dokchitser L-function of %s'%E) return L