def deriv_at1(self, k=None, prec=None): r""" Compute `L'(E,1)` using `k` terms of the series for `L'(E,1)`, under the assumption that `L(E,1) = 0`. The algorithm used is from Section 7.5.3 of Henri Cohen's book *A Course in Computational Algebraic Number Theory*. INPUT: - ``k`` -- number of terms of the series. If zero or ``None``, use `k = \sqrt{N}`, where `N` is the conductor. - ``prec`` -- numerical precision in bits. If zero or ``None``, use a reasonable automatic default. OUTPUT: A tuple of real numbers ``(L1, err)`` where ``L1`` is an approximation for `L'(E,1)` and ``err`` is a bound on the error in the approximation. .. WARNING:: This function only makes sense if `L(E)` has positive order of vanishing at 1, or equivalently if `L(E,1) = 0`. ALGORITHM: - Compute the root number eps. If it is 1, return 0. - Compute the Fourier coefficients `a_n`, for `n` up to and including `k`. - Compute the sum .. MATH:: 2 \cdot \sum_{n=1}^{k} (a_n / n) \cdot E_1(2 \pi n/\sqrt{N}), where `N` is the conductor of `E`, and `E_1` is the exponential integral function. - Compute a bound on the tail end of the series, which is .. MATH:: 2 e^{-2 \pi (k+1) / \sqrt{N}} / (1 - e^{-2 \pi/\sqrt{N}}). For a proof see [Grigorov-Jorza-Patrascu-Patrikis-Stein]. This is exactly the same as the bound for the approximation to `L(E,1)` produced by :meth:`at1`. EXAMPLES:: sage: E = EllipticCurve('37a') sage: E.lseries().deriv_at1() (0.3059866, 0.000801045) sage: E.lseries().deriv_at1(100) (0.3059997738340523018204836833216764744526377745903, 1.52493e-45) sage: E.lseries().deriv_at1(1000) (0.305999773834052301820483683321676474452637774590771998..., 2.75031e-449) With less numerical precision, the error is bounded by numerical accuracy:: sage: L,err = E.lseries().deriv_at1(100, prec=64) sage: L,err (0.305999773834052302, 5.55318e-18) sage: parent(L) Real Field with 64 bits of precision sage: parent(err) Real Field with 24 bits of precision and rounding RNDU Rank 2 and rank 3 elliptic curves:: sage: E = EllipticCurve('389a1') sage: E.lseries().deriv_at1() (0.0000000, 0.000000) sage: E = EllipticCurve((1, 0, 1, -131, 558)) # curve 59450i1 sage: E.lseries().deriv_at1() (-0.00010911444, 0.142428) sage: E.lseries().deriv_at1(4000) (6.990...e-50, 1.31318e-43) """ sqrtN = sqrt(self.__E.conductor()) if k: k = int(k) else: k = int(ceil(sqrtN)) if prec: prec = int(prec) else: # Estimate number of bits for the computation, based on error # estimate below (the denominator of that error is close enough # to 1 that we can ignore it). # 9.065 = 2*Pi/log(2) # 1.443 = 1/log(2) # 12 is an arbitrary extra number of bits (it is chosen # such that the precision is 24 bits when the conductor # equals 11 and k is the default value 4) prec = int(9.065 * k / sqrtN + 1.443 * log(k)) + 12 R = RealField(prec) # Compute error term with bounded precision of 24 bits and # round towards +infinity Rerror = RealField(24, rnd='RNDU') if self.__E.root_number() == 1: # Order of vanishing at 1 of L(E) is even and assumed to be # positive, so L'(E,1) = 0. return (R.zero(), Rerror.zero()) an = self.__E.anlist(k) # list of Sage Integers pi = R.pi() sqrtN = R(self.__E.conductor()).sqrt() v = exp_integral.exponential_integral_1(2 * pi / sqrtN, k) # Compute series sum and accumulate floating point errors L = R.zero() error = Rerror.zero() # Sum of |an[n]|/n sumann = Rerror.zero() for n in xrange(1, k + 1): term = (v[n - 1] * an[n]) / n L += term error += term.epsilon(Rerror) * 5 + L.ulp(Rerror) sumann += Rerror(an[n].abs()) / n L *= 2 # Add error term for exponential_integral_1() errors. # Absolute error for 2*v[i] is 4*max(1, v[0])*2^-prec if v[0] > 1.0: sumann *= Rerror(v[0]) error += (sumann >> (prec - 2)) # Add series error (we use (-2)/(z-1) instead of 2/(1-z) # because this causes 1/(1-z) to be rounded up) z = (-2 * pi / sqrtN).exp() zpow = ((-2 * (k + 1)) * pi / sqrtN).exp() error += ((-2) * Rerror(zpow)) / Rerror(z - 1) return (L, error)
def deriv_at1(self, k=0): r""" Compute $L'(E,1)$ using$ k$ terms of the series for $L'(E,1)$. The algorithm used is from page 406 of Henri Cohen's book ``A Course in Computational Algebraic Number Theory.'' The real precision of the computation is the precision of Python floats. INPUT: k -- int; number of terms of the series OUTPUT: real number -- an approximation for L'(E,1) real number -- a bound on the error in the approximation ALGORITHM: \begin{enumerate} \item Compute the root number eps. If it is 1, return 0. \item Compute the Fourier coefficients $a_n$, for $n$ up to and including $k$. \item Compute the sum $$ 2 * \sum_{n=1}^{k} (a_n / n) * E_1(2 \pi n/\sqrt{N}), $$ where $N$ is the conductor of $E$, and $E_1$ is the exponential integral function. \item Compute a bound on the tail end of the series, which is $$ 2 * e^{-2 \pi (k+1) / \sqrt{N}} / (1 - e^{-2 \ pi/\sqrt{N}}). $$ For a proof see [Grigorov-Jorza-Patrascu-Patrikis-Stein]. This is exactly the same as the bound for the approximation to $L(E,1)$ produced by \code{E.lseries().at1}. \end{enumerate} EXAMPLES:: sage: E = EllipticCurve('37a') sage: E.lseries().deriv_at1() (0.305986660898516, 0.000800351433106958) sage: E.lseries().deriv_at1(100) (0.305999773834052, 1.52437502288740e-45) sage: E.lseries().deriv_at1(1000) (0.305999773834052, 0.000000000000000) """ if self.__E.root_number() == 1: return 0 k = int(k) sqrtN = float(self.__E.conductor().sqrt()) if k == 0: k = int(ceil(sqrtN)) an = self.__E.anlist(k) # list of Sage Integers # Compute z = e^(-2pi/sqrt(N)) pi = 3.14159265358979323846 v = exp_integral.exponential_integral_1(2*pi/sqrtN, k) L = 2*float(sum([ (v[n-1] * an[n])/n for n in xrange(1,k+1)])) error = 2*exp(-2*pi*(k+1)/sqrtN)/(1-exp(-2*pi/sqrtN)) return R(L), R(error)
def deriv_at1(self, k=None, prec=None): r""" Compute `L'(E,1)` using `k` terms of the series for `L'(E,1)`, under the assumption that `L(E,1) = 0`. The algorithm used is from Section 7.5.3 of Henri Cohen's book ``A Course in Computational Algebraic Number Theory.'' INPUT: - ``k`` -- number of terms of the series. If zero or ``None``, use `k = \sqrt(N)`, where `N` is the conductor. - ``prec`` -- numerical precision in bits. If zero or ``None``, use a reasonable automatic default. OUTPUT: A tuple of real numbers ``(L1, err)`` where ``L1`` is an approximation for `L'(E,1)` and ``err`` is a bound on the error in the approximation. .. WARNING:: This function only makes sense if `L(E)` has positive order of vanishing at 1, or equivalently if `L(E,1) = 0`. ALGORITHM: - Compute the root number eps. If it is 1, return 0. - Compute the Fourier coefficients `a_n`, for `n` up to and including `k`. - Compute the sum .. MATH:: 2 * \sum_{n=1}^{k} (a_n / n) * E_1(2 \pi n/\sqrt{N}), where `N` is the conductor of `E`, and `E_1` is the exponential integral function. - Compute a bound on the tail end of the series, which is .. MATH:: 2 e^{-2 \pi (k+1) / \sqrt{N}} / (1 - e^{-2 \pi/\sqrt{N}}). For a proof see [Grigorov-Jorza-Patrascu-Patrikis-Stein]. This is exactly the same as the bound for the approximation to `L(E,1)` produced by :meth:`at1`. EXAMPLES:: sage: E = EllipticCurve('37a') sage: E.lseries().deriv_at1() (0.3059866, 0.000801045) sage: E.lseries().deriv_at1(100) (0.3059997738340523018204836833216764744526377745903, 1.52493e-45) sage: E.lseries().deriv_at1(1000) (0.305999773834052301820483683321676474452637774590771998..., 2.75031e-449) With less numerical precision, the error is bounded by numerical accuracy:: sage: L,err = E.lseries().deriv_at1(100, prec=64) sage: L,err (0.305999773834052302, 5.55318e-18) sage: parent(L) Real Field with 64 bits of precision sage: parent(err) Real Field with 24 bits of precision and rounding RNDU Rank 2 and rank 3 elliptic curves:: sage: E = EllipticCurve('389a1') sage: E.lseries().deriv_at1() (0.0000000, 0.000000) sage: E = EllipticCurve((1, 0, 1, -131, 558)) # curve 59450i1 sage: E.lseries().deriv_at1() (-0.00010911444, 0.142428) sage: E.lseries().deriv_at1(4000) (6.9902290...e-50, 1.31318e-43) """ sqrtN = sqrt(self.__E.conductor()) if k: k = int(k) else: k = int(ceil(sqrtN)) if prec: prec = int(prec) else: # Estimate number of bits for the computation, based on error # estimate below (the denominator of that error is close enough # to 1 that we can ignore it). # 9.065 = 2*Pi/log(2) # 1.443 = 1/log(2) # 12 is an arbitrary extra number of bits (it is chosen # such that the precision is 24 bits when the conductor # equals 11 and k is the default value 4) prec = int(9.065*k/sqrtN + 1.443*log(k)) + 12 R = RealField(prec) # Compute error term with bounded precision of 24 bits and # round towards +infinity Rerror = RealField(24, rnd='RNDU') if self.__E.root_number() == 1: # Order of vanishing at 1 of L(E) is even and assumed to be # positive, so L'(E,1) = 0. return (R.zero(), Rerror.zero()) an = self.__E.anlist(k) # list of Sage Integers pi = R.pi() sqrtN = R(self.__E.conductor()).sqrt() v = exp_integral.exponential_integral_1(2*pi/sqrtN, k) # Compute series sum and accumulate floating point errors L = R.zero() error = Rerror.zero() # Sum of |an[n]|/n sumann = Rerror.zero() for n in xrange(1,k+1): term = (v[n-1] * an[n])/n L += term error += term.epsilon(Rerror)*5 + L.ulp(Rerror) sumann += Rerror(an[n].abs())/n L *= 2 # Add error term for exponential_integral_1() errors. # Absolute error for 2*v[i] is 4*max(1, v[0])*2^-prec if v[0] > 1.0: sumann *= Rerror(v[0]) error += (sumann >> (prec - 2)) # Add series error (we use (-2)/(z-1) instead of 2/(1-z) # because this causes 1/(1-z) to be rounded up) z = (-2*pi/sqrtN).exp() zpow = ((-2*(k+1))*pi/sqrtN).exp() error += ((-2)*Rerror(zpow)) / Rerror(z - 1) return (L, error)
def deriv_at1(self, k=0): r""" Compute $L'(E,1)$ using$ k$ terms of the series for $L'(E,1)$. The algorithm used is from page 406 of Henri Cohen's book ``A Course in Computational Algebraic Number Theory.'' The real precision of the computation is the precision of Python floats. INPUT: k -- int; number of terms of the series OUTPUT: real number -- an approximation for L'(E,1) real number -- a bound on the error in the approximation ALGORITHM: \begin{enumerate} \item Compute the root number eps. If it is 1, return 0. \item Compute the Fourier coefficients $a_n$, for $n$ up to and including $k$. \item Compute the sum $$ 2 * \sum_{n=1}^{k} (a_n / n) * E_1(2 \pi n/\sqrt{N}), $$ where $N$ is the conductor of $E$, and $E_1$ is the exponential integral function. \item Compute a bound on the tail end of the series, which is $$ 2 * e^{-2 \pi (k+1) / \sqrt{N}} / (1 - e^{-2 \ pi/\sqrt{N}}). $$ For a proof see [Grigorov-Jorza-Patrascu-Patrikis-Stein]. This is exactly the same as the bound for the approximation to $L(E,1)$ produced by \code{E.lseries().at1}. \end{enumerate} EXAMPLES:: sage: E = EllipticCurve('37a') sage: E.lseries().deriv_at1() (0.305986660898516, 0.000800351433106958) sage: E.lseries().deriv_at1(100) (0.305999773834052, 1.52437502288740e-45) sage: E.lseries().deriv_at1(1000) (0.305999773834052, 0.000000000000000) """ if self.__E.root_number() == 1: return 0 k = int(k) sqrtN = float(self.__E.conductor().sqrt()) if k == 0: k = int(ceil(sqrtN)) an = self.__E.anlist(k) # list of Sage Integers # Compute z = e^(-2pi/sqrt(N)) pi = 3.14159265358979323846 v = exp_integral.exponential_integral_1(2 * pi / sqrtN, k) L = 2 * float(sum([(v[n - 1] * an[n]) / n for n in xrange(1, k + 1)])) error = 2 * exp(-2 * pi * (k + 1) / sqrtN) / (1 - exp(-2 * pi / sqrtN)) return R(L), R(error)