Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/lfunctions/dokchitser.py
4057 views
1
"""
2
Dokchitser's L-functions Calculator
3
4
AUTHORS:
5
6
- Tim Dokchitser (2002): original PARI code and algorithm (and the
7
documentation below is based on Dokchitser's docs).
8
9
- William Stein (2006-03-08): Sage interface
10
11
TODO:
12
13
- add more examples from data/extcode/pari/dokchitser that illustrate
14
use with Eisenstein series, number fields, etc.
15
16
- plug this code into number fields and modular forms code (elliptic
17
curves are done).
18
"""
19
20
#*****************************************************************************
21
# Copyright (C) 2006 William Stein <[email protected]>
22
#
23
# Distributed under the terms of the GNU General Public License (GPL)
24
# as published by the Free Software Foundation; either version 2 of
25
# the License, or (at your option) any later version.
26
# http://www.gnu.org/licenses/
27
#*****************************************************************************
28
29
import copy
30
from sage.structure.sage_object import SageObject
31
from sage.rings.all import ComplexField, Integer
32
from sage.misc.all import verbose, sage_eval
33
import sage.interfaces.gp
34
35
class Dokchitser(SageObject):
36
r"""
37
Dokchitser's `L`-functions Calculator
38
39
Create a Dokchitser `L`-series with
40
41
Dokchitser(conductor, gammaV, weight, eps, poles, residues, init,
42
prec)
43
44
where
45
46
- ``conductor`` - integer, the conductor
47
48
- ``gammaV`` - list of Gamma-factor parameters, e.g. [0] for
49
Riemann zeta, [0,1] for ell.curves, (see examples).
50
51
- ``weight`` - positive real number, usually an integer e.g. 1 for
52
Riemann zeta, 2 for `H^1` of curves/`\QQ`
53
54
- ``eps`` - complex number; sign in functional equation
55
56
- ``poles`` - (default: []) list of points where `L^*(s)` has
57
(simple) poles; only poles with `Re(s)>weight/2` should be
58
included
59
60
- ``residues`` - vector of residues of `L^*(s)` in those poles or
61
set residues='automatic' (default value)
62
63
- ``prec`` - integer (default: 53) number of *bits* of precision
64
65
RIEMANN ZETA FUNCTION:
66
67
We compute with the Riemann Zeta function.
68
69
::
70
71
sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
72
sage: L
73
Dokchitser L-series of conductor 1 and weight 1
74
sage: L(1)
75
Traceback (most recent call last):
76
...
77
ArithmeticError
78
sage: L(2)
79
1.64493406684823
80
sage: L(2, 1.1)
81
1.64493406684823
82
sage: L.derivative(2)
83
-0.937548254315844
84
sage: h = RR('0.0000000000001')
85
sage: (zeta(2+h) - zeta(2.))/h
86
-0.937028232783632
87
sage: L.taylor_series(2, k=5)
88
1.64493406684823 - 0.937548254315844*z + 0.994640117149451*z^2 - 1.00002430047384*z^3 + 1.00006193307...*z^4 + O(z^5)
89
90
RANK 1 ELLIPTIC CURVE:
91
92
We compute with the `L`-series of a rank `1`
93
curve.
94
95
::
96
97
sage: E = EllipticCurve('37a')
98
sage: L = E.lseries().dokchitser(); L
99
Dokchitser L-function associated to Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
100
sage: L(1)
101
0.000000000000000
102
sage: L.derivative(1)
103
0.305999773834052
104
sage: L.derivative(1,2)
105
0.373095594536324
106
sage: L.num_coeffs()
107
48
108
sage: L.taylor_series(1,4)
109
0.000000000000000 + 0.305999773834052*z + 0.186547797268162*z^2 - 0.136791463097188*z^3 + O(z^4)
110
sage: L.check_functional_equation()
111
6.11218974800000e-18 # 32-bit
112
6.04442711160669e-18 # 64-bit
113
114
RANK 2 ELLIPTIC CURVE:
115
116
We compute the leading coefficient and Taylor expansion of the
117
`L`-series of a rank `2` curve.
118
119
::
120
121
sage: E = EllipticCurve('389a')
122
sage: L = E.lseries().dokchitser()
123
sage: L.num_coeffs ()
124
156
125
sage: L.derivative(1,E.rank())
126
1.51863300057685
127
sage: L.taylor_series(1,4)
128
2.90759778535572e-20 + (-1.64772676916085e-20)*z + 0.759316500288427*z^2 - 0.430302337583362*z^3 + O(z^4) # 32-bit
129
-3.11623283109075e-21 + (1.76595961125962e-21)*z + 0.759316500288427*z^2 - 0.430302337583362*z^3 + O(z^4) # 64-bit
130
131
RAMANUJAN DELTA L-FUNCTION:
132
133
The coefficients are given by Ramanujan's tau function::
134
135
sage: L = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
136
sage: pari_precode = 'tau(n)=(5*sigma(n,3)+7*sigma(n,5))*n/12 - 35*sum(k=1,n-1,(6*k-4*(n-k))*sigma(k,3)*sigma(n-k,5))'
137
sage: L.init_coeffs('tau(k)', pari_precode=pari_precode)
138
139
We redefine the default bound on the coefficients: Deligne's
140
estimate on tau(n) is better than the default
141
coefgrow(n)=`(4n)^{11/2}` (by a factor 1024), so
142
re-defining coefgrow() improves efficiency (slightly faster).
143
144
::
145
146
sage: L.num_coeffs()
147
12
148
sage: L.set_coeff_growth('2*n^(11/2)')
149
sage: L.num_coeffs()
150
11
151
152
Now we're ready to evaluate, etc.
153
154
::
155
156
sage: L(1)
157
0.0374412812685155
158
sage: L(1, 1.1)
159
0.0374412812685155
160
sage: L.taylor_series(1,3)
161
0.0374412812685155 + 0.0709221123619322*z + 0.0380744761270520*z^2 + O(z^3)
162
"""
163
def __init__(self, conductor, gammaV, weight, eps, \
164
poles=[], residues='automatic', prec=53,
165
init=None):
166
"""
167
Initialization of Dokchitser calculator EXAMPLES::
168
169
sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
170
sage: L.num_coeffs()
171
4
172
"""
173
self.conductor = conductor
174
self.gammaV = gammaV
175
self.weight = weight
176
self.eps = eps
177
self.poles = poles
178
self.residues = residues
179
self.prec = prec
180
self.__CC = ComplexField(self.prec)
181
self.__RR = self.__CC._real_field()
182
if not init is None:
183
self.init_coeffs(init)
184
self.__init = init
185
else:
186
self.__init = False
187
188
def __reduce__(self):
189
D = copy.copy(self.__dict__)
190
if D.has_key('_Dokchitser__gp'):
191
del D['_Dokchitser__gp']
192
return reduce_load_dokchitser, (D, )
193
194
def _repr_(self):
195
z = "Dokchitser L-series of conductor %s and weight %s"%(
196
self.conductor, self.weight)
197
return z
198
199
def __del__(self):
200
self.gp().quit()
201
202
def gp(self):
203
"""
204
Return the gp interpreter that is used to implement this Dokchitser
205
L-function.
206
207
EXAMPLES::
208
209
sage: E = EllipticCurve('11a')
210
sage: L = E.lseries().dokchitser()
211
sage: L(2)
212
0.546048036215014
213
sage: L.gp()
214
PARI/GP interpreter
215
"""
216
try:
217
return self.__gp
218
except AttributeError:
219
logfile = None
220
# For debugging
221
#logfile = os.path.join(DOT_SAGE, 'dokchitser.log')
222
g = sage.interfaces.gp.Gp(script_subdirectory='dokchitser', logfile=logfile)
223
g.read('computel.gp')
224
self.__gp = g
225
self._gp_eval('default(realprecision, %s)'%(self.prec//3 + 2))
226
self._gp_eval('conductor = %s'%self.conductor)
227
self._gp_eval('gammaV = %s'%self.gammaV)
228
self._gp_eval('weight = %s'%self.weight)
229
self._gp_eval('sgn = %s'%self.eps)
230
self._gp_eval('Lpoles = %s'%self.poles)
231
self._gp_eval('Lresidues = %s'%self.residues)
232
g._dokchitser = True
233
return g
234
235
def _gp_eval(self, s):
236
try:
237
t = self.gp().eval(s)
238
except (RuntimeError, TypeError):
239
raise RuntimeError, "Unable to create L-series, due to precision or other limits in PARI."
240
if '***' in t:
241
raise RuntimeError, "Unable to create L-series, due to precision or other limits in PARI."
242
return t
243
244
def __check_init(self):
245
if not self.__init:
246
raise ValueError, "you must call init_coeffs on the L-function first"
247
248
def num_coeffs(self, T=1):
249
"""
250
Return number of coefficients `a_n` that are needed in
251
order to perform most relevant `L`-function computations to
252
the desired precision.
253
254
EXAMPLES::
255
256
sage: E = EllipticCurve('11a')
257
sage: L = E.lseries().dokchitser()
258
sage: L.num_coeffs()
259
26
260
sage: E = EllipticCurve('5077a')
261
sage: L = E.lseries().dokchitser()
262
sage: L.num_coeffs()
263
568
264
sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
265
sage: L.num_coeffs()
266
4
267
"""
268
return Integer(self.gp().eval('cflength(%s)'%T))
269
270
def init_coeffs(self, v, cutoff=1,
271
w=None,
272
pari_precode='',
273
max_imaginary_part=0,
274
max_asymp_coeffs=40):
275
"""
276
Set the coefficients `a_n` of the `L`-series. If
277
`L(s)` is not equal to its dual, pass the coefficients of
278
the dual as the second optional argument.
279
280
INPUT:
281
282
283
- ``v`` - list of complex numbers or string (pari
284
function of k)
285
286
- ``cutoff`` - real number = 1 (default: 1)
287
288
- ``w`` - list of complex numbers or string (pari
289
function of k)
290
291
- ``pari_precode`` - some code to execute in pari
292
before calling initLdata
293
294
- ``max_imaginary_part`` - (default: 0): redefine if
295
you want to compute L(s) for s having large imaginary part,
296
297
- ``max_asymp_coeffs`` - (default: 40): at most this
298
many terms are generated in asymptotic series for phi(t) and
299
G(s,t).
300
301
302
EXAMPLES::
303
304
sage: L = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
305
sage: pari_precode = 'tau(n)=(5*sigma(n,3)+7*sigma(n,5))*n/12 - 35*sum(k=1,n-1,(6*k-4*(n-k))*sigma(k,3)*sigma(n-k,5))'
306
sage: L.init_coeffs('tau(k)', pari_precode=pari_precode)
307
308
Evaluate the resulting L-function at a point, and compare with the answer that
309
one gets "by definition" (of L-function attached to a modular form)::
310
311
sage: L(14)
312
0.998583063162746
313
sage: a = delta_qexp(1000)
314
sage: sum(a[n]/float(n)^14 for n in range(1,1000))
315
0.9985830631627459
316
317
Illustrate that one can give a list of complex numbers for v (see trac 10937)::
318
319
sage: L2 = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
320
sage: L2.init_coeffs(list(delta_qexp(1000))[1:])
321
sage: L2(14)
322
0.998583063162746
323
324
TESTS:
325
326
Verify that setting the `w` parameter does not raise an error
327
(see trac 10937). Note that the meaning of `w` does not seem to
328
be documented anywhere in Dokchitser's package yet, so there is
329
no claim that the example below is meaningful! ::
330
331
sage: L2 = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
332
sage: L2.init_coeffs(list(delta_qexp(1000))[1:], w=[1..1000])
333
"""
334
if isinstance(v, tuple) and w is None:
335
v, cutoff, w, pari_precode, max_imaginary_part, max_asymp_coeffs = v
336
337
self.__init = (v, cutoff, w, pari_precode, max_imaginary_part, max_asymp_coeffs)
338
gp = self.gp()
339
if pari_precode != '':
340
self._gp_eval(pari_precode)
341
RR = self.__CC._real_field()
342
cutoff = RR(cutoff)
343
if isinstance(v, str):
344
if w is None:
345
self._gp_eval('initLdata("%s", %s)'%(v, cutoff))
346
return
347
self._gp_eval('initLdata("%s",%s,"%s")'%(v,cutoff,w))
348
return
349
if not isinstance(v, (list, tuple)):
350
raise TypeError, "v (=%s) must be a list, tuple, or string"%v
351
CC = self.__CC
352
v = ','.join([CC(a)._pari_init_() for a in v])
353
self._gp_eval('Avec = [%s]'%v)
354
if w is None:
355
self._gp_eval('initLdata("Avec[k]", %s)'%cutoff)
356
return
357
w = ','.join([CC(a)._pari_init_() for a in w])
358
self._gp_eval('Bvec = [%s]'%w)
359
self._gp_eval('initLdata("Avec[k]",%s,"Bvec[k]")'%cutoff)
360
361
def __to_CC(self, s):
362
s = s.replace('.E','.0E').replace(' ','')
363
return self.__CC(sage_eval(s, locals={'I':self.__CC.gen(0)}))
364
365
def _clear_value_cache(self):
366
del self.__values
367
368
def __call__(self, s, c=None):
369
r"""
370
INPUT:
371
372
- ``s`` - complex number
373
374
.. note::
375
376
Evaluation of the function takes a long time, so each
377
evaluation is cached. Call ``self._clear_value_cache()`` to
378
clear the evaluation cache.
379
380
EXAMPLES::
381
382
sage: E = EllipticCurve('5077a')
383
sage: L = E.lseries().dokchitser(100)
384
sage: L(1)
385
0.00000000000000000000000000000
386
sage: L(1+I)
387
-1.3085436607849493358323930438 + 0.81298000036784359634835412129*I
388
"""
389
self.__check_init()
390
s = self.__CC(s)
391
try:
392
return self.__values[s]
393
except AttributeError:
394
self.__values = {}
395
except KeyError:
396
pass
397
z = self.gp().eval('L(%s)'%s)
398
if 'pole' in z:
399
print z
400
raise ArithmeticError
401
elif '***' in z:
402
print z
403
raise RuntimeError
404
elif 'Warning' in z:
405
i = z.rfind('\n')
406
msg = z[:i].replace('digits','decimal digits')
407
verbose(msg, level=-1)
408
ans = self.__to_CC(z[i+1:])
409
self.__values[s] = ans
410
return ans
411
ans = self.__to_CC(z)
412
self.__values[s] = ans
413
return ans
414
415
def derivative(self, s, k=1):
416
r"""
417
Return the `k`-th derivative of the `L`-series at
418
`s`.
419
420
.. warning::
421
422
If `k` is greater than the order of vanishing of
423
`L` at `s` you may get nonsense.
424
425
EXAMPLES::
426
427
sage: E = EllipticCurve('389a')
428
sage: L = E.lseries().dokchitser()
429
sage: L.derivative(1,E.rank())
430
1.51863300057685
431
"""
432
self.__check_init()
433
s = self.__CC(s)
434
k = Integer(k)
435
z = self.gp().eval('L(%s,,%s)'%(s,k))
436
if 'pole' in z:
437
raise ArithmeticError, z
438
elif 'Warning' in z:
439
i = z.rfind('\n')
440
msg = z[:i].replace('digits','decimal digits')
441
verbose(msg, level=-1)
442
return self.__CC(z[i:])
443
return self.__CC(z)
444
445
446
def taylor_series(self, a=0, k=6, var='z'):
447
r"""
448
Return the first `k` terms of the Taylor series expansion
449
of the `L`-series about `a`.
450
451
This is returned as a series in ``var``, where you
452
should view ``var`` as equal to `s-a`. Thus
453
this function returns the formal power series whose coefficients
454
are `L^{(n)}(a)/n!`.
455
456
INPUT:
457
458
459
- ``a`` - complex number (default: 0); point about
460
which to expand
461
462
- ``k`` - integer (default: 6), series is
463
`O(``var``^k)`
464
465
- ``var`` - string (default: 'z'), variable of power
466
series
467
468
469
EXAMPLES::
470
471
sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
472
sage: L.taylor_series(2, 3)
473
1.64493406684823 - 0.937548254315844*z + 0.994640117149451*z^2 + O(z^3)
474
sage: E = EllipticCurve('37a')
475
sage: L = E.lseries().dokchitser()
476
sage: L.taylor_series(1)
477
0.000000000000000 + 0.305999773834052*z + 0.186547797268162*z^2 - 0.136791463097188*z^3 + 0.0161066468496401*z^4 + 0.0185955175398802*z^5 + O(z^6)
478
479
We compute a Taylor series where each coefficient is to high
480
precision.
481
482
::
483
484
sage: E = EllipticCurve('389a')
485
sage: L = E.lseries().dokchitser(200)
486
sage: L.taylor_series(1,3)
487
6.2240188634103774348273446965620801288836328651973234573133e-73 + (-3.527132447498646306292650465494647003849868770...e-73)*z + 0.75931650028842677023019260789472201907809751649492435158581*z^2 + O(z^3)
488
"""
489
self.__check_init()
490
a = self.__CC(a)
491
k = Integer(k)
492
try:
493
z = self.gp()('Vec(Lseries(%s,,%s))'%(a,k-1))
494
except TypeError, msg:
495
raise RuntimeError, "%s\nUnable to compute Taylor expansion (try lowering the number of terms)"%msg
496
r = repr(z)
497
if 'pole' in r:
498
raise ArithmeticError, r
499
elif 'Warning' in r:
500
i = r.rfind('\n')
501
msg = r[:i].replace('digits','decimal digits')
502
verbose(msg, level=-1)
503
v = list(z)
504
K = self.__CC
505
v = [K(repr(x)) for x in v]
506
R = self.__CC[[var]]
507
return R(v,len(v))
508
509
def check_functional_equation(self, T=1.2):
510
r"""
511
Verifies how well numerically the functional equation is satisfied,
512
and also determines the residues if ``self.poles !=
513
[]`` and residues='automatic'.
514
515
More specifically: for `T>1` (default 1.2),
516
``self.check_functional_equation(T)`` should ideally
517
return 0 (to the current precision).
518
519
520
- if what this function returns does not look like 0 at all,
521
probably the functional equation is wrong (i.e. some of the
522
parameters gammaV, conductor etc., or the coefficients are wrong),
523
524
- if checkfeq(T) is to be used, more coefficients have to be
525
generated (approximately T times more), e.g. call cflength(1.3),
526
initLdata("a(k)",1.3), checkfeq(1.3)
527
528
- T=1 always (!) returns 0, so T has to be away from 1
529
530
- default value `T=1.2` seems to give a reasonable
531
balance
532
533
- if you don't have to verify the functional equation or the
534
L-values, call num_coeffs(1) and initLdata("a(k)",1), you need
535
slightly less coefficients.
536
537
538
EXAMPLES::
539
540
sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
541
sage: L.check_functional_equation()
542
-1.35525271600000e-20 # 32-bit
543
-2.71050543121376e-20 # 64-bit
544
545
If we choose the sign in functional equation for the
546
`\zeta` function incorrectly, the functional equation
547
doesn't check out.
548
549
::
550
551
sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=-11, poles=[1], residues=[-1], init='1')
552
sage: L.check_functional_equation()
553
-9.73967861488124
554
"""
555
self.__check_init()
556
z = self.gp().eval('checkfeq(%s)'%T).replace(' ','')
557
return self.__CC(z)
558
559
def set_coeff_growth(self, coefgrow):
560
r"""
561
You might have to redefine the coefficient growth function if the
562
`a_n` of the `L`-series are not given by the
563
following PARI function::
564
565
coefgrow(n) = if(length(Lpoles),
566
1.5*n^(vecmax(real(Lpoles))-1),
567
sqrt(4*n)^(weight-1));
568
569
570
INPUT:
571
572
573
- ``coefgrow`` - string that evaluates to a PARI
574
function of n that defines a coefgrow function.
575
576
577
EXAMPLE::
578
579
sage: L = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
580
sage: pari_precode = 'tau(n)=(5*sigma(n,3)+7*sigma(n,5))*n/12 - 35*sum(k=1,n-1,(6*k-4*(n-k))*sigma(k,3)*sigma(n-k,5))'
581
sage: L.init_coeffs('tau(k)', pari_precode=pari_precode)
582
sage: L.set_coeff_growth('2*n^(11/2)')
583
sage: L(1)
584
0.0374412812685155
585
"""
586
if not isinstance(coefgrow, str):
587
raise TypeError, "coefgrow must be a string"
588
g = self.gp()
589
g.eval('coefgrow(n) = %s'%(coefgrow.replace('\n',' ')))
590
591
592
def reduce_load_dokchitser(D):
593
X = Dokchitser(1,1,1,1)
594
X.__dict__ = D
595
X.init_coeffs(X._Dokchitser__init)
596
return X
597
598