Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
241820 views
1
#################################################################################
2
#
3
# (c) Copyright 2011 William Stein
4
#
5
# This file is part of PSAGE
6
#
7
# PSAGE is free software: you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation, either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# PSAGE is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
#
20
21
"""
22
Computing L-series of elliptic curves over general number fields.
23
24
EXAMPLES::
25
26
sage: from psage.ellcurve.lseries.lseries_nf import lseries_dokchitser
27
sage: K.<a> = NumberField(x^2-x-1); E = EllipticCurve([0,-a,a,0,0])
28
sage: L = lseries_dokchitser(E,32); L
29
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
30
sage: L(1)
31
0.422214159
32
sage: L.taylor_series(1, 5)
33
0.422214159 + 0.575883865*z - 0.102163427*z^2 - 0.158119743*z^3 + 0.120350688*z^4 + O(z^5)
34
35
The sign of the functional equation is numerically determined when constructing the L-series::
36
37
sage: L.eps
38
1
39
40
41
AUTHORS:
42
- William Stein
43
- Adam Sorkin (very early version: http://trac.sagemath.org/sage_trac/ticket/9402)
44
45
"""
46
47
import math
48
49
from sage.all import (PowerSeriesRing, Integer, factor, QQ, ZZ,
50
RDF, RealField, Dokchitser, prime_range, prod, pari)
51
from sage.rings.all import is_NumberField
52
53
from psage.ellcurve.lseries.helper import extend_multiplicatively_generic
54
55
##################################################################################
56
# Optimized Special Case: Q(sqrt(5))
57
##################################################################################
58
def anlist_over_sqrt5(E, bound):
59
"""
60
Compute the Dirichlet L-series coefficients, up to and including
61
a_bound. The i-th element of the return list is a[i].
62
63
INPUT:
64
- E -- elliptic curve over Q(sqrt(5)), which must have
65
defining polynomial `x^2-x-1`.
66
- ``bound`` -- integer
67
68
OUTPUT:
69
- list of integers of length bound + 1
70
71
EXAMPLES::
72
73
sage: from psage.ellcurve.lseries.lseries_nf import anlist_over_sqrt5
74
sage: K.<a> = NumberField(x^2-x-1); E = EllipticCurve([0,-a,a,0,0])
75
sage: v = anlist_over_sqrt5(E, 50); v
76
[0, 1, 0, 0, -2, -1, 0, 0, 0, -4, 0, 3, 0, 0, 0, 0, 0, 0, 0, 5, 2, 0, 0, 0, 0, -4, 0, 0, 0, 11, 0, -6, 0, 0, 0, 0, 8, 0, 0, 0, 0, -1, 0, 0, -6, 4, 0, 0, 0, -6, 0]
77
sage: len(v)
78
51
79
80
This function isn't super fast, but at least it will work in a few
81
seconds up to `10^4`::
82
83
sage: t = cputime()
84
sage: v = anlist_over_sqrt5(E, 10^4)
85
sage: assert cputime(t) < 5
86
"""
87
import aplist_sqrt5
88
from psage.number_fields.sqrt5.prime import primes_of_bounded_norm, Prime
89
90
# Compute all of the prime ideals of the ring of integers up to the given bound
91
primes = primes_of_bounded_norm(bound+1)
92
93
# Compute the traces of Frobenius: this is supposed to be the hard part
94
v = aplist_sqrt5.aplist(E, bound+1)
95
96
# Compute information about the primes of bad reduction, in
97
# particular the integers i such that primes[i] is a prime of bad
98
# reduction.
99
bad_primes = set([Prime(a.prime()) for a in E.local_data()])
100
101
102
# We compute the local factors of the L-series as power series in ZZ[T].
103
P = PowerSeriesRing(ZZ, 'T')
104
T = P.gen()
105
# Table of powers of T, so we don't have to compute T^4 (say) thousands of times.
106
Tp = [T**i for i in range(5)]
107
108
# For each prime, we write down the local factor.
109
L_P = []
110
for i, P in enumerate(primes):
111
inertial_deg = 2 if P.is_inert() else 1
112
a_p = v[i]
113
if P in bad_primes:
114
# bad reduction
115
f = 1 - a_p*Tp[inertial_deg]
116
else:
117
# good reduction
118
q = P.norm()
119
f = 1 - a_p*Tp[inertial_deg] + q*Tp[2*inertial_deg]
120
L_P.append(f)
121
122
# Use the local factors of the L-series to compute the Dirichlet
123
# series coefficients of prime-power index.
124
coefficients = [0,1] + [0]*(bound-1)
125
i = 0
126
while i < len(primes):
127
P = primes[i]
128
if P.is_split():
129
s = L_P[i] * L_P[i+1]
130
i += 2
131
else:
132
s = L_P[i]
133
i += 1
134
p = P.p
135
# We need enough terms t so that p^t > bound
136
accuracy_p = int(math.floor(math.log(bound)/math.log(p))) + 1
137
series_p = s.add_bigoh(accuracy_p)**(-1)
138
for j in range(1, accuracy_p):
139
coefficients[p**j] = series_p[j]
140
141
# Using multiplicativity, fill in the non-prime power Dirichlet
142
# series coefficients.
143
extend_multiplicatively_generic(coefficients)
144
return coefficients
145
146
147
##################################################################################
148
# General case over number fields. Largely untouched from trac
149
# ticket. Once Q(sqrt(5)) case above is more optimized, revisit the
150
# three *_over_nf functions below and refactor and improve.
151
##################################################################################
152
153
def get_factor_over_nf(curve, prime_ideal, prime_number, conductor, accuracy):
154
"""
155
Returns the inverse of the factor corresponding to the given prime
156
ideal in the Euler product expansion of the L-function at
157
prime_ideal. Unless the accuracy doesn't need this expansion, and
158
then returns 1 in power series ring.
159
"""
160
P = PowerSeriesRing(ZZ, 'T')
161
T = P.gen()
162
q = prime_ideal.norm()
163
inertial_deg = Integer(q).ord(prime_number)
164
if inertial_deg > accuracy:
165
return P(1)
166
if prime_ideal.divides(conductor):
167
a = curve.local_data(prime_ideal).bad_reduction_type()
168
L = 1 - a*(T**inertial_deg)
169
else:
170
discriminant = curve.discriminant()
171
if prime_ideal.divides(discriminant):
172
a = q + 1 - curve.local_minimal_model(prime_ideal).reduction(prime_ideal).count_points()
173
else:
174
a = q + 1 - curve.reduction(prime_ideal).count_points()
175
L = 1 - a*(T**inertial_deg) + q*(T**(2*inertial_deg))
176
return L
177
178
def get_coeffs_p_over_nf(curve, prime_number, accuracy=20 , conductor=None):
179
"""
180
Computes the inverse of product of L_prime on all primes above prime_number,
181
then returns power series of L_p up to desired accuracy.
182
But will not return power series if need not do so (depends on accuracy).
183
"""
184
if conductor is None:
185
conductor = curve.conductor()
186
primes = curve.base_field().prime_factors(prime_number)
187
series_p = [get_factor_over_nf(curve, prime_id, prime_number, conductor, accuracy) for prime_id in primes]
188
return ( prod(series_p).O(accuracy) )**(-1)
189
190
def anlist_over_nf(E, bound):
191
"""
192
Caution: This method is slow, especially for curves of high
193
conductor, or defined over number fields of high degree.
194
The method is to take the Euler product form, and retrieve
195
the coefficients by expanding each product factor as a power
196
series. The bottleneck is counting points over good reductions.
197
198
TODO: Cache this method: it is computed when initializing the
199
class dokchitser, if cached would have .num_coeffs() of a_i stored.
200
201
EXAMPLE::
202
203
sage: K.<i> = NumberField(x^2+1)
204
sage: E = EllipticCurve(K,[0,-1,1,0,0])
205
sage: from psage.ellcurve.lseries.lseries_nf import anlist_over_nf
206
sage: anlist_over_nf(E, 20)
207
[0, 1, -2, 0, 2, 2, 0, 0, 0, -5, -4, 0, 0, 8, 0, 0, -4, -4, 10, 0, 4]
208
"""
209
conductor = E.conductor()
210
coefficients = [0,1] + [0]*(bound-1)
211
for p in prime_range(bound+1):
212
accuracy_p = int(math.floor(math.log(bound)/math.log(p))) + 1
213
series_p = get_coeffs_p_over_nf(E, p, accuracy_p, conductor)
214
for i in range(1, accuracy_p):
215
coefficients[p**i] = series_p[i]
216
extend_multiplicatively_generic(coefficients)
217
return coefficients
218
219
220
########################################################################
221
222
def anlist(E, bound):
223
r"""
224
Compute the Dirichlet L-series coefficients, up to and including
225
a_bound. The i-th element of the return list is a[i].
226
227
INPUT:
228
- E -- elliptic curve over any number field or the rational numbers
229
- ``bound`` -- integer
230
231
OUTPUT:
232
- list of integers of length bound + 1
233
234
EXAMPLES::
235
236
sage: from psage.ellcurve.lseries.lseries_nf import anlist
237
sage: anlist(EllipticCurve([1,2,3,4,5]),40)
238
[0, 1, 1, 0, -1, -3, 0, -1, -3, -3, -3, -1, 0, 1, -1, 0, -1, 5, -3, 4, 3, 0, -1, -6, 0, 4, 1, 0, 1, -2, 0, 2, 5, 0, 5, 3, 3, 7, 4, 0, 9]
239
sage: K.<a> = NumberField(x^2-x-1)
240
sage: anlist(EllipticCurve(K,[1,2,3,4,5]),40)
241
[0, 1, 0, 0, -3, -3, 0, 0, 0, -6, 0, -2, 0, 0, 0, 0, 5, 0, 0, 8, 9, 0, 0, 0, 0, 4, 0, 0, 0, -4, 0, 4, 0, 0, 0, 0, 18, 0, 0, 0, 0]
242
sage: K.<i> = NumberField(x^2+1)
243
sage: anlist(EllipticCurve(K,[1,2,3,4,5]),40)
244
[0, 1, 1, 0, -1, -6, 0, 0, -3, -6, -6, 0, 0, 2, 0, 0, -1, 10, -6, 0, 6, 0, 0, 0, 0, 17, 2, 0, 0, -4, 0, 0, 5, 0, 10, 0, 6, 14, 0, 0, 18]
245
246
Note that the semantics of anlist agree with the anlist method on
247
elliptic curves over QQ in Sage::
248
249
sage: from psage.ellcurve.lseries.lseries_nf import anlist
250
sage: E = EllipticCurve([1..5])
251
sage: v = E.anlist(10); v
252
[0, 1, 1, 0, -1, -3, 0, -1, -3, -3, -3]
253
sage: len(v)
254
11
255
sage: anlist(E, 10)
256
[0, 1, 1, 0, -1, -3, 0, -1, -3, -3, -3]
257
"""
258
if E.base_field() == QQ:
259
# Rational numbers -- use code built into Sage
260
v = E.anlist(bound)
261
elif list(E.base_field().defining_polynomial()) == [-1,-1,1]:
262
# An optimized special case -- Q(sqrt(5))
263
v = anlist_over_sqrt5(E, bound)
264
else:
265
# General number field -- very slow in general
266
v = anlist_over_nf(E, bound)
267
return v
268
269
270
def lseries_dokchitser(E, prec=53):
271
"""
272
Return the Dokchitser L-series object associated to the elliptic
273
curve E, which may be defined over the rational numbers or a
274
number field. Also prec is the number of bits of precision to
275
which evaluation of the L-series occurs.
276
277
INPUT:
278
- E -- elliptic curve over a number field (or QQ)
279
- prec -- integer (default: 53) precision in *bits*
280
281
OUTPUT:
282
- Dokchitser L-function object
283
284
EXAMPLES::
285
286
A curve over Q(sqrt(5)), for which we have an optimized implementation::
287
288
sage: from psage.ellcurve.lseries.lseries_nf import lseries_dokchitser
289
sage: K.<a> = NumberField(x^2-x-1); E = EllipticCurve([0,-a,a,0,0])
290
sage: L = lseries_dokchitser(E); L
291
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
292
sage: L(1)
293
0.422214159001667
294
sage: L.taylor_series(1,5)
295
0.422214159001667 + 0.575883864741340*z - 0.102163426876721*z^2 - 0.158119743123727*z^3 + 0.120350687595265*z^4 + O(z^5)
296
297
Higher precision::
298
299
sage: L = lseries_dokchitser(E, 200)
300
sage: L(1)
301
0.42221415900166715092967967717023093014455137669360598558872
302
303
A curve over Q(i)::
304
305
sage: K.<i> = NumberField(x^2 + 1)
306
sage: E = EllipticCurve(K, [1,0])
307
sage: E.conductor().norm()
308
256
309
sage: L = lseries_dokchitser(E, 10)
310
sage: L.taylor_series(1,5)
311
0.86 + 0.58*z - 0.62*z^2 + 0.19*z^3 + 0.18*z^4 + O(z^5)
312
313
More examples::
314
315
sage: lseries_dokchitser(EllipticCurve([0,-1,1,0,0]), 10)(1)
316
0.25
317
sage: K.<i> = NumberField(x^2+1)
318
sage: lseries_dokchitser(EllipticCurve(K, [0,-1,1,0,0]), 10)(1)
319
0.37
320
sage: K.<a> = NumberField(x^2-x-1)
321
sage: lseries_dokchitser(EllipticCurve(K, [0,-1,1,0,0]), 10)(1)
322
0.72
323
324
sage: E = EllipticCurve([0,-1,1,0,0])
325
sage: E.quadratic_twist(2).rank()
326
1
327
sage: K.<d> = NumberField(x^2-2)
328
sage: L = lseries_dokchitser(EllipticCurve(K, [0,-1,1,0,0]), 10)
329
sage: L(1)
330
0
331
sage: L.taylor_series(1, 5)
332
0.58*z + 0.20*z^2 - 0.50*z^3 + 0.28*z^4 + O(z^5)
333
334
You can use this function as an algorithm to compute the sign of the functional
335
equation (global root number)::
336
337
sage: E = EllipticCurve([1..5])
338
sage: E.root_number()
339
-1
340
sage: L = lseries_dokchitser(E,32); L
341
Dokchitser L-function of Elliptic Curve defined by y^2 + x*y = x^3 - x^2 + 4*x + 3 over Rational Field
342
sage: L.eps
343
-1
344
345
Over QQ, this isn't so useful (since Sage has a root_number
346
method), but over number fields it is very useful::
347
348
sage: K.<a> = NumberField(x^2 - x - 1)
349
sage: E1=EllipticCurve([0,-a-1,1,a,0]); E0 = EllipticCurve([0,-a,a,0,0])
350
sage: lseries_dokchitser(E1, 16).eps
351
-1
352
sage: E1.rank()
353
1
354
sage: lseries_dokchitser(E0, 16).eps
355
1
356
sage: E0.rank()
357
0
358
"""
359
# The code asssumes in various places that we have a global minimal model,
360
# for example, in anlist_sqrt5 above.
361
E = E.global_minimal_model()
362
363
# Check that we're over a number field.
364
K = E.base_field()
365
if not is_NumberField(K):
366
raise TypeError, "base field must be a number field"
367
368
# Compute norm of the conductor -- awkward because QQ elements have no norm method (they should).
369
N = E.conductor()
370
if K != QQ:
371
N = N.norm()
372
373
# We guess the sign epsilon in the functional equation to be +1
374
# first. If our guess is wrong then we just choose the other
375
# possibility.
376
epsilon = 1
377
378
# Define the Dokchitser L-function object with all parameters set:
379
L = Dokchitser(conductor = N * K.discriminant()**2,
380
gammaV = [0]*K.degree() + [1]*K.degree(),
381
weight = 2, eps = epsilon, poles = [], prec = prec)
382
383
# Find out how many coefficients of the Dirichlet series are needed
384
# to compute to the requested precision.
385
n = L.num_coeffs()
386
# print "num coeffs = %s"%n
387
388
389
# Compute the Dirichlet series coefficients
390
coeffs = anlist(E, n)[1:]
391
392
# Define a string that when evaluated in PARI defines a function
393
# a(k), which returns the Dirichlet coefficient a_k.
394
s = 'v=%s; a(k)=v[k];'%coeffs
395
396
# Actually tell the L-series / PARI about the coefficients.
397
L.init_coeffs('a(k)', pari_precode = s)
398
399
# Test that the functional equation is satisfied. This will very,
400
# very, very likely if we chose the sign of the functional
401
# equation incorrectly, or made any mistake in computing the
402
# Dirichlet series coefficients.
403
tiny = max(1e-8, 1.0/2**(prec-1))
404
if abs(L.check_functional_equation()) > tiny:
405
# The test failed, so we try the other choice of functional equation.
406
epsilon *= -1
407
L.eps = epsilon
408
409
# It is not necessary to recreate L -- just tell PARI the different sign.
410
L._gp_eval('sgn = %s'%epsilon)
411
412
# Once again, verify that the functional equation is
413
# satisfied. If it is, then we've got it. If it isn't, then
414
# there is definitely some other subtle bug, probably in computed
415
# the Dirichlet series coefficients.
416
if abs(L.check_functional_equation()) > tiny:
417
raise RuntimeError, "Functional equation not numerically satisfied for either choice of sign"
418
419
L.rename('Dokchitser L-function of %s'%E)
420
return L
421
422