Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
241818 views
1
# -*- coding: utf-8 -*-
2
#*****************************************************************************
3
# Copyright (C) 2010 Fredrik Strömberg <[email protected]>,
4
#
5
# Distributed under the terms of the GNU General Public License (GPL)
6
#
7
# This code is distributed in the hope that it will be useful,
8
# but WITHOUT ANY WARRANTY; without even the implied warranty of
9
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
# General Public License for more details.
11
#
12
# The full text of the GPL is available at:
13
#
14
# http://www.gnu.org/licenses/
15
#*****************************************************************************
16
17
18
#from sage.all_cmdline import * # import sage library
19
#import mpmath as mpmath
20
#import mpmath as mpmath
21
from sage.structure.element import Element
22
from sage.structure.parent import Parent
23
from sage.structure.sage_object import SageObject,cPickle
24
#from mpmath import mpf
25
from sage.functions.all import ln,sqrt,floor
26
from sage.rings.arith import divisors,gcd
27
from sage.modular.dirichlet import DirichletGroup
28
from sage.rings.all import RR
29
# needed for attaching the file locally
30
##import __main__
31
from sage.modular.arithgroup.all import Gamma0
32
33
from maass_forms_alg import *
34
r"""
35
Maass waveforms for subgroups of the modular group
36
37
AUTHORS:
38
39
- Fredrik Strömberg (March 2010)
40
41
EXAMPLES::
42
43
44
?
45
46
47
TODO:
48
- Nontrivial multiplier systems and weights
49
- improve eigenvalue finding alorithms
50
51
52
"""
53
54
55
#load "maass_forms_alg.pyx"
56
57
58
class MaassWaveForms (Parent):
59
r"""
60
Describes a space of Maass waveforms
61
"""
62
def __init__(self,G,prec=500,verbose=None):
63
r"""
64
Creates an ambient space of Maass waveforms
65
(i.e. there are apriori no members).
66
67
INPUT:
68
69
- `'G`` -- subgroup of the modular group
70
- ``prec`` -- default working precision in bits
71
72
EXAMPLES::
73
74
75
sage: S=MaassWaveForms(Gamma0(1)); S
76
Space of Maass waveforms on the group G:
77
Arithmetic Subgroup of PSL2(Z) with index 1. Given by:
78
perm(S)=()
79
perm(ST)=()
80
Constructed from G=Modular Group SL(2,Z)
81
82
"""
83
from mysubgroup import MySubgroup
84
if(not isinstance(G, MySubgroup)):
85
if(isinstance(G,int) or isinstance(G,sage.rings.integer.Integer)):
86
self._G=MySubgroup(Gamma0(G))
87
else:
88
try:
89
self._G=MySubgroup(G)
90
except TypeError:
91
raise TypeError,"Incorrect input!! Need subgroup of PSL2Z! Got :%s" %(G)
92
else:
93
self._G=G
94
95
self.verbose=verbose
96
self.prec=prec
97
self._Weyl_law_const=self._Weyl_law_consts()
98
maass_forms=dict() # list of members
99
if(verbose==None):
100
self._verbose=0 # output debugging stuff or not
101
else:
102
self._verbose=verbose
103
self._symmetry=None
104
105
def _repr_(self):
106
r"""
107
Return the string representation of self.
108
109
EXAMPLES::
110
111
112
sage: M=MaassWaveForms(MySubgroup(Gamma0(1)));M
113
Space of Maass waveforms on the group G:
114
Arithmetic Subgroup of PSL2(Z) with index 1. Given by:
115
perm(S)=()
116
perm(ST)=()
117
Constructed from G=Modular Group SL(2,Z)
118
119
120
"""
121
s="Space of Maass waveforms on the group G:\n"+str(self._G)
122
return s
123
124
def __reduce__(self):
125
r""" Used for pickling.
126
"""
127
return(MaassWaveForms,(self._G,self.prec,self.verbose))
128
129
def __cmp__(self,other):
130
r""" Compare self to other
131
"""
132
if(self._G <> other._G or self.prec<>other.prec):
133
return False
134
else:
135
return True
136
137
def get_element_in_range(self,R1,R2,ST=None,neps=10):
138
r""" Finds element of the space self with R in the interval R1 and R2
139
140
INPUT:
141
142
- ``R1`` -- lower bound (real)
143
- ``R1`` -- upper bound (real)
144
145
"""
146
if(ST <>None):
147
ST0=ST
148
else:
149
ST0=self._ST
150
l=self.split_interval(R1,R2)
151
if(self._verbose>1):
152
print "Split into intervals:"
153
for [r1,r2,y] in l:
154
print "[",r1,",",r2,"]:",y
155
Rl=list()
156
for [r1,r2,y] in l:
157
[R,er]=find_single_ev(self,r1,r2,Yset=y,ST=ST0,neps=neps)
158
Rl.append([R,er])
159
print "R=",R
160
print "er=",er
161
162
163
def _Weyl_law_consts(self):
164
r"""
165
Compute constants for the Weyl law on self._G
166
167
OUTPUT:
168
169
- tuple of real numbers
170
171
EXAMPLES::
172
173
174
sage: M=MaassWaveForms(MySubgroup(Gamma0(1)))
175
sage: M._Weyl_law_consts()
176
(0, 2/pi, (log(pi) - log(2) + 2)/pi, 0, -2)
177
"""
178
import mpmath
179
pi=mpmath.fp.pi
180
ix=Integer(self._G.index())
181
nc=Integer(len(self._G.cusps()))
182
if(self._G.is_congruence()):
183
lvl=Integer(self._G.level())
184
else:
185
lvl=0
186
n2=Integer(self._G.nu2())
187
n3=Integer(self._G.nu3())
188
c1=ix/Integer(12)
189
c2=Integer(2)*nc/pi
190
c3=nc*(Integer(2)-ln(Integer(2))+ln(pi))/pi
191
if(lvl<>0):
192
A=1
193
for q in divisors(lvl):
194
num_prim_dc=0
195
DG=DirichletGroup(q)
196
for chi in DG.list():
197
if(chi.is_primitive()):
198
num_prim_dc=num_prim_dc+1
199
for m in divisors(lvl):
200
if(lvl % (m*q) == 0 and m % q ==0 ):
201
fak=(q*lvl)/gcd(m,lvl/m)
202
A=A*Integer(fak)**num_prim_dc
203
c4=-ln(A)/pi
204
else:
205
c4=Integer(0)
206
# constant term
207
c5=-ix/144+n2/8+n3*2/9-nc/4-1
208
return (c1,c2,c3,c4,c5)
209
210
def Weyl_law_N(self,T,T1=None):
211
r"""
212
The counting function for this space. N(T)=#{disc. ev.<=T}
213
214
INPUT:
215
216
- ``T`` -- double
217
218
219
EXAMPLES::
220
221
sage: M=MaassWaveForms(MySubgroup(Gamma0(1))
222
sage: M.Weyl_law_N(10)
223
0.572841337202191
224
225
"""
226
(c1,c2,c3,c4,c5)=self._Weyl_law_const
227
cc1=RR(c1); cc2=RR(c2); cc3=RR(c3); cc4=RR(c4); cc5=RR(c5)
228
#print "c1,c2,c3,c4,c5=",cc1,cc2,cc3,cc4,cc5
229
t=sqrt(T*T+0.25)
230
try:
231
lnt=ln(t)
232
except TypeError:
233
lnt=mpmath.ln(t)
234
#print "t,ln(t)=",t,lnt
235
NT=cc1*t*t-cc2*t*lnt+cc3*t+cc4*t+cc5
236
if(T1<>None):
237
t=sqrt(T1*T1+0.25)
238
NT1=cc1*(T1*T1+0.25)-cc2*t*ln(t)+cc3*t+cc4*t+cc5
239
return RR(abs(NT1-NT))
240
else:
241
return RR(NT)
242
243
def next_eigenvalue(self,R):
244
r"""
245
An estimate of where the next eigenvlue will be, i.e. the smallest R1>R so that N(R1)-N(R)>=1
246
247
INPUT:
248
- ``R`` -- real > 0
249
250
OUTPUT:
251
- real > R
252
253
EXAMPLES::
254
255
sage: M.next_eigenvalue(10.0)
256
12.2500000000000
257
258
259
"""
260
#cdef nmax
261
N=self.Weyl_law_N(R)
262
try:
263
for j in range(1,10000):
264
R1=R+j*RR(j)/100.0
265
N1=self.Weyl_law_N(R1)
266
if(N1-N >= 1.0):
267
raise StopIteration()
268
except StopIteration:
269
return R1
270
else:
271
raise ArithmeticError,"Could not find next eigenvalue! in interval: [%s,%s]" %(R,R1)
272
273
def Weyl_law_Np(self,T,T1=None):
274
r"""
275
The derviative of the counting function for this space. N(T)=#{disc. ev.<=T}
276
277
INPUT:
278
279
- ``T`` -- double
280
281
282
EXAMPLES::
283
284
sage: M=MaassWaweForms(MySubgroup(Gamma0(1))
285
sage: M.Weyl_law_Np(10)
286
287
"""
288
(c1,c2,c3,c4,c5)=self._Weyl_law_const
289
cc1=RR(c1); cc2=RR(c2); cc3=RR(c3); cc4=RR(c4); cc5=RR(c5)
290
#print "c1,c2,c3,c4,c5=",c1,c2,c3,c4,c5
291
NpT=2.0*cc1*T-cc2*(ln(T)+1.0)+cc3+cc4
292
return RR(NpT)
293
294
295
#### Split an interv
296
def split_interval(self,R1,R2):
297
r"""
298
Split an interval into pieces, each containing (on average) at most one
299
eigenvalue as well as a 0<Y<Y0 s.t. K_IR(Y) has no zero here
300
301
INPUT:
302
303
- ''R1'' -- real
304
- ''R2'' -- real
305
306
OUPUT:
307
308
- list of triplets (r1,r2,y) where [r1,r2] does not contain a zero of K_ir(y)
309
310
EXAMPLES::
311
312
313
sage: M._next_kbes
314
sage: l=M.split_interval(9.0,11.0)
315
sage: print l[0],'\n',l[1],'\n',l[2],'\n',l[3]
316
(9.00000000000000, 9.9203192604549457, 0.86169527676551638)
317
(9.9203192704549465, 10.135716354265259, 0.86083358148875089)
318
(10.13571636426526, 10.903681677771321, 0.86083358148875089)
319
(10.903681687771321, 11.0000000000000, 0.85997274790726208)
320
321
"""
322
# It is enough to work with double precision
323
base=mpmath.fp
324
pi=base.pi
325
# Locate all zeros of K_IR(Y0) first
326
#def f(r):
327
# ir=base.mpc(0 ,r)
328
# return base.besselk(ir,Y0)
329
# First we find the next zero
330
# First split into intervals having at most one zero
331
ivs=list()
332
rnew=R1; rold=R1
333
while (rnew < R2):
334
rnew=min(R2,self.next_eigenvalue(rold))
335
if( abs(rold-rnew)==0.0):
336
print "ivs=",ivs
337
exit
338
iv=(rold,rnew)
339
ivs.append(iv)
340
rold=rnew
341
342
# We now need to split these intervals into pieces with at most one zero of the K-Bessel function
343
Y00=base.mpf(0.995)*base.sqrt(base.mpf(3))/base.mpf(2 *self._G._level)
344
new_ivs=list()
345
for (r1,r2) in ivs:
346
print "r1,r2=",r1,r2
347
Y0=Y00; r11=r1
348
i=0
349
while(r11 < r2 and i<1000):
350
t=self._next_kbessel_zero(r11,r2,Y0*pi);i=i+1
351
print "t=",t
352
iv=(r11,t,Y0); new_ivs.append(iv)
353
# must find Y0 s.t. |besselk(it,Y0)| is large enough
354
Y1=Y0
355
k=base.besselk(base.mpc(0,t),Y1).real*mpmath.exp(t*0.5*base.pi)
356
j=0
357
while(j<1000 and abs(k)<1e-3):
358
Y1=Y1*0.999;j=j+1
359
k=base.besselk(base.mpc(0,t),Y1).real*mpmath.exp(t*0.5*base.pi)
360
Y0=Y1
361
r11=t+1E-08
362
return new_ivs
363
364
365
def _next_kbessel_zero(self,r1,r2,y):
366
r"""
367
The first zero after r1 i the interval [r1,r2] of K_ir(y),K_ir(2y)
368
369
INPUT:
370
371
- ´´r1´´ -- double
372
- ´´r2´´ -- double
373
- ´´y´´ -- double
374
375
OUTPUT:
376
377
- ''double''
378
379
EXAMPLES::
380
381
382
sage: M=MaassWaveForms(MySubgroup(Gamma0(1)))
383
sage: Y0=0.995*sqrt(3.0)/2.0
384
sage: M._next_kbessel_zero(9.0,15.0,Y0)
385
9.9203192604549439
386
sage: M._next_kbessel_zero(9.921,15.0,Y0)
387
10.139781183668587
388
389
390
CAVEAT:
391
The rootfinding algorithm is not very sophisticated and might miss roots
392
393
"""
394
base=mpmath.fp
395
h=(r2-r1)/500.0
396
t1=-1.0; t2=-1.0
397
r0=base.mpf(r1)
398
kd0=my_mpmath_kbes_diff_r(r0,y,base)
399
#print "r0,y=",r0,y,kd0
400
while(t1<r1 and r0<r2):
401
402
# Let us first find a R-value for which the derivative changed sign
403
kd=my_mpmath_kbes_diff_r(r0,y,base)
404
i=0
405
while(kd*kd0>0 and i<500 and r0<r2):
406
i=i+1
407
r0=r0+h
408
kd=my_mpmath_kbes_diff_r(r0,y,base)
409
#print "r0,kd=",r0,kd
410
#print "kd*kd0=",kd*kd0
411
#print "-r0,y,kd=",r0,y,kd
412
#t1=base.findroot(lambda x : base.besselk(base.mpc(0,x),base.mpf(y),verbose=True).real,r0)
413
try:
414
t1=base.findroot(lambda x : my_mpmath_kbes(x,y,base),r0)
415
except ValueError:
416
t1=base.findroot(lambda x : my_mpmath_kbes(x,y,mpmath.mp),r0)
417
r0=r0+h
418
if(r0>=r2 or t1>=r2):
419
t1=r2
420
r0=r1
421
kd0=my_mpmath_kbes_diff_r(r0,y,base)
422
while(t2<r1 and r0<r2):
423
kd=my_mpmath_kbes_diff_r(r0,y,base)
424
i=0
425
while(kd*kd0>0 and i<500 and r0<r2):
426
i=i+1
427
r0=r0+h
428
kd=my_mpmath_kbes_diff_r(r0,y,base)
429
try:
430
t2=base.findroot(lambda x : my_mpmath_kbes(x,2*y,base),r0)
431
except ValueError:
432
t2=base.findroot(lambda x : my_mpmath_kbes(x,2*y,mpmath.mp),r0)
433
#t2=base.findroot(lambda x : base.besselk(base.mpc(0,x),base.mpf(2*y),verbose=True).real,r0)
434
r0=r0+h
435
if(r0>=r2 or t2>=r2):
436
t2=r2
437
#print "zero(besselk,y1,y2)(",r1,r2,")=",t1,t2
438
t=min(min(max(r1,t1),max(r1,t2)),r2)
439
return t
440
441
442
443
def my_mpmath_kbes(r,x,mp_ctx=None):
444
r"""Scaled K-Bessel function with
445
446
INPUT:
447
448
- ''r'' -- real
449
- ''x'' -- real
450
- ''mp_ctx'' -- mpmath context (default None)
451
452
OUTPUT:
453
454
- real -- K_ir(x)*exp(pi*r/2)
455
456
EXAMPLES::
457
458
459
sage: my_mpmath_kbes(9.0,1.0)
460
mpf('-0.71962866121965863')
461
sage: my_mpmath_kbes(9.0,1.0,mpmath.fp)
462
-0.71962866121967572
463
464
465
466
"""
467
import mpmath
468
if(mp_ctx==None):
469
mp_ctx=mpmath.mp
470
if(mp_ctx==mpmath.mp):
471
pi=mpmath.mp.pi()
472
else:
473
pi=mpmath.fp.pi
474
try:
475
k=mp_ctx.besselk(ctx.mpc(0,r),ctx.mpf(x))
476
f=k*mp_ctx.exp(r*ctx.mpf(0.5)*pi)
477
except OverflowError:
478
k=mp_cyx.besselk(mp_ctx.mpc(0,r),mp_ctx.mpf(x))
479
f=k*mp_ctx.exp(r*mp_ctx.mpf(0.5)*pi)
480
return f.real
481
482
def my_mpmath_kbes_diff_r(r,x,mp_ctx=None):
483
r"""
484
Derivative with respect to R of the scaled K-Bessel function.
485
486
INPUT:
487
488
- ''r'' -- real
489
- ''x'' -- real
490
- ''ctx'' -- mpmath context (default mpmath.mp)
491
492
OUTPUT:
493
494
- real -- K_ir(x)*exp(pi*r/2)
495
496
EXAMPLES::
497
498
499
sage: my_mpmath_kbes_diff_r(9.45,0.861695276766 ,mpmath.fp)
500
-0.31374673969963851
501
sage: my_mpmath_kbes_diff_r(9.4,0.861695276766 ,mpmath.fp)
502
0.074219541623676832
503
504
505
"""
506
import mpmath
507
if(mp_ctx==None):
508
mp_ctx=mpmath.mp
509
if(mp_ctx==mpmath.mp):
510
pi=mpmath.mp.pi()
511
else:
512
pi=mpmath.fp.pi
513
try:
514
k=mp_ctx.besselk(ctx.mpc(0,r),ctx.mpf(x))
515
f=k*mp_ctx.exp(r*ctx.mpf(0.5)*pi)
516
except OverflowError:
517
k=mp_ctx.besselk(mp_ctx.mpc(0,r),mp_ctx.mpf(x))
518
f=k*mp_ctx.exp(r*mp_ctx.mpf(0.5)*pi)
519
f1=f.real
520
try:
521
h=mp_ctx.mpf(1e-8)
522
k=mp_ctx.besselk(mp_ctx.mpc(0,r+h),mp_ctx.mpf(x))
523
f=k*mp_ctx.exp((r+h)*mp_ctx.mpf(0.5)*pi)
524
except OverflowError:
525
h=mp_ctx.mpf(1e-8)
526
k=mp_ctx.besselk(mp_ctx.mpc(0,r+h),mp_ctx.mpf(x))
527
f=k*mp_ctx.exp((r+h)*mp_ctx.mpf(0.5)*pi)
528
f2=f.real
529
diff=(f2-f1)/h
530
return diff
531
532
#class MaassWaveformElement (SageObject):
533
class MaassWaveformElement (Parent):
534
r"""
535
An element of a space of Maass waveforms
536
537
EXAMPLES::
538
539
sage: G=MySubgroup(Gamma0(1))
540
sage: R=mpmath.mpf(9.53369526135355755434423523592877032382125639510725198237579046413534)
541
sage: F=MaassWaveformElement(G,R)
542
Maass waveform with parameter R=9.5336952613536
543
in Space of Maass waveforms on the group G:
544
Arithmetic Subgroup of PSL2(Z) with index 1. Given by:
545
perm(S)=()
546
perm(ST)=()
547
Constructed from G=Modular Group SL(2,Z)
548
sage: G=MySubgroup(Gamma0(4))
549
sage: R=mpmath.mpf(3.70330780121891)
550
sage: F=MaassWaveformElement(G,R);F
551
Maass waveform with parameter R=3.70330780121891
552
Member of the Space of Maass waveforms on the group G:
553
Arithmetic Subgroup of PSL2(Z) with index 6. Given by:
554
perm(S)=(1,2)(3,4)(5,6)
555
perm(ST)=(1,3,2)(4,5,6)
556
Constructed from G=Congruence Subgroup Gamma0(4)
557
sage: F.C(0,-1)
558
mpc(real='-1.0000000000014575', imag='5.4476887980094281e-13')
559
sage: F.C(0,15)-F.C(0,5)*F.C(0,3)
560
mpc(real='-5.938532886679327e-8', imag='-1.0564743382278074e-8')
561
sage: F.C(0,3)
562
mpc(real='0.53844676975670527', imag='-2.5525466782958545e-13')
563
sage: F.C(1,3)
564
mpc(real='-0.53844676975666916', imag='2.4484251009604091e-13')
565
sage: F.C(2,3)
566
mpc(real='-0.53844676975695485', imag='3.3624257152434837e-13')
567
568
569
570
571
572
"""
573
def __init__(self,G,R,C=None,nd=12,sym_type=None,verbose=0):
574
r"""
575
Construct a Maass waveform on thegroup G with spectral parameter R and coefficients C
576
577
INPUT:
578
- ``G`` -- Group
579
- ``R`` -- Spectral parameter
580
- ``C`` -- Fourier coefficients (default None)
581
- ``nd``-- Number of desired digits (default 15)
582
"""
583
import mpmath
584
self._space= MaassWaveForms (G)
585
self._group=self._space._G
586
self._R=R
587
self._nd=nd
588
self._sym_type=sym_type
589
self._space._verbose=verbose
590
if(nd>15):
591
mpmath.mp.dps=nd
592
self.mp_ctx=mpmath.mp
593
else:
594
self.mp_ctx=mpmath.fp
595
## We use the Fourier coefficients to verify whether we really have an eigenvalue
596
if(C<>None):
597
self.coeffs=C
598
er=self.test(C)
599
else:
600
#print "Need to compute coefficients!"
601
# We compute a set of Fourier coefficients
602
#(Y,M)=find_Y_and_M(G,R)
603
#Q=M+10
604
self.coeffs=Maassform_coeffs(self._space,R,ndigs=self._nd)[0]
605
606
607
def _repr_(self):
608
r""" Returns string representation of self.
609
610
EXAMPLES::
611
612
613
sage: R=mpmath.mpf(9.53369526135355755434423523592877032382125639510725198237579046413534)
614
sage: F=MaassWaveformElement(Gamma0(1),R,nd=50);F
615
Maass waveform with parameter R=9.5336952613535575543442352359287703238212563951073
616
Member of the Space of Maass waveforms on the group G:
617
Arithmetic Subgroup of PSL2(Z) with index 1.Given by
618
perm(S)=()
619
perm(ST)=()
620
Constructed from G=Modular Group SL(2,Z)
621
622
623
"""
624
s="Maass waveform with parameter R="+str(self._R)+"\nMember of the "+str(self._space)
625
return s
626
627
628
def __reduce__(self):
629
r""" Used for pickling.
630
"""
631
return(MaassWaveformElement,(self._group,self._R,self.coeffs,self._nd))
632
633
def group():
634
r"""
635
Return self._group
636
"""
637
return self._group
638
639
def eigenvalue():
640
return self._R #eigenvalue
641
642
def C(self,i,j=None):
643
r"""
644
Return the coefficient C(i,j) i.e. coefficient nr. j at cusp i (or if j=none C(1,i))
645
646
647
EXAMPLES::
648
649
650
sage: G=MySubgroup(Gamma0(1))
651
sage: R=mpmath.mpf(9.53369526135355755434423523592877032382125639510725198237579046413534)
652
sage: F=MaassWaveformElement(G,R)
653
sage: F.C(2)
654
mpc(real='-1.068333551223568', imag='2.5371356217909904e-17')
655
sage: F.C(3)
656
mpc(real='-0.45619735450601293', imag='-7.4209294760716175e-16')
657
sage: F.C(2)*F.C(3)-F.C(6)
658
mpc(real='8.2470016583210667e-8', imag='1.6951583479643061e-9')
659
660
661
"""
662
if(j==None):
663
cusp=0
664
j=i
665
else:
666
cusp=i
667
if(not self.coeffs.has_key(cusp)):
668
raise ValueError," Need a valid index of a cusp as first argument! I.e in %s" %self.coeffs.keys()
669
if(not self.coeffs[cusp].has_key(j)):
670
return None
671
return self.coeffs[cusp][j]
672
673
def test(self,do_twoy=False,up_to_M=0):
674
r""" Return the number of digits we believe are correct (at least)
675
676
EXAMPLES::
677
678
679
sage: G=MySubgroup(Gamma0(1))
680
sage: R=mpmath.mpf(9.53369526135355755434423523592877032382125639510725198237579046413534)
681
sage: F=MaassWaveformElement(G,R)
682
sage: F.test()
683
7
684
685
686
687
"""
688
# If we have a Gamma_0(N) we can use Hecke operators
689
if(not do_twoy and (isinstance(self._space,sage.modular.arithgroup.congroup_gamma0.Gamma0_class) or \
690
self._space._G.is_congruence)):
691
# isinstance(self._space,sage.modular.arithgroup.congroup_sl2z.SL2Z_class_with_category))):
692
if(self._space._verbose>1):
693
print "Check Hecke relations!"
694
er=test_Hecke_relations(2,3,self.coeffs)
695
d=floor(-mpmath.log10(er))
696
if(self._space._verbose>1):
697
print "Hecke is ok up to ",d,"digits!"
698
return d
699
else:
700
# Test two Y's
701
nd=self._nd+5
702
[M0,Y0]=find_Y_and_M(G,R,nd)
703
Y1=Y0*0.95
704
C1=Maassform_coeffs(self,R,Mset=M0,Yset=Y0 ,ndigs=nd )[0]
705
C2=Maassform_coeffs(self,R,Mset=M0,Yset=Y1 ,ndigs=nd )[0]
706
er=mpmath.mpf(0)
707
for j in range(2,max(M0/2,up_to_M)):
708
t=abs(C1[j]-C2[j])
709
print "|C1-C2[",j,"]|=|",C1[j],'-',C2[j],'|=',t
710
if(t>er):
711
er=t
712
d=floor(-mpmath.log10(er))
713
print "Hecke is ok up to ",d,"digits!"
714
return d
715
716
def Maassform_coeffs(S,R,Mset=0 ,ST=None ,ndigs=12,twoy=None):
717
r"""
718
Compute M Fourier coefficients (at each cusp) of a Maass (cusp)
719
waveform with eigenvalue R for the group G.
720
721
722
INPUT:
723
724
- ''S'' -- space of Maass waveforms
725
- ''R'' -- Real number with precision prec
726
- ''Mset'' -- integer : number of desired coefficients
727
- ''ST'' -- set symmetry
728
- ''Yset'' -- real
729
- ''ndigs''-- integer
730
731
732
OUTPUT:
733
734
-''D'' -- dictionary of Fourier coefficients
735
736
EXAMPLES:
737
738
739
sage: R=mpmath.mpf(9.53369526135355755434423523592877032382125639510725198237579046413534)
740
sage: sage: M=MaassWaveForms(Gamma0(1))
741
sage: sage: C=Maassform_coeffs(M,R)
742
743
744
"""
745
G=S._G
746
if(S._verbose>1):
747
print "S=",S
748
[YY,M0]=find_Y_and_M(G,R,ndigs)
749
if(ndigs>=15):
750
Y=mpmath.mp.mpf(YY)
751
else:
752
Y=YY
753
#print "M,Y=",M0,Y0
754
#if(Yset<>None and Yset<=Y0):
755
# Y=Yset
756
#else:
757
# Y=Y0
758
if(Mset>=M0):
759
M=Mset
760
else:
761
M=M0
762
if(ST<>None):
763
if(ST.has_key('sym_type')):
764
sym_type=ST['sym_type']
765
else:
766
sym_type=False
767
else:
768
sym_type=None
769
Q=M+10
770
dold=mpmath.mp.dps
771
###mpmath.mp.dps=ndigs+2 # We work with low precision initially
772
if(S._verbose>1):
773
print "R,Y,M,Q=",R,Y,M,Q
774
#print "sym_type=",sym_type
775
#print "nd=",mpmath.mp.dps
776
X = coefficients_for_Maass_waveforms(S,R,Y,M,Q,ndigs,cuspidal=True,sym_type=sym_type)
777
return X
778
779
780
781
def coefficients_for_Maass_waveforms(S,R,Y,M,Q,ndigs,cuspidal=True,sym_type=None):
782
r"""
783
Compute coefficients of a Maass waveform given a specific M and Y.
784
INPUT:
785
786
- ''S'' -- Space of Maass waveforms
787
- ''R'' -- real : 1/4+R*R is the eigenvalue
788
- ''Y'' -- real number > 9
789
- ''M'' -- integer
790
- ''Q'' -- integer
791
- ''cuspidal''-- logical (default True)
792
- ''sym_type'' -- integer (default None)
793
- ''ndigs''-- integer : desired precision
794
795
OUTPUT:
796
797
-''D'' -- dictionary of Fourier coefficients
798
799
800
EXAMPLES::
801
802
sage: S=MaassWaveForms(Gamma0(1))
803
sage: R=mpmath.mpf(9.53369526135355755434423523592877032382125639510725198237579046413534)
804
sage: Y=mpmath.mpf(0.85)
805
sage: C=coefficients_for_Maass_waveforms(S,R,Y,10,20,12)
806
807
808
809
"""
810
G=S._G
811
if(ndigs<=12):
812
W=setup_matrix_for_Maass_waveforms(G,R,Y,M,Q,cuspidal=True,sym_type=sym_type,low_prec=True)
813
else:
814
W=setup_matrix_for_Maass_waveforms(G,R,Y,M,Q,cuspidal=True,sym_type=sym_type)
815
dim=1
816
N=set_norm_maass(dim,cuspidal=True)
817
#return [W, N]
818
dold=mpmath.mp.dps
819
mpmath.mp.dps=max(dold,50) # We work with low precision initially
820
if(S._verbose>1):
821
deb=True
822
else:
823
deb=False
824
done=False; j=0
825
while(done==False and j<=10):
826
if(S._verbose>1):
827
print "Trying to solve with prec=",mpmath.mp.dps
828
try:
829
X=solve_system_for_Maass_waveforms(W,N,deb=deb)
830
except ZeroDivisionError:
831
pass
832
if(is_Integer(X) or isinstance(X,int)):
833
mpmath.mp.dps=X+5
834
elif(isinstance(X,dict)):
835
done=True
836
else:
837
raise ArithmeticError," Could not solve system!"
838
j=j+1
839
if(S._verbose>1):
840
for m in range(dim):
841
print "Function nr. ",m+1
842
if(sym_type==None):
843
for n in range(M,1 ,-1 ):
844
print "C[",n,"]=",X[m][n]
845
for n in range(M):
846
print "C[",n,"]=",X[m][n]
847
else:
848
for n in range(1,M+1):
849
print "C[",n,"]=",X[m][n]
850
#print "C2=",X[0][2]
851
#print "c2c3-c6=",X[0][2]*X[0][3]-X[0][6]
852
mpmath.mp.dps=dold
853
return X
854
855
def verify_eigenvalue(S,R,nd=10,ST=None,method='TwoY'):
856
r""" Verify an eigenvalue and give an estimate of the error.
857
858
INPUT:
859
-''S'' -- Space of Maass waveforms
860
-''R'' -- real: (tentative) eigenvalue = 1/4+R**2
861
-''nd''-- integer : number of digits we try to get (at a minimum)
862
"""
863
C=Maassform_coeffs(S,R,ST=ST ,ndigs=nd)
864
865
866
867
868
869
def find_single_ev(S,R1in,R2in,Yset=None,ST=None,neps=10,method='TwoY',verbose=0):
870
r""" Locate a single eigenvalue on G between R1 and R2
871
872
INPUT:(tentative)
873
874
- ''S'' -- space of Maass waveforms
875
- ''R1in'' -- real
876
- ''R1in'' -- real
877
- ''Yset'' -- real (use this value of Y to compute coefficients)
878
- ''ST''' -- dictionary giving symmetry
879
- ''neps'' -- number of desired digits
880
881
OUPUT:
882
883
- ''R'' --
884
885
886
"""
887
G=S._G
888
jmax=1000 # maximal number of interation
889
if(neps>=15):
890
R1=mpmath.mp.mpf(R1in);R3=mpmath.mp.mpf(R2in)
891
print "mpmath.mp.dps=",mpmath.mp.dps
892
print "R1=",R1,type(R1)
893
print "R3=",R3,type(R3)
894
else:
895
R1=mpmath.fp.mpf(R1in);R3=mpmath.fp.mpf(R2in)
896
if(Yset==None):
897
[Y,M]=find_Y_and_M(G,R1,neps)
898
else:
899
[Y,M]=find_Y_and_M(G,R1,neps,Yset=Yset)
900
Y1=Y; Y2=mpmath.mpf(0.995)*Y1
901
tol=mpmath.mpf(10)**mpmath.mpf(-neps)
902
dold=mpmath.mp.dps
903
mpmath.mp.dps=neps+3 # We work with low precision initially
904
h=dict()
905
signs=dict();diffs=dict()
906
c=dict(); h=dict()
907
c[1]=2 ; c[2 ]=3 ; c[3 ]=4
908
#met='Hecke'
909
910
met=method
911
[diffs[1 ],h[1 ]]=functional(S,R1,M,Y1,Y2,signs,c,ST,first_time=True,method=met,ndigs=neps)
912
[diffs[3 ],h[3 ]]=functional(S,R3,M,Y1,Y2,signs,c,ST,first_time=True,method=met,ndigs=neps)
913
if(S._verbose>1):
914
print "diffs: met=",met
915
print "R1=",R1
916
print "R3=",R3
917
for n in list(c.keys()): #.sort():
918
for j in list(diffs.keys()): #.sort():
919
print "diff[",j,c[n],"]=",diffs[j][n]
920
# Sset signs and check zeros
921
if(met=='Hecke'):
922
if(h[1 ]*h[3]>mpmath.eps()):
923
# We do not have a signchange
924
return [0 ,0 ]
925
else:
926
var=0.0
927
for j in range(1 ,3 +1 ):
928
var+=abs(diffs[1 ][j])+abs(diffs[3 ][j])
929
print "var=",var
930
for j in range(1 ,3 +1 ):
931
signs[j]=1
932
if(diffs[1 ][j]*diffs[3 ][j]>mpmath.eps()):
933
# If we do not have a signchange
934
# and the absolute values are relatively large
935
# there is probably no zero here
936
if(abs(diffs[1][j])+abs(diffs[3][j]) > 0.01*var):
937
return [0 ,0 ]
938
elif(diffs[1 ][j]>0 ):
939
signs[j]=-1
940
# Recompute functionals using the signs
941
if(S._verbose>1):
942
print "h1=",h
943
print "diffs1=",diffs
944
print "signs=",signs
945
for k in [1,3]:
946
h[k]=0
947
for j in range(1,3+1):
948
h[k]=h[k]+signs[j]*diffs[k][j]
949
Rnew=prediction(h[1 ],h[3 ],R1,R3)
950
if(S._verbose>1):
951
print "h=",h
952
print "Rnew=",Rnew
953
[diffs[2],h[2]]=functional(S,Rnew,M,Y1,Y2,signs,c,ST,first_time=False,method=met,ndigs=neps)
954
zero_in=is_zero_in(h)
955
if(zero_in == -1 ):
956
R3=Rnew; h[3]=h[2 ]; diffs[3 ]=diffs[2 ]; errest=abs(Rnew-R1)
957
else:
958
R1=Rnew; h[1 ]=h[2 ]; diffs[1 ]=diffs[2 ]; errest=abs(Rnew-R3)
959
step=0
960
for j in range(100):
961
Rnew=prediction(h[1 ],h[3 ],R1,R3)
962
errest=max(abs(Rnew-R1),abs(Rnew-R3))
963
if(S._verbose>1):
964
print "R1,R3,Rnew,errest=",R1,R3,Rnew,errest
965
if(errest<tol):
966
return [Rnew,errest]
967
[diffs[2 ],h[2 ]]=functional(S,Rnew,M,Y1,Y2,signs,c,ST,first_time=False,method=met,ndigs=neps)
968
zero_in=is_zero_in(h)
969
if(zero_in==0):
970
return [Rnew,errest]
971
elif(zero_in not in [1,-1]):
972
raise StopIteration()
973
if(zero_in==-1):
974
stepz=abs(Rnew-R3)
975
R3=Rnew; h[3 ]=h[2 ]; diffs[3 ]=diffs[2 ]; errest=abs(Rnew-R1)
976
elif(zero_in==1):
977
stepz=abs(Rnew-R1)
978
R1=Rnew; h[1 ]=h[2 ]; diffs[1 ]=diffs[2 ]; errest=abs(Rnew-R3)
979
# If we have gone in the same direction too many times we need to modify our approach
980
step=step+zero_in
981
if(S._verbose>1):
982
print "step=",step
983
if(step>2): # Have gone too many times to the left
984
Rtest=Rnew + mpmath.mpf(0.5)*stepz # Need to test if this modified R3 work:
985
if(S._verbose>1):
986
print "Rtest(R)=",Rtest
987
[diffs[2 ],h[2 ]]=functional(S,Rtest,M,Y1,Y2,signs,c,ST,False,met,neps)
988
if(is_zero_in(h) ==-1): # all is ok
989
R3=Rtest; h[3]=h[2]; diffs[3]=diffs[2]; step=step-1
990
else: # Test another one
991
Rtest=Rnew + mpmath.mpf(0.5)*abs(R1-R3) # Need to test if this modified R3 work:
992
if(S._verbose>1):
993
print "Rtest(R)=",Rtest
994
[diffs[2 ],h[2 ]]=functional(G,Rtest,M,Y1,Y2,signs,c,ST,False,met,neps)
995
if(is_zero_in(h) ==-1): # all is ok
996
R3=Rtest; h[3]=h[2]; diffs[3]=diffs[2]; step=step-1
997
elif(step<-2): # Have gone too many times to the right
998
Rtest=Rnew - mpmath.mpf(0.5)*stepz
999
if(S._verbose>1):
1000
print "Rtest(L)=",Rtest
1001
[diffs[2 ],h[2 ]]=functional(S,Rtest,M,Y1,Y2,signs,c,ST,False,met,neps)
1002
if(is_zero_in(h) == 1): # all is ok
1003
R1=Rtest; h[1]=h[2]; diffs[1]=diffs[2]; step=step+1
1004
else:
1005
Rtest=Rnew - mpmath.mpf(0.5)*abs(R3-R1)
1006
if(S._verbose>1):
1007
print "Rtest(L)=",Rtest
1008
[diffs[2 ],h[2 ]]=functional(S,Rtest,M,Y1,Y2,signs,c,ST,False,met,neps)
1009
if(is_zero_in(h) == 1): # all is ok
1010
R1=Rtest; h[1]=h[2]; diffs[1]=diffs[2]; step=step+1
1011
1012
####
1013
1014
def is_zero_in(h):
1015
r"""
1016
Tells which interval contains changes of sign.
1017
1018
1019
INPUT:
1020
1021
- ''h'' -- dictionary h[j]=[h1,h2,h3]
1022
1023
OUTPUT:
1024
1025
- integer (-1 0 1)
1026
1027
EXAMPLES::
1028
1029
1030
"""
1031
zi=dict(); i=0
1032
if(h[1]*h[2] < 0):
1033
zi[-1]=1; i=-1
1034
if(h[3]*h[2] < 0):
1035
zi[1]=1; i=1
1036
if(zi.values().count(1) >1 ): # need to split
1037
return -2
1038
#s="Neeed to split! Not implemented!"
1039
#raise ValueError,s
1040
return i
1041
1042
def prediction(f0,f1,x0,x1):
1043
r"""
1044
Predict zero using the secant method.
1045
1046
INPUT:
1047
1048
- ''f0'' -- real
1049
- ''f1'' -- real
1050
- ''x0'' -- real
1051
- ''x1'' -- real
1052
1053
OUTPUT:
1054
1055
- real
1056
1057
1058
EXAMPLES::
1059
1060
1061
sage: prediction(-1,1,9,10)
1062
19/2
1063
sage: prediction(-1.0,1.0,9.0,10.0)
1064
9.50000000000000
1065
1066
1067
"""
1068
xnew=x0-f0*(x1-x0)/(f1-f0)
1069
if(xnew<x0 or xnew>x1):
1070
st= "Secant method ended up outside interval! \n"
1071
st+="input: f0,f1,x0,x1=%s,%s,%s,%s \n xnew=%s"
1072
raise ValueError,st%(f0,f1,x0,x1,xnew)
1073
return xnew
1074
1075
def prediction_newton(x,f,df):
1076
r"""
1077
Predict zero using the secant method.
1078
1079
INPUT:
1080
1081
- ''x'' -- real
1082
- ''f'' -- real, f(x)
1083
- ''df'' -- real, f'(x)
1084
1085
OUTPUT:
1086
1087
- real
1088
1089
1090
EXAMPLES::
1091
1092
1093
sage: prediction_newton(1,9,10)
1094
19/2
1095
sage: prediction_newton(1.0,9.0,10.0)
1096
9.50000000000000
1097
1098
1099
"""
1100
if(df==0.0):
1101
st= "Newtons method failed! \n"
1102
st+="f'(x)=0. input: f,df,x=%s,%s,%s"
1103
raise ValueError,st%(f,df,x)
1104
xnew=x-f/df
1105
return xnew
1106
1107
1108
def functional(S,r,M,Y1,Y2,signs,c,ST,first_time=False,method='Hecke',ndigs=12):
1109
r"""
1110
Computes the functional we use as an indicator of an eigenvalue.
1111
1112
INPUT:
1113
1114
-''S'' -- space of Maass waveforms
1115
-''r'' -- real
1116
-''M'' -- integer
1117
-''Y1''-- real
1118
-''Y2''-- real
1119
-''signs'' -- dict
1120
-''c'' -- set which coefficients to use
1121
-''ST''-- normalization
1122
-''first_time'' --
1123
-''method'' -- Hecke/two y
1124
-''ndigs'' -- integer (number of digits wanted)
1125
1126
OUTPUT:
1127
1128
- list of real values
1129
1130
1131
1132
"""
1133
diffsx=dict()
1134
h=0
1135
if(S._verbose>1):
1136
print "r,Y1,Y2=",r,Y1,Y2
1137
if(ndigs>=15 and not isinstance(r,sage.libs.mpmath.ext_main.mpf)):
1138
raise TypeError,"Need mpmath input! got r=",r
1139
C1=Maassform_coeffs(S,r,M,ST,Yset=Y1,ndigs=ndigs)
1140
if(method=='TwoY'):
1141
C2=Maassform_coeffs(S,r,M,ST,Yset=Y2,ndigs=ndigs)
1142
for j in range(1 ,4 ):
1143
diffsx[j]=(C1[0 ][c[j]]-C2[0 ][c[j]]).real
1144
if(not first_time and signs.keys().count(j)>0 ):
1145
h=h+signs[j]*diffsx[j]
1146
else:
1147
h=h+abs(diffsx[j])
1148
return [diffsx,h]
1149
elif(method=='Hecke'):
1150
h=(C1[0 ][2 ]*C1[0 ][3 ]-C1[0 ][6 ]).real
1151
diffsx[1 ]=0 ;diffsx[1 ]=0 ;diffsx[3 ]=0 ;
1152
#print "c2c3-c6=",h
1153
return [diffsx,h]
1154
1155
def find_Y_and_M(G,R,ndigs=12,Yset=None,Mset=None):
1156
r"""
1157
Compute a good value of M and Y for Maass forms on G
1158
1159
INPUT:
1160
1161
- ''G'' -- group
1162
- ''R'' -- real
1163
- ''ndigs'' -- integer (number of desired digits of precision)
1164
- ''Yset'' -- real (default None) if set we return M corr. to this Y
1165
- ''Mset'' -- integer (default None) if set we return Y corr. to this M
1166
1167
OUTPUT:
1168
1169
- [Y,M] -- good values of Y (real) and M (integer)
1170
1171
EXAMPLES::
1172
1173
1174
1175
TODO:
1176
Better and more effective bound
1177
"""
1178
l=G._level
1179
if(Mset <> None):
1180
# then we get Y corr. to this M
1181
Y0=mpmath.sqrt(3.0)/mpmath.mpf(2*l)
1182
1183
if(Yset==None):
1184
Y0=mpmath.sqrt(3.0)/mpmath.mpf(2*l)
1185
Y=mpmath.mpf(0.95*Y0)
1186
else:
1187
Y=Yset
1188
#print "Y=",Y,"Yset=",Yset
1189
IR=mpmath.mpc(0,R)
1190
eps=mpmath.mpf(10 **-ndigs)
1191
twopiY=mpmath.pi()*Y*mpmath.mpf(2)
1192
1193
M0=get_M_for_maass(R,Y,eps)
1194
if(M0<10):
1195
M0=10
1196
## Do this in low precision
1197
dold=mpmath.mp.dps
1198
#print "Start M=",M0
1199
#print "dold=",dold
1200
#mpmath.mp.dps=100
1201
try:
1202
for n in range(M0,10000 ):
1203
X=mpmath.pi()*Y*mpmath.mpf(2 *n)
1204
#print "X,IR=",X,IR
1205
test=mpmath.fp.besselk(IR,X)
1206
if(abs(test)<eps):
1207
raise StopIteration()
1208
except StopIteration:
1209
M=n
1210
else:
1211
M=n
1212
raise Exception,"Error: Did not get small enough error:=M=%s gave err=%s" % (M,test)
1213
mpmath.mp.dps=dold
1214
return [Y,M]
1215
1216
1217
1218
1219
1220
1221
1222
def testing_kbes(Rt,Xt):
1223
[R0,R1,NR]=Rt
1224
[X0,X1,NX]=Xt
1225
NRr=mpmath.mpf(NR)
1226
NXr=mpmath.mpf(NX)
1227
for j in range(1,NR):
1228
rj=mpmath.mpf(j)
1229
R=R0+R1*rj/NRr
1230
iR=mpmath.mpc(0,R)
1231
for k in range(1,NX):
1232
rk=mpmath.mpf(k)
1233
x=X0+X1*rk/NXr
1234
print "r,x=",R,x
1235
if(x>R):
1236
print "kbes_asymp="
1237
timeit( "kbes_asymp(R,x)",repeat=1)
1238
else:
1239
print "kbes_rec="
1240
timeit( "kbes_rec(R,x)",repeat=1)
1241
print "mpmath.besselk="
1242
timeit("mpmath.besselk(iR,x)",repeat=1)
1243
1244
1245
#print "t1(",R,x,")=",t1
1246
#print "t2(",R,x,")=",t2
1247
if(R<15.0):
1248
if(x<0.3 *R):
1249
print "Case 1"
1250
elif(x<=max(10.0 +1.2*R,2 *R)):
1251
print "Case 2"
1252
elif(R>20 and x>4 *R):
1253
print "Case 3"
1254
else:
1255
print "Case 4"
1256
1257
1258
def test_Hecke_relations(a,b,C):
1259
r"""Testing Hecke relations for the Fourier coefficients in C
1260
1261
1262
1263
INPUT:
1264
-''C'' -- dictionary of complex (Fourier coefficients)
1265
-''a'' -- integer
1266
-''b'' -- integer
1267
1268
OUTPUT:
1269
-''diff'' -- real : |C(a)C(b)-C(ab)| if (a,b)=1
1270
1271
EXAMPLE::
1272
1273
1274
sage: S=MaassWaveForms(Gamma0(1))
1275
sage: R=mpmath.mpf(9.53369526135355755434423523592877032382125639510725198237579046413534)
1276
sage: Y=mpmath.mpf(0.85)
1277
sage: C=coefficients_for_Maass_waveforms(S,R,Y,10,20,12)
1278
sage: d=test_Hecke_relations(C,2,3); mppr(d)
1279
'9.29e-8'
1280
sage: C=coefficients_for_Maass_waveforms(S,R,Y,30,50,20)
1281
sage: d=test_Hecke_relations(C,2,3); mppr(d)
1282
'3.83e-43'
1283
1284
1285
"""
1286
c=gcd(Integer(a),Integer(b))
1287
lhs=C[0][a]*C[0][b]
1288
rhs=mpmath.mpf(0)
1289
for d in divisors(c):
1290
rhs=rhs+C[0][Integer(a*b/d/d)]
1291
return abs(rhs-lhs)
1292
1293
1294
def test_Hecke_relations_all(C):
1295
r"""
1296
Test all possible Hecke relations.
1297
1298
1299
EXAMPLE::
1300
1301
1302
sage: S=MaassWaveForms(Gamma0(1))
1303
sage: mpmath.mp.dps=100
1304
sage: R=mpmath.mpf(9.53369526135355755434423523592877032382125639510725198237579046413534899129834778176925550997543536649304476785828585450706066844381418681978063450078510030977880577576)
1305
sage: Y=mpmath.mpf(0.85)
1306
sage: C=coefficients_for_Maass_waveforms(S,R,Y,30,50,20)
1307
sage: test=test_Hecke_relations_all(C); test
1308
{4: '9.79e-68', 6: '4.11e-63', 9: '4.210e-56', 10: '9.47e-54', 14: '2.110e-44', 15: '4.79e-42', 21: '4.78e-28', 22: '1.02e-25', 25: '9.72e-19', 26: '2.06e-16'}
1309
1310
1311
We can see how the base precision used affects the coefficients
1312
1313
sage: mpmath.mp.dps=50
1314
sage: C=coefficients_for_Maass_waveforms(S,R,Y,30,50,20)
1315
sage: test=test_Hecke_relations_all(C); test
1316
sage: test=test_Hecke_relations_all(C); test
1317
{4: '1.83e-48', 6: '4.75e-43', 9: '3.21e-36', 10: '1.24e-33', 14: '4.41e-25', 15: '1.53e-23', 21: '6.41e-8', 22: '4.14e-6', 25: '91.455', 26: '12591.0'}
1318
1319
1320
1321
"""
1322
N=max(C[0].keys())
1323
test=dict()
1324
for a in prime_range(N):
1325
for b in prime_range(N):
1326
if(a*b <= N):
1327
test[a*b]=mppr(test_Hecke_relations(C,a,b))
1328
return test
1329
1330
def set_norm_maass(k,cuspidal=True):
1331
r""" Set normalization for computing maass forms.
1332
1333
INPUT:
1334
1335
- ``k`` -- dimenson
1336
- ``cuspidal`` -- cuspidal maass waveforms (default=True)
1337
1338
1339
OUTPUT:
1340
1341
- ``N`` -- normalization (dictionary)
1342
-- N['comp_dim'] -- dimension of space we are computing in
1343
-- N['SetCs']`` -- which coefficients are set
1344
-- N['Vals'] -- values of set coefficients
1345
1346
EXAMPLES::
1347
1348
sage: set_norm_maass(1)
1349
{'Vals': {0: {0: 0, 1: 1}}, 'comp_dim': 1, 'num_set': 2, 'SetCs': [0, 1]}
1350
sage: set_norm_maass(1,cuspidal=False)
1351
{'Vals': {0: {0: 1}}, 'comp_dim': 1, 'num_set': 1, 'SetCs': [0]}
1352
sage: set_norm_maass(2)
1353
{'Vals': {0: {0: 0, 1: 1, 2: 0}, 1: {0: 0, 1: 0, 2: 1}}, 'comp_dim': 2, 'num_set': 3, 'SetCs': [0, 1, 2]}
1354
1355
"""
1356
C=dict()
1357
Vals=dict()
1358
# set coeffs c(0),c(1),...,c(k-1) if not cuspidal
1359
# set coeffs c(0)=0,c(1),...,c(k) if cuspidal
1360
if(cuspidal and k>0):
1361
SetCs=range(0,k+1)
1362
else:
1363
SetCs=range(0,k)
1364
#if(cuspidal): # have to set other cusps too
1365
# for i in range(1,len(G.cusps())+1):
1366
# SetCs.append(0+Ml*i)
1367
if(cuspidal):
1368
C['cuspidal']=True
1369
else:
1370
C['cuspidal']=False
1371
for j in range(k):
1372
Vals[j]=dict()
1373
for n in SetCs:
1374
Vals[j][n]=0
1375
if(cuspidal):
1376
Vals[j][j+1]=1
1377
else:
1378
Vals[j][j]=1
1379
C['comp_dim']=k
1380
C['SetCs']=SetCs
1381
C['Vals']=Vals
1382
return C
1383
1384
def solve_system_for_Maass_waveforms(W,N,deb=False):
1385
r"""
1386
Solve the linear system to obtain the Fourier coefficients of Maass forms
1387
1388
INPUT:
1389
1390
- ``W`` -- (system) dictionary
1391
1392
- ``W['Ms']`` -- M start
1393
- ``W['Mf']`` -- M stop
1394
- ``W['nc']`` -- number of cusps
1395
- ``W['V']`` -- matrix of size ((Ms-Mf+1)*nc)**2
1396
- ``W['RHS']`` -- right hand side (for inhomogeneous system) matrix of size ((Ms-Mf+1)*nc)*(dim)
1397
1398
- ``N`` -- normalisation (dictionary, output from the set_norm_for_maass function)
1399
1400
- ``N['SetCs']`` -- Which coefficients are set
1401
- ``N['Vals'] `` -- To which values are these coefficients set
1402
- ``N['comp_dim']``-- How large is the assumed dimension of the solution space
1403
1404
- ``deb`` -- print debugging information (default False)
1405
1406
OUTPUT:
1407
1408
- ``C`` -- Fourier coefficients
1409
1410
EXAMPLES::
1411
1412
sage: G=MySubgroup(Gamma0(1))
1413
sage: mpmath.mp.dps=20
1414
sage: R=mpmath.mpf(9.533695261353557554344235235928770323821256395107251982375790464135348991298347781769255509975435366)
1415
sage: Y=mpmath.mpf(0.5)
1416
sage: W=setup_matrix_for_Maass_waveforms(G,R,Y,12,22)
1417
sage: N=set_norm_maass(1)
1418
sage: C=solve_system_for_Maass_waveforms(W,N)
1419
sage: C[0][2]*C[0][3]-C[0][6]
1420
mpc(real='-1.8055426724989656270259e-14', imag='1.6658248366482944572967e-19')
1421
1422
If M is too large and the precision is not high enough the matrix might be numerically singular
1423
1424
W=setup_matrix_for_Maass_waveforms(G,R,Y,20,40)
1425
sage: C=solve_system_for_Maass_waveforms(W,N)
1426
Traceback (most recent call last)
1427
...
1428
ZeroDivisionError: Need higher precision! Use > 23 digits!
1429
1430
Increasing the precision helps
1431
1432
sage: mpmath.mp.dps=25
1433
sage: R=mpmath.mpf(9.533695261353557554344235235928770323821256395107251982375790464135348991298347781769255509975435366)
1434
sage: C=solve_system_for_Maass_waveforms(W,N)
1435
sage: C[0][2]*C[0][3]-C[0][6]
1436
mpc(real='3.780824715556976438911480324e-25', imag='2.114746048869188750991752872e-99')
1437
1438
1439
"""
1440
import mpmath
1441
V=W['V']
1442
Ms=W['Ms']
1443
Mf=W['Mf']
1444
nc=W['nc']
1445
Ml=Mf-Ms+1
1446
if(V.cols<>Ml*nc or V.rows<>Ml*nc):
1447
raise Exception," Wrong dimension of input matrix!"
1448
SetCs=N['SetCs']
1449
Vals=N['Vals']
1450
comp_dim=N['comp_dim']
1451
if(N['cuspidal']):
1452
for i in range(1,nc):
1453
if(SetCs.count(i*Ml)==0):
1454
SetCs.append(i*Ml)
1455
for fn_j in range(comp_dim):
1456
Vals[fn_j][i*Ml]=0
1457
1458
if(Ms<0):
1459
use_sym=0
1460
else:
1461
use_sym=1
1462
if(use_sym==1 and SetCs.count(0)>0):
1463
num_set=len(N['SetCs'])-1
1464
else:
1465
num_set=len(N['SetCs'])
1466
t=V[0,0]
1467
if(isinstance(t,float)):
1468
mpmath_ctx=mpmath.fp
1469
else:
1470
mpmath_ctx=mpmath.mp
1471
if(W.has_key('RHS')):
1472
RHS=W['RHS']
1473
else:
1474
RHS=mpmath_ctx.matrix(int(Ml*nc-num_set),int(comp_dim))
1475
LHS=mpmath_ctx.matrix(int(Ml*nc-num_set),int(Ml*nc-num_set))
1476
roffs=0
1477
1478
if(deb):
1479
print "num_set,use_sym=",num_set,use_sym
1480
print "SetCs,Vals=",SetCs,Vals
1481
print "V.rows,cols=",V.rows,V.cols
1482
print "LHS.rows,cols=",LHS.rows,LHS.cols
1483
print "RHS.rows,cols=",RHS.rows,RHS.cols
1484
for r in range(V.rows):
1485
cr=r+Ms
1486
if(SetCs.count(r+Ms)>0):
1487
roffs=roffs+1
1488
continue
1489
for fn_j in range(comp_dim):
1490
RHS[r-roffs,fn_j]=mpmath_ctx.mpf(0)
1491
for cset in SetCs:
1492
v=Vals[fn_j][cset]
1493
if(mpmath_ctx==mpmath.mp):
1494
tmp=mpmath_ctx.mpmathify(v)
1495
elif(isinstance(v,float)):
1496
tmp=mpmath_ctx.mpf(v)
1497
else:
1498
tmp=mpmath_ctx.mpc(v)
1499
#print "tmp=",tmp
1500
#print "V[",r,cset-Ms,"]=",V[r,cset-Ms]
1501
tmp=tmp*V[r,cset-Ms]
1502
RHS[r-roffs,fn_j]=RHS[r-roffs,fn_j]-tmp
1503
coffs=0
1504
for k in range(V.cols):
1505
if(SetCs.count(k+Ms)>0):
1506
coffs=coffs+1
1507
continue
1508
# print "r,k=",r,k
1509
#print "roffs,coffs=",roffs,coffs
1510
#print "r-roffs,k-coffs=",r-roffs,k-coffs
1511
LHS[r-roffs,k-coffs]=V[r,k]
1512
#print "LHS[",r,k,"]=",LHS[r-roffs,k-coffs]
1513
#print "RHS="
1514
#for j in range(RHS.rows):
1515
# print j,RHS[j,0]#
1516
try:
1517
A, p = mpmath_ctx.LU_decomp(LHS)
1518
except ZeroDivisionError:
1519
t1=smallest_inf_norm(LHS)
1520
print "n=",smallest_inf_norm(LHS)
1521
t2=mpmath_ctx.log10(smallest_inf_norm(LHS))
1522
t3=mpmath_ctx.ceil(-t2)
1523
isinf=False
1524
if(isinstance(t3,float)):
1525
isinf = (t3 == float(infinity))
1526
if(isinstance(t3,sage.libs.mpmath.ext_main.mpf)):
1527
isinf = ((t3.ae(mpmath.inf)) or t3==mpmath.inf)
1528
if(isinstance(t3,sage.rings.real_mpfr.RealLiteral)):
1529
isinf = t3.is_infinity()
1530
if(isinf):
1531
raise ValueError, " element in LHS is infinity! t3=%s" %t3
1532
#print "LHS="
1533
#for j in range(LHS.rows):
1534
# print j,LHS.column(j)
1535
#print "t3=",t3
1536
t=int(t3)
1537
#t=int(mpmath_ctx.ceil(-mpmath_ctx.log10(smallest_inf_norm(LHS))))
1538
#raise ZeroDivisionError,"Need higher precision! Use > %s digits!" % t
1539
return t
1540
X=dict()
1541
for fn_j in range(comp_dim):
1542
X[fn_j] = dict() #mpmath.matrix(int(Ml),int(1))
1543
b = mpmath_ctx.L_solve(A, RHS.column(fn_j), p)
1544
TMP = mpmath_ctx.U_solve(A, b)
1545
roffs=0
1546
res = mpmath_ctx.norm(mpmath_ctx.residual(LHS, TMP, RHS.column(fn_j)))
1547
#print "res(",fn_j,")=",res
1548
for i in range(nc):
1549
X[fn_j][i]=dict()
1550
for n in range(Ml):
1551
if(SetCs.count(n+Ms)>0):
1552
roffs=roffs+1
1553
#print "X[",fn_j,",",n,",Vals[fn_j][n]
1554
X[fn_j][0][n+Ms]=Vals[fn_j][n+Ms]
1555
continue
1556
X[fn_j][0][n+Ms]=TMP[n-roffs,0]
1557
#print "X[",fn_j,",",n+Ms,"=",TMP[n-roffs,0]
1558
for i in range(1,nc):
1559
for n in range(Ml):
1560
if(SetCs.count(n+Ms+i*Ml)>0):
1561
roffs=roffs+1
1562
# print "X[",fn_j,",",n,",Vals[fn_j][n]
1563
X[fn_j][i][n+Ms]=Vals[fn_j][n+Ms+i*Ml]
1564
continue
1565
X[fn_j][i][n+Ms]=TMP[n+i*Ml-roffs,0]
1566
# return x
1567
return X
1568
1569
1570
1571
1572
# Stuff needed for attaching the file locally
1573
#__main__.MaassWaveForms=MaassWaveForms
1574
#__main__.MaassWaveformElement=MaassWaveformElement
1575
1576