CoCalc
Sharedwww / Tables / magma / hecke.mOpen in CoCalc
Author: William A. Stein
1
/****-*-magma-*-*************************************************************
2
* HECKE: Modular Symbols Calculator *
3
* *
4
* Version 0.3M (September 14, 1999) *
5
* *
6
*Send bug reports and suggestions to William Stein was@math.berkeley.edu. *
7
***************************************************************************/
8
9
/*************************************************************************
10
TODO TODO TODO TODO TODO TODO TODO TODO TODO
11
12
13
[ ] Intersections with Eisenstein series NOT programmed!
14
15
[ ] Add a feature for "tensoring with Qp".
16
17
[ ] Decomposition of S_3(25,[4];Q) does not work.
18
19
[ ] Need to be able to compute eigenforms over a single
20
number field, so they can be worked with.
21
22
> m4:=msym(DirichletCharacter(13,[3]),4,+1);
23
> Print(Decomposition(m4));
24
Modular symbols factors:
25
13k4A: dim = 1 cuspidal
26
13k4B: dim = 2 cuspidal
27
13k4C: dim = 1 eisenstein
28
13k4D: dim = 1 eisenstein
29
> f4b:=qEigenform(Factor(m4,2),17);
30
> MinimalPolynomial(Coefficient(f4b,2));
31
x^2 + (-5*zeta - 5)*x + 2*zeta
32
> f4b;
33
q + a*q^2 + (-3*a + (5*zeta + 5))*q^3 + ((5*zeta + 5)*a - 10*zeta)*q^4 +
34
(-5*zeta*a - 20)*q^5 + ((-10*zeta - 10)*a + 6*zeta)*q^6 + ((zeta + 1)*a +
35
5*zeta)*q^7 + (7*zeta*a + 10)*q^8 + ((15*zeta + 15)*a - 20*zeta)*q^9 + (5*a
36
- 10*zeta - 10)*q^10 + (-15*a + (29*zeta + 29))*q^11 + (-20*zeta*a +
37
20)*q^12 + ((-7*zeta - 5)*a + (50*zeta + 45))*q^13 + (10*zeta*a + 2)*q^14 +
38
(10*a - 70*zeta - 70)*q^15 + (15*a - 66*zeta - 66)*q^16 + ((-16*zeta - 16)*a
39
+ 75*zeta)*q^17
40
41
USELESS!
42
43
[ ] Torsion bound -- should start new bound where left off from
44
old one.
45
46
[ ] Analytic invariants, e.g., ImaginaryPeriod: don't get force
47
recomputed when the precision of SOME analytic computation
48
goes up and they are re-called on. They should!
49
50
[ ] Clean interface!! Seperate files?
51
52
*************************************************************************/
53
54
HeckeBugWatch := false;
55
HeckeVerbose := true;
56
HeckeSuperverbose := false;
57
58
/************************************************************************
59
* *
60
* DATA STRUCTURES *
61
* *
62
************************************************************************/
63
64
CManSymList := recformat<
65
k, // weight
66
F, // base field
67
R, // F[X,Y].
68
p1list, // List of elements of P^1(Z/NZ).
69
n // size of list of Manin symbols = #p1list * (k-1).
70
> ;
71
72
/************************************************************************
73
* CQuotient: *
74
* First we motivate the format. *
75
* To save memory and space we mod out by the S, T, and possibly I *
76
* relations in two phases. First mod out by the S,I relations *
77
* x + xS = 0, x - xI = 0. *
78
* by identifying equivalent pairs. Next mod out by the T relations *
79
* x + xT + xT^2 = 0. *
80
************************************************************************/
81
CQuotient := recformat<
82
Sgens, // * List of the free generators after modding out
83
// by the 2-term S and possibly I relations.
84
Squot, // * The i-th Manin symbol is equivalent to
85
Scoef, // Scoef[i]*(Squot[i]-th free generator).
86
Tgens, // * List of the free generators after modding
87
// out the S-quotient by the T-relations.
88
Tquot // * The i-th Sgen is equal to Tquot[i], which
89
// is a vector on Tgens.
90
>;
91
92
93
// The categories: (someday these will be made a part of Magma.)
94
// Presently they are used to implement polymorphism in some cases.
95
ModSym := 1;
96
ModSymFac := 2;
97
98
function GetCategory(M)
99
return M`theCategory;
100
end function;
101
102
procedure SetCategory(M, category)
103
M`theCategory := category;
104
end procedure;
105
106
///////////////////////////////////////////////////////////////////
107
// ModSym: Modular symbols object. //
108
///////////////////////////////////////////////////////////////////
109
declare attributes ModTupFld:
110
theCategory, // * indicate that this is a mod sym object
111
k, // * weight
112
N, // * level
113
F, // * the base field
114
eps, // * the Dirichlet character
115
sign, // * sign -- see doc of ModularSymbols()
116
mlist, // * list of Manin symbols, and other related data
117
quot, // * gives representation of any
118
// Manin symbol in terms of free generators
119
disc, // * discriminant of the Hecke algebra
120
decomp, olddecomp, newdecomp, // * ambient decomposition
121
semidecomp,
122
gammaalp, // * action of character via Gamma_0(N).
123
Z, // * integral modular symbols.
124
ModSymBasis, // * Basis of modular symbols.
125
BoundaryMap, // * boundary map
126
SkF, // * cuspidal modular symbols, over F
127
SkZ, // * cuspidal modular symbols, over integer Z.
128
// (only makes sense when char(F)=0).
129
SkZplus,SkZminus, // * for *-involution.
130
old, // * old spaces
131
sknew, sknewdual, // * new cuspidal modular symbols
132
mknew, mknewdual, // * new cuspidal modular symbols
133
newforms, // * basis of eigenforms for new subspace.
134
oldforms, // * old forms, from lower level.
135
winding, // * list of winding submodules
136
T_images, // * images of standard basis vectors under Hecke.
137
X, // * list of character groups for
138
mestre, // each p exactly dividing N.
139
cusplist; // * the cusps.
140
141
///////////////////////////////////////////////////////////////////
142
// ModSymFac: Factor of a modular symbols object. //
143
// This is represented by a subspace of the dual of //
144
// a ModSym object. //
145
///////////////////////////////////////////////////////////////////
146
declare attributes ModTupFld:
147
theCategory, // * indicates that this is a modsym factor.
148
M, // * ambient space of modular symbols.
149
V, // * Subspace of M
150
Z, // * Lattice -- Integral subspace of ambient space.
151
Zdual, // * Lattice -- Integral subspace of ambient space.
152
qexp, // * q-expansion -- a pair, f(x), coefs.
153
eigen, eigenplus, eigenminus, // * Eigenvector in M tensor Fbar.
154
eigenint, // * EigenformInTermsOfIntegralBasis
155
moddeg, // * Degree of the canonical map.
156
PeriodLattice,
157
realvolume,// * Real volume
158
imagvolume,// * Pure imaginary volume
159
cinf, cinfimag, // * Number of real components.
160
Lvals, // * Critical values of the L-function.
161
LRatio, // * Ratios L(M,1)/Omega*(fudge).
162
LRatioOdd, // * odd part of Ratios L(M,1)/Omega*(fudge).
163
cp, // * Orders of component groups.
164
wq, // * Atkin-Lehner
165
qintbasis, // * integral basis of q-expansions.
166
N, // * the level
167
iso, // * the isogeny class
168
isnew, // * whether or not it is new
169
iscusp, // * whether it is cuspidal or not
170
fast, // * fast matrix of Tn on M.
171
signspace, // * A^+ and A^-.
172
// * there is also the X from ModularSymbols...
173
xdata, // * local phix and mx
174
ZxZalp, VolLEven, VolLOdd, // * For LRatio.
175
PeriodGens, PGfast,
176
RatPeriodMap, RatPeriodLat,
177
RatPeriodConj,RatPeriodMapSign,
178
PeriodMap, PeriodMapPrecision;
179
180
181
182
/************************************************************************
183
* *
184
* Manin Symbols (basic functions) *
185
* *
186
************************************************************************/
187
188
/////////////////////////////////////////////////////////////////////////
189
// NormalizePair (written by Allan Steel) //
190
// INPUT: [u,v] in Z/N x Z/N. //
191
// OUTPUT: 1) the *index* of a fixed choice [a,b] of representative //
192
// in the P^1(Z/NZ) equivalence class of [u,v]. //
193
// If gcd(u,v,N)>1 then the index returned is 0. //
194
// 2) a scalar s such that //
195
// [a*s,b*s] = [u,v]. //
196
// The character relation is thus //
197
// eps(s) [a,b] == [u,v]. //
198
/////////////////////////////////////////////////////////////////////////
199
function NormalizePair(x)
200
Z := IntegerRing();
201
u := x[1];
202
v := x[2];
203
R := Parent(u);
204
N := Modulus(R);
205
if u eq 0 then
206
return [R | 0, 1], v;
207
else
208
u := Z ! u;
209
g, s := XGCD(u, N);
210
if g ne 1 then
211
d := N div g;
212
while GCD(s, N) ne 1 do
213
s := (s + d) mod N;
214
end while;
215
end if;
216
// Multiply (u, v) by s; new u = g
217
u := R!g;
218
v := v*s;
219
minv := Z!v;
220
mint := 1;
221
if g ne 1 then
222
Ng := N div g;
223
vNg := v*Ng;
224
t := R!1;
225
for k := 2 to g do
226
v +:= vNg;
227
t +:= Ng;
228
if Z!v lt minv and IsUnit(t) then
229
minv := Z!v;
230
mint := t;
231
end if;
232
end for;
233
end if;
234
if GCD([Z | u, minv, N]) ne 1 then
235
printf "Bad x=%o, N=%o, u=%o, minv=%o, s=%o, mint=%o\n",
236
x, N, u, minv, s, mint;
237
error "";
238
end if;
239
// return [R|u, minv], R!InverseMod(s*mint,N);
240
return [R|u, minv], 1/(R!(s*mint));
241
end if;
242
end function;
243
244
245
//////////////////////////////////////////////////////////////////////////
246
// P1Reduce: //
247
// INPUT: [u,v] in Z/N x Z/N. //
248
// OUTPUT: 1) the *index* of a fixed choice [a,b] of representative //
249
// in the P^1(Z/NZ) equivalence class of [u,v]. //
250
// If gcd(u,v,N)>1 then the index returned is 0. //
251
// 2) a scalar s such that //
252
// [a*s,b*s] = [u,v]. //
253
// so the character relation is //
254
// eps(s) [a,b] == [u,v]. //
255
//////////////////////////////////////////////////////////////////////////
256
function P1Reduce(x, list)
257
N := Characteristic(Parent(x[1]));
258
if N eq 1 then
259
return 1, 1;
260
end if;
261
if Gcd([x[1], x[2], N]) ne 1 then
262
return 0, 1;
263
end if;
264
n, s := NormalizePair(x);
265
return Index(list, n), s;
266
end function;
267
268
269
//////////////////////////////////////////////////////////////////////////
270
// EnumerateP1: //
271
// Construct a list of distinct normalized representatives for //
272
// the set of equivalence classes of P^1(Z/NZ). //
273
// The output of this function is used by P1Reduce. //
274
//////////////////////////////////////////////////////////////////////////
275
function EnumerateP1(N)
276
R := (N gt 1) select IntegerRing(N) else quo<Integers()|1>;
277
return {@ NormalizePair([R|c,1]) : c in [0..N-1] @} join
278
{@ NormalizePair([R|1,d]) : d in [0..N-1] | Gcd(d,N) gt 1 @} join
279
{@ NormalizePair([R|c,d]) : c in Divisors(N), d in [0..N-1] |
280
c ne 1 and c ne N and Gcd(c,d) eq 1
281
and Gcd(d,N) gt 1 @};
282
end function;
283
284
285
//////////////////////////////////////////////////////////////////////////
286
// ManinSymbolList: //
287
// Construct a list of distinct Manin symbols. These are //
288
// elements of the Cartesion product: //
289
// {0,...,k-2} x P^1(Z/NZ). //
290
// In fact, we only store a list of the elements of P^1(Z/NZ), //
291
// as the full Cartesion product can be stored using //
292
// the following scheme. //
293
// //
294
// There are Manin symbols 1,...,#({0,..,k-2}xP^1) indexed by i. //
295
// Thus i is an integer between 1 and the number of generating Manin //
296
// symbols. Suppose P^1(N) = {x_1, ..., x_n}. The encoding is //
297
// as follows: //
298
// 1=<X^0Y^(k-2),x_1>, 2=<0, x_2>, ..., n=<0,x_n>, //
299
// n+1=<X^1Y^(k-3),x_1>,n+2=<1, x_2>, ...,2n=<1,x_n>, //
300
// ... //
301
//////////////////////////////////////////////////////////////////////////
302
function ManinSymbolList(k,N,F)
303
p1list := EnumerateP1(N);
304
n := (k-1)*#p1list;
305
return rec<CManSymList |
306
k := k,
307
F := F,
308
R := PolynomialRing(F,2),
309
p1list := p1list,
310
n := n
311
>;
312
end function;
313
314
315
///////////////////////////////////////////////////////////////////////////
316
// ManinSymbolApply //
317
// Apply an element g=[a,b, c,d] of SL(2,Z) to the i-th //
318
// standard Manin symbol. The definition of the action is //
319
// g.(X^i*Y^j[u,v]) := //
320
// (aX+bY)^i*(cX+dY)^j [[u,v]*g]. //
321
// The argument "manin" should be as returned by //
322
// the function ManinSymbolsList above. //
323
// The character eps should be an array which //
324
// defines a Dirichlet character Z/NZ ---> K. //
325
// Thus eps[a] in K and makes sense for a in (Z/NZ)^*. //
326
// If eps is trivial, then the character is assumed trivial. //
327
///////////////////////////////////////////////////////////////////////////
328
329
330
///////////////////////////////////////////////////////////////////////////
331
// Unwind -- Given an int i, this function gives back the //
332
// ith generating Manin symbol. //
333
///////////////////////////////////////////////////////////////////////////
334
function UnwindManinSymbol(i, mlist)
335
// P^1(N) part.
336
p1list := mlist`p1list;
337
n := #p1list;
338
ind := (i mod n);
339
if ind eq 0 then
340
ind := n;
341
end if;
342
uv := p1list[ind];
343
w := Integers()!((i - ind)/n);
344
return uv, w, ind;
345
end function;
346
347
// Wind -- Given w in the range 0<=w<=k-2, and an index ind
348
// into the P^1-list, this function gives back
349
// the number of the generating Manin symbol.
350
function WindManinSymbol(w, ind, mlist)
351
return w*#(mlist`p1list) + ind;
352
end function;
353
354
355
intrinsic ManinSymbolApply(g::SeqEnum, i::RngIntElt,
356
mlist::Rec, eps::Rec) -> SeqEnum
357
{Apply g to the ith Manin symbol.}
358
k := mlist`k;
359
uv, w, ind := UnwindManinSymbol(i,mlist);
360
p1list := mlist`p1list;
361
uvg := Parent(uv) ! [g[1]*uv[1]+g[3]*uv[2], g[2]*uv[1]+g[4]*uv[2]];
362
act_uv, scalar := P1Reduce(uvg, p1list);
363
364
if act_uv eq 0 then
365
return [<0,1>];
366
end if;
367
368
if k eq 2 then
369
if not IsTrivial(eps) then
370
return [<Evaluate(eps,scalar),act_uv>];
371
/*
372
if Evaluate(eps,scalar) ne 0 then
373
return [<Evaluate(eps,scalar)^(-1),act_uv>];
374
else
375
return [<0,act_uv>];
376
end if;
377
*/
378
else
379
return [<1,act_uv>];
380
end if;
381
end if;
382
383
// Polynomial part.
384
R<x> :=PolynomialRing(mlist`F); // univariate is fine for computation
385
hP := (g[1]*x+g[2])^w*(g[3]*x+g[4])^(k-2-w);
386
387
if not IsTrivial(eps)then
388
hP *:= Evaluate(eps,scalar);
389
end if;
390
pol := ElementToSequence(hP);
391
392
// Put it together
393
n := #p1list;
394
ans := [<pol[w+1], w*n + act_uv> : w in [0..#pol-1]];
395
return [x : x in ans | x[1] ne 0];
396
end intrinsic;
397
398
399
/////////////////////////////////////////////////////////////////
400
// ModularSymbolApply //
401
// Apply an element g=[a,b, c,d] of SL(2,Z) to the given //
402
// modular symbol. The definition of the action is //
403
// g.(X^i*Y^j{u,v}) := //
404
// (dX-bY)^i*(-cX+aY)^j {g(u),g(v)}. //
405
// A modular symbol is represented as a sequence of pairs //
406
// <P,x>, where P is a polynomial in X and Y (an element //
407
// of the ring M`mlist`R, and x=[[a,b],[c,d]] is a pair //
408
// of elements of P^1(Q), //
409
// where [a,b] <--> a/b and [c,d] <--> c/d. //
410
// After computing the action, no further reduction is done. //
411
/////////////////////////////////////////////////////////////////
412
413
intrinsic ModularSymbolApply( M::ModTupFld, g::SeqEnum, s::Tup
414
) -> SeqEnum
415
{Apply an element g=[a,b, c,d] of SL(2,Z) to the given
416
modular symbol. The definition of the action is
417
g.(X^i*Y^j\{u,v\}) :=
418
(dX-bY)^i*(-cX+aY)^j \{g(u),g(v)\}.
419
A modular symbol is represented as a pair
420
<P,x>, where P is a polynomial in X and Y (an element
421
of the ring M`mlist`R, and x=[[a,b],[c,d]] is a pair
422
of elements of P^1(Q),
423
where [a,b] <--> a/b and [c,d] <--> c/d.}
424
425
R := M`mlist`R;
426
h := hom <R -> R | g[4]*R.1-g[2]*R.2, -g[3]*R.1+g[1]*R.2>;
427
hP := h(s[1]);
428
a,b:= Explode(s[2][1]);
429
c,d:= Explode(s[2][2]);
430
gx := [[g[1]*a+g[2]*b, g[3]*a+g[4]*b],
431
[g[1]*c+g[2]*d, g[3]*c+g[4]*d]];
432
return <hP, gx>;
433
end intrinsic;
434
435
intrinsic ModularSymbolApply(M::ModTupFld, g::SeqEnum, s::SeqEnum) -> SeqEnum
436
{Apply an element g=[a,b, c,d] of SL(2,Z) to the given
437
modular symbol. The definition of the action is
438
g.(X^i*Y^j\{u,v\}) :=
439
(dX-bY)^i*(-cX+aY)^j \{g(u),g(v)\}.
440
A modular symbol is represented as a sequence of pairs
441
<P,x>, where P is a polynomial in X and Y (an element
442
of the ring M`mlist`R, and x=[[a,b],[c,d]] is a pair
443
of elements of P^1(Q),
444
where [a,b] <--> a/b and [c,d] <--> c/d.}
445
return [ModularSymbolApply(M, g,term): term in s];
446
end intrinsic;
447
448
449
/////////////////////////////////////////////////////////////////
450
// Sparse2Quotient: //
451
// Performs Sparse Gauss elimination on a matrix all of //
452
// whose columns have at most 2 nonzero entries. I just //
453
// use the fairly obvious algorithm. It runs fast //
454
// enough. Example: //
455
// rels := [[1,2], [1,3], [2,3], [4,5]]; //
456
// relc := [[3,-1],[1,1], [1,1], [1,-1]]; //
457
// n := 5; // x1,...,x5 //
458
// corresponds to 3*x1-x2=0, x1+x3=0, x2+x3=0, x4-x5=0. //
459
/////////////////////////////////////////////////////////////////
460
461
function Sparse2Quotient (rels, relc, n, F)
462
free := [1..n];
463
coef := [F|1 : i in [1..n]];
464
related_to_me := [[] : i in [1..n]];
465
for i in [1..#rels] do
466
t := rels[i];
467
c1 := relc[i][1]*coef[t[1]];
468
c2 := relc[i][2]*coef[t[2]];
469
// Mod out by the relation
470
// c1*x_free[t[1]] + c2*x_free[t[2]] = 0.
471
die := 0;
472
if c1 eq 0 and c2 eq 0 then
473
// do nothing.
474
elif c1 eq 0 and c2 ne 0 then // free[t[2]] --> 0
475
die := free[t[2]];
476
elif c2 eq 0 and c1 ne 0 then
477
die := free[t[1]];
478
elif free[t[1]] eq free[t[2]] then
479
if c1+c2 ne 0 then
480
// all xi equal to free[t[1]] must now equal to zero.
481
die := free[t[1]];
482
end if;
483
else // x1 = -c2/c1 * x2.
484
x := free[t[1]];
485
free[x] := free[t[2]];
486
coef[x] := -c2/c1;
487
for i in related_to_me[x] do
488
free[i] := free[x];
489
coef[i] *:= coef[x];
490
Append (~related_to_me[free[t[2]]], i);
491
end for;
492
Append (~related_to_me[free[t[2]]], x);
493
end if;
494
495
if die gt 0 then
496
for i in related_to_me[die] do
497
free[i] := 1;
498
coef[i] := 0;
499
end for;
500
free[die] := 1 ;
501
coef[die] := 0;
502
end if;
503
end for;
504
505
// Enumerate the subscripts of free generators that survived.
506
// x_{i_1} <----> y_1
507
// x_{i_2} <----> y_2, etc.
508
509
for i in [1..#free] do
510
if coef[i] eq 0 then
511
free[i] := -1;
512
end if;
513
end for;
514
ykey := {@ x : x in Set(free) | x ne -1 @};
515
for i in [1..#free] do
516
if free[i] eq -1 then
517
free[i] := 1;
518
else
519
free[i] := Index(ykey,free[i]);
520
end if;
521
end for;
522
return ykey, free, coef;
523
end function;
524
525
526
527
/*********************************************************
528
Quotient:
529
The INPUT is a list of (sparse) relations
530
[[<c_1, i_1>, <c_2, i_2>, ... <c_r,i_r>], ... ]
531
The first listed spare relation is
532
c_1*e_{i_1} + c_2*e_{i_2} + ... c_r*e_{i_r} = 0.
533
The integer n denotes the total number of basis
534
elements e_i.
535
The field K is the field over which the c_i are defined.
536
The OUTPUT is (1) an indexed set of g free generators, and
537
(2) an expression for each e_i in terms of the free
538
generators. These expressions are elements of the
539
g-dimensional vector space over K.
540
generators, quotient
541
*********************************************************/
542
function Pivots(B) // find pivots of reduced basis.
543
pivots := [];
544
for b in B do
545
j := 1;
546
while b[j] eq 0 do
547
j +:= 1;
548
end while;
549
Append(~pivots, j);
550
end for;
551
return pivots;
552
end function;
553
554
forward Quotient2;
555
function Quotient(rels, n, K)
556
ringchoice := Characteristic(K) eq 0;
557
if Type(K) eq FldPr then
558
ringchoice := false;
559
end if;
560
return Quotient2(rels,n,K : ring:=ringchoice);
561
562
end function;
563
function Quotient2(rels, n, K : ring := true)
564
if HeckeSuperverbose then
565
"# relations = ", #rels;
566
end if;
567
if ring then // POLYNOMIAL ALGORITHM
568
if HeckeSuperverbose then
569
"ring reduction";
570
end if;
571
R := PolynomialRing(K, n);
572
vars := {@ R.i : i in [1..n] @};
573
Rels := [ &+[t[1]*R.t[2] : t in r] : r in rels];
574
Rels := Reduce(Rels);
575
W := quo<R|Rels>;
576
gens := {@ i : i in [1..n] | not exists
577
{ g : g in Rels | LeadingMonomial(g) eq R.i } @};
578
Z := VectorSpace(K,#gens);
579
quot := [ &+[Z|
580
LeadingCoefficient(t) *
581
Z.(Index(gens,Index(vars,t/LeadingCoefficient(t))))
582
: t in Terms(R!W.i)] : i in [1..n] ];
583
else // VECTOR SPACE ALGORITHM
584
if HeckeSuperverbose then
585
"vector space reduction";
586
end if;
587
V := VectorSpace(K, n);
588
Rels := [ &+[t[1]*V.t[2] : t in r] : r in rels];
589
S := RowSpace(RMatrixSpace(K, #Rels, n) ! Rels);
590
m := n - Dimension(S);
591
B := Basis(S);
592
W := VectorSpace(K, m);
593
quot := [ W!0 : i in [1..n]];
594
595
pivots := Pivots(B);
596
597
gens := {@ i : i in [1..n] | i notin pivots @};
598
for i := 1 to #pivots do
599
quot[pivots[i]] := -W![B[i][j] : j in gens];
600
end for;
601
for i :=1 to #gens do
602
quot[gens[i]] := W.i;
603
end for;
604
end if;
605
return gens, quot;
606
end function;
607
608
609
////////////////////////////////////////////////////////////////////
610
// CONSTRUCT QUOTIENT BY 2 AND 3 TERM RELS //
611
////////////////////////////////////////////////////////////////////
612
613
function ManSym2termQuotient (mlist, eps, sign)
614
n := mlist`n;
615
K := mlist`F;
616
S := [0,-1, 1,0];
617
I := [-1,0, 0,1];
618
xS := [ManinSymbolApply(S,i,mlist,eps) : i in [1..n]];
619
S_rels := [ [i, (xS[i][1])[2]] : i in [1..n]| #xS[i] gt 0];
620
S_relc := [ [K!1, (xS[i][1])[1]] : i in [1..n]| #xS[i] gt 0];
621
if sign ne 0 then
622
xI := [ManinSymbolApply(I,i,mlist,eps) : i in [1..n]];
623
I_rels := [ [i, (xI[i][1])[2]] : i in [1..n]];
624
I_relc := [ [K!1, -sign*(xI[i][1])[1]] : i in [1..n]];
625
else
626
I_rels := [];
627
I_relc := [];
628
end if;
629
rels := S_rels cat I_rels;
630
relc := S_relc cat I_relc;
631
return Sparse2Quotient(rels,relc,n,K);
632
end function;
633
634
function ManSym3termQuotient (mlist, eps, Skey, Squot, Scoef)
635
// Construct the subspace of 3-term relations.
636
n := mlist`n;
637
F := mlist`F;
638
k := mlist`k;
639
T := [0,-1, 1,-1];
640
TT:= [-1,1, -1,0];
641
642
if k eq 2 then
643
mask := [false : i in [1..n]];
644
rels := [];
645
for j in [1..n] do
646
if not mask[j] then
647
t := ManinSymbolApply(T,j,mlist,eps)[1];
648
tt := ManinSymbolApply(TT,j,mlist,eps)[1];
649
mask[t[2]] := true;
650
mask[tt[2]] := true;
651
Append(~rels, [<Scoef[j],Squot[j]>,
652
<t[1]*Scoef[t[2]],Squot[t[2]]>,
653
<tt[1]*Scoef[tt[2]],Squot[tt[2]]>]);
654
end if;
655
end for;
656
else
657
rels := [&cat[
658
[<Scoef[i],Squot[i]>],
659
[<x[1]*Scoef[x[2]],Squot[x[2]]>
660
: x in ManinSymbolApply(T,i,mlist,eps)],
661
[<x[1]*Scoef[x[2]],Squot[x[2]]>
662
: x in ManinSymbolApply(TT,i,mlist,eps)]
663
]
664
: i in [1..n]];
665
end if;
666
667
return Quotient(rels, #Skey, F);
668
end function;
669
670
671
/*********************************************************
672
* *
673
* MODULARSYMBOLS: *
674
* Construct the space of modular symbols of weight k, *
675
* level N and character eps. *
676
* *
677
*********************************************************/
678
679
intrinsic ModularSymbols(N::RngIntElt) -> ModTupFld
680
{Returns the space of modular symbols
681
of weight 2 for Gamma_0(N), over the rational numbers.}
682
return ModularSymbols(DirichletCharacter(N),2,0);
683
end intrinsic;
684
685
intrinsic ModularSymbols(N::RngIntElt, k::RngIntElt) -> ModTupFld
686
{Returns the space of modular symbols
687
of weight k for Gamma_0(N), over the rational numbers.}
688
return ModularSymbols(DirichletCharacter(N),k,0);
689
end intrinsic;
690
691
intrinsic ModularSymbols(N::RngIntElt, k::RngIntElt,
692
sign::RngIntElt) -> ModTupFld
693
{Returns the space of modular symbols
694
of weight k for Gamma_0(N), over the rational numbers.
695
If sign=+1 then returns the +1 quotient, if sign=-1
696
returns the -1 quotient, and if sign=0 returns the full space.
697
If sign is a positive prime, then the full space of modular symbols
698
mod sign isreturned.}
699
if sign gt 1 and IsPrime(sign) then
700
return ModularSymbols(N,k,0,sign);
701
end if;
702
return ModularSymbols(DirichletCharacter(N),k,sign);
703
end intrinsic;
704
705
intrinsic ModularSymbols(N::RngIntElt, k::RngIntElt,
706
sign::RngIntElt,
707
p::RngIntElt) -> ModTupFld
708
{Returns the the space of modular symbols
709
of weight k for Gamma_0(N), over the finite field Fp.}
710
assert IsPrime(p);
711
return ModularSymbols(DirichletCharacter(N,p),k,sign);
712
end intrinsic;
713
714
intrinsic ModularSymbols(eps::Rec) -> ModTupFld
715
{Returns the space of modular symbols
716
of weight k for Gamma_1(N) with character eps,
717
over the rational numbers.}
718
return ModularSymbols(eps,2,0);
719
end intrinsic;
720
721
intrinsic ModularSymbols(eps::Rec, k::RngIntElt) -> ModTupFld
722
{Returns the space of modular symbols
723
of weight k for Gamma_1(N) with character eps,
724
over the rational numbers.}
725
return ModularSymbols(eps,k,0);
726
end intrinsic;
727
728
forward TrivialSpace;
729
intrinsic ModularSymbols(eps::Rec, k::RngIntElt,
730
sign::RngIntElt) -> ModTupFld
731
{Returns the space of modular symbols of character eps and weight k.
732
The level and base field are specified by the DirichletCharacter
733
eps. The third argument "sign" allows for working in certain
734
quotients. The possible values are -1, 0, or +1, which correspond
735
to the -1 quotient, full space, and +1 quotient.}
736
if not (-1 le sign and sign le 1) then
737
error "sign must be -1, 0, or 1";
738
end if;
739
if k lt 2 then
740
error "Modular symbols are only defined for weight k >= 2.";
741
end if;
742
743
N := CharacterLevel(eps);
744
F := FieldOfValues(eps);
745
if HeckeVerbose then
746
tt := Cputime();
747
printf "Creating M_%o(Gamma_1(%o),eps;F_%o)",
748
k, N, Characteristic(F) eq 0 select 0 else #F;
749
if sign eq 1 then
750
printf "^+";
751
elif sign eq -1 then
752
printf "^-";
753
end if;
754
if not HeckeSuperverbose then
755
printf "\n";
756
end if;
757
end if;
758
759
if Evaluate(eps,-1) ne (-1)^k then
760
return TrivialSpace(k,eps,sign);
761
end if;
762
763
if HeckeSuperverbose then
764
t := Cputime(); "Step I. Manin symbols list.";
765
end if;
766
mlist := ManinSymbolList(k,N,F);
767
if HeckeSuperverbose then
768
Cputime(t), " seconds.";
769
end if;
770
771
if HeckeSuperverbose then
772
t := Cputime(); "Step II. 2-term relations.";
773
end if;
774
Sgens, Squot, Scoef := ManSym2termQuotient(mlist, eps, sign);
775
if HeckeSuperverbose then
776
Cputime(t), " seconds.";
777
end if;
778
779
if #Sgens lt 1 then
780
return TrivialSpace(k,eps,sign);
781
end if;
782
783
if HeckeSuperverbose then
784
t := Cputime(); "Step III. 3-term relations.";
785
end if;
786
Tgens, Tquot := ManSym3termQuotient(mlist, eps, Sgens, Squot, Scoef);
787
if HeckeSuperverbose then
788
Cputime(t), " seconds.";
789
end if;
790
if #Tgens lt 1 then
791
return TrivialSpace(k,eps,sign);
792
end if;
793
794
V := VectorSpace(F,#Tgens);
795
796
// The reason we use "WithBasis" is that for some reason Magma
797
// distinguishes different elements of the category ModTupFld
798
// created via this constructor (it still says they are equal but
799
// their attributes are kept distinct). If we did not use WithBasis,
800
// then any two space of modular symbols of the same dimension
801
// would be equal. Someday this will be replaced with
802
// MY OWN CATEGORY. It is best to use this hack for now,
803
// so in the future, when I get a category, minimal changes
804
// will be necessary.
805
M := VectorSpaceWithBasis(Basis(V));
806
SetCategory(M,ModSym);
807
M`k := k;
808
M`N := N;
809
M`eps := eps;
810
M`sign := sign;
811
M`F := F;
812
M`mlist:= mlist;
813
M`quot := rec<CQuotient |
814
Sgens := Sgens,
815
Squot := Squot,
816
Scoef := Scoef,
817
Tgens := Tgens,
818
Tquot := Tquot>;
819
// M`quot`Tquot lies in V and really M is almost a V, so there
820
// is a possibility of a "circular reference bug" in Magma
821
// leading to a memory leak!
822
M`quot`Tquot := [V!v : v in M`quot`Tquot]; // move them into M.
823
if HeckeVerbose then
824
", ",Cputime(tt), "seconds.";
825
end if;
826
return M;
827
end intrinsic;
828
829
function TrivialSpace(k,eps,sign)
830
F := FieldOfValues(eps);
831
V := VectorSpace(F,0);
832
N := CharacterLevel(eps);
833
M := VectorSpaceWithBasis(Basis(V));
834
M`k := k;
835
M`N := N;
836
M`eps := eps;
837
M`sign := sign;
838
M`F := F;
839
M`quot := rec<CQuotient | Sgens:=[], Squot:=[],
840
Scoef:=[], Tgens := [], Tquot:=[]>;
841
SetCategory(M,ModSym);
842
return M;
843
end function;
844
845
intrinsic Weight(M::ModTupFld) -> RngIntElt
846
{Return the weight of the space M of modular symbols.}
847
if not assigned M`k then return Weight(ModSymParent(M)); end if;
848
return M`k;
849
end intrinsic;
850
851
intrinsic Level(M::ModTupFld) -> RngIntElt
852
{Return the level of the space M of modular symbols.}
853
return M`N;
854
end intrinsic;
855
856
intrinsic Conductor(M::ModTupFld) -> RngIntElt
857
{Return the level of the space M of modular symbols.}
858
return M`N;
859
end intrinsic;
860
861
intrinsic BaseField(M::ModTupFld) -> .
862
{Return the base field of the space M of modular symbols.}
863
if not assigned M`F then
864
return BaseField(ModSymParent(M));
865
end if;
866
return M`F;
867
end intrinsic;
868
869
intrinsic Character(M::ModTupFld) -> SeqEnum
870
{Return the Dirichlet character of the space M of modular symbols.}
871
case GetCategory(M):
872
when ModSym:
873
return M`eps;
874
when ModSymFac:
875
return M`M`eps;
876
else:
877
error "Character -- invalid input type.";
878
end case;
879
end intrinsic
880
881
intrinsic IsPlusQuotient(M::ModTupFld) -> SeqEnum
882
{Return true iff working in the plus one quotient of the
883
space M of modular symbols.}
884
if not assigned M`sign then return M`M`sign eq 1; end if;
885
return M`sign eq 1;
886
end intrinsic;
887
888
intrinsic IsMinusQuotient(M::ModTupFld) -> SeqEnum
889
{Return true iff working in the plus one quotient of
890
the space M of modular symbols.}
891
if not assigned M`sign then return M`M`sign eq -1; end if;
892
return M`sign eq -1;
893
end intrinsic;
894
895
intrinsic Sign(M::ModTupFld) -> RngIntElt
896
{Returns the sign of M.}
897
if not assigned M`sign then return M`M`sign; end if;
898
return M`sign;
899
end intrinsic;
900
901
intrinsic IsogenyClass(A::ModTupFld) -> RngIntElt
902
{Returns the isogeny class of A.}
903
if not assigned A`iso then
904
return 0;
905
end if;
906
return A`iso;
907
end intrinsic;
908
909
910
911
912
/*********************************************************
913
* *
914
* COMPUTE HECKE OPERATORS *
915
* *
916
*********************************************************/
917
intrinsic HeilbronnMerel(n::RngIntElt) -> SeqEnum
918
{Return Heilbronn matrices of determinant n, as given by Merel.
919
Here n can be composite.}
920
H := [];
921
i := 0;
922
for a in [1..n] do
923
for d in [1..n] do;
924
// ad-bc=n so c=0 and ad=n, or b=(ad-n)/c
925
bc := a*d - n;
926
if bc lt 0 then
927
continue;
928
end if;
929
if bc eq 0 then
930
for b in [0..a-1] do
931
Append(~H,[a,b,0,d]);
932
end for;
933
end if;
934
if bc ne 0 then
935
for c in Divisors(Abs(bc)) do
936
if c lt d and Floor(bc/c) lt a then
937
Append(~H,[a,Floor(bc/c),c,d]);
938
end if;
939
end for;
940
elif 0 lt a then
941
for c in [1..d-1] do
942
Append(~H,[a,0,c,d]);
943
end for;
944
end if;
945
end for;
946
end for;
947
return H;
948
end intrinsic;
949
950
951
intrinsic HeilbronnCremona(p::RngIntElt) -> SeqEnum
952
{Return the Heilbronn matrices of determinant p, as defined by Cremona.}
953
assert IsPrime(p);
954
if p eq 2 then
955
return [[1,0, 0,2], [2,0, 0,1], [2,1, 0,1], [1,0, 1,2]];
956
end if;
957
ans := [[1,0, 0,p]];
958
for r in [Ceiling(-p/2)..Floor(p/2)] do
959
x1:=p; x2:=-r; y1:=0; y2:=1; a:=-p; b:=r; c:=0; x3:=0; y3:=0; q:=0;
960
Append(~ans, [x1,x2, y1,y2]);
961
while b ne 0 do
962
q := Round(a/b);
963
c := a-b*q;
964
a := -b;
965
b := c;
966
x3 := q*x2-x1;
967
x1 := x2; x2 := x3; y3 := q*y2-y1; y1 := y2; y2 := y3;
968
Append(~ans, [x1,x2, y1, y2]);
969
end while;
970
end for;
971
return ans;
972
end intrinsic;
973
974
intrinsic Heilbronn(n::RngIntElt) -> SeqEnum
975
{If n is prime, return Cremona's Heilbronn matrices; otherwise
976
return Merel's.}
977
requirege n,1;
978
if IsPrime(n) then
979
return HeilbronnCremona(n);
980
else
981
return HeilbronnMerel(n);
982
end if;
983
end intrinsic;
984
985
// m is a sequence <alp, i> representing sum alp*e_i,
986
// where e_i runs through the initial list of
987
// generating Manin symbols.
988
intrinsic InitialManinSymbolGenListToSquot(m::SeqEnum, M::ModTupFld,
989
Tmat::ModMatFldElt)
990
-> ModTupFldElt
991
{}
992
Tquot := M`quot`Tquot;
993
V:=Parent(Tquot[1]);
994
Sgens := M`quot`Sgens;
995
Scoef := M`quot`Scoef;
996
Squot := M`quot`Squot;
997
// Tmat is a map from W to V, where W is
998
W:=VectorSpace(Field(V),#Sgens);
999
v := W!0;
1000
for t in m do
1001
v[Squot[t[2]]] +:= t[1]*Scoef[t[2]];
1002
end for;
1003
return v;
1004
end intrinsic;
1005
1006
intrinsic InitialManinSymbolGenListToM(m::SeqEnum, M::ModTupFld)
1007
-> ModTupFldElt
1008
{}
1009
Scoef := M`quot`Scoef;
1010
Tquot := M`quot`Tquot;
1011
V:=Parent(Tquot[1]);
1012
Squot := M`quot`Squot;
1013
return &+[V|t[1]*Scoef[t[2]]
1014
*Tquot[Squot[t[2]]] : t in m];
1015
end intrinsic;
1016
1017
///////////////////////////////////////////////////////////////
1018
// COMPUTATION of HECKE OPERATORS //
1019
///////////////////////////////////////////////////////////////
1020
1021
intrinsic Tn(M::ModTupFld, n::RngIntElt) -> AlgMatElt
1022
{}
1023
return HeckeOperator(M,n);
1024
end intrinsic;
1025
1026
intrinsic HeckeOperator(M::ModTupFld, n::RngIntElt) -> AlgMatElt
1027
{}
1028
requirege n,1;
1029
return HeckeOperator(M,Heilbronn(n));
1030
end intrinsic;
1031
1032
intrinsic HeckeOperator(M::ModTupFld, Heil::SeqEnum) -> AlgMatElt
1033
{Compute the n-th Hecke operator Tn on the space M of modular symbols.}
1034
if Dimension(M) eq 0 then
1035
return Hom(M,M)!0;
1036
end if;
1037
1038
F := M`F;
1039
mlist := M`mlist;
1040
eps := M`eps;
1041
1042
quot := M`quot;
1043
Sgens := quot`Sgens;
1044
Squot := quot`Squot;
1045
Tgens := quot`Tgens;
1046
Tquot := quot`Tquot;
1047
1048
1049
Mn := MatrixAlgebra(F,Dimension(M));
1050
V := Parent(Tquot[1]);
1051
T := [];
1052
1053
W := VectorSpace(F, #Sgens);
1054
Tmat := RMatrixSpace(F, Dimension(W), Dimension(V)) !
1055
[Tquot[i] : i in [1..#Sgens]];
1056
1057
for j in [1..#Tgens] do
1058
i := Sgens[Tgens[j]];
1059
v := InitialManinSymbolGenListToSquot(
1060
&cat[ ManinSymbolApply(h,i, mlist,eps)
1061
: h in Heil],
1062
M,Tmat);
1063
Append(~T,v);
1064
end for;
1065
S := RMatrixSpace(F, #T, #Sgens) ! T;
1066
return Mn!(S*Tmat);
1067
end intrinsic;
1068
1069
intrinsic TnSparse(M::ModTupFld, n::RngIntElt, sparsevec::SeqEnum)
1070
-> AlgMatElt
1071
{}
1072
requirege n,1;
1073
if HeckeSuperverbose then
1074
"TnSparse ", n;
1075
end if;
1076
return TnSparse(M, Heilbronn(n), sparsevec);
1077
end intrinsic;
1078
1079
1080
intrinsic TnSparse(M::ModTupFld, Heil::SeqEnum, sparsevec::SeqEnum)
1081
-> AlgMatElt
1082
{Compute the action of the Hecke operator defined by the
1083
Heilbronn matrices Heil on the sparse vector v.}
1084
1085
if Dimension(M) eq 0 then
1086
return M!0;
1087
end if;
1088
F := M`F;
1089
k := M`k;
1090
mlist := M`mlist;
1091
eps := M`eps;
1092
quot := M`quot;
1093
Sgens := quot`Sgens;
1094
Tgens := quot`Tgens;
1095
Tquot := quot`Tquot;
1096
1097
Mn := MatrixAlgebra(F,Dimension(M));
1098
v := M!0;
1099
for m in sparsevec do
1100
i := Sgens[Tgens[m[2]]];
1101
if k eq 2 then // faster, since always just one entry.
1102
x := [ ManinSymbolApply(h,i, mlist,eps)[1] : h in Heil];
1103
else
1104
x := &cat[ ManinSymbolApply(h,i, mlist,eps) : h in Heil];
1105
end if;
1106
v +:= m[1]*InitialManinSymbolGenListToM(x,M);
1107
end for;
1108
return v;
1109
end intrinsic;
1110
1111
1112
1113
/*******************************************************
1114
CyclicHeckeImage:
1115
The goal of this function is to compute
1116
the cyclic Hecke module generated by a vector v.
1117
The result is returned as a subspace with Z-basis.
1118
1119
Let Tn be the matrix representing the right
1120
action of the nth Hecke operator on P.
1121
We must compute gens for an F-module who (Z-span) equals
1122
span {Tn*v : 1<=n<=b}
1123
where b is a bound on the number of Tn necessary
1124
to generate the Hecke algebra as a Z-module.
1125
1126
We do this by:
1127
1) Computing Mp for p prime using Hecke action on
1128
easy elements of M_k(Q).
1129
2) Iteratively computing prod Mp^i*c where n=prod
1130
p^i varies from 1 to b.
1131
*********************************************************/
1132
1133
intrinsic SparseRepresentation(v::ModTupFldElt) -> SeqEnum
1134
{Return sparse representation of vector v.}
1135
sp := [];
1136
v := Eltseq(v);
1137
for i in [1..#v] do
1138
if v[i] ne 0 then
1139
Append(~sp, <v[i],i>);
1140
end if;
1141
end for;
1142
return sp;
1143
end intrinsic;
1144
1145
1146
intrinsic HeckeBound(M::ModTupFld) -> RngIntElt
1147
{Returns a bound b such that T1, ..., Tb generate the Hecke
1148
algebra as a Z-module.}
1149
b := HeckeBound(M`k, M`N);
1150
if not IsTrivial(M`eps) then
1151
" Warning: William Stein has not proved that his bound on the number";
1152
" of Hecke operators needed to generate the Hecke algebra is correct";
1153
" when Character(M) is not trivial.";
1154
b *:= 3;
1155
end if;
1156
return b;
1157
end intrinsic;
1158
1159
forward idxG0;
1160
intrinsic HeckeBound(k::RngIntElt, N::RngIntElt) -> RngIntElt
1161
{Returns a bound b such that T1, ..., Tb generate the Hecke
1162
algebra as a Z-module.}
1163
return Ceiling(k * idxG0(N) / 12);
1164
end intrinsic;
1165
1166
intrinsic VectorSpaceZBasis(B::SeqEnum) -> ModTupFld
1167
{Return vector space with basis the lattice defined by the elements of B.}
1168
V := VectorSpace(Parent(B[1][1]),#Eltseq(B[1]));
1169
Latbase := Basis(Lattice(
1170
RMatrixSpace(Rationals(),#B, Dimension(V))!B));
1171
return VectorSpaceWithBasis([V!v : v in Latbase]);
1172
end intrinsic;
1173
1174
intrinsic HeckeSpan(v::ModTupFldElt, M::ModTupFld) -> ModTupFld
1175
{This function computes
1176
the Hecke module generated by a vector v.
1177
The result is returned as a subspace with Z-basis.}
1178
1179
s := SparseRepresentation(v);
1180
b := HeckeBound(M);
1181
B := [v] cat [TnSparse(M, n, s) : n in [2..b]];
1182
return VectorSpaceZBasis(B);
1183
end intrinsic;
1184
1185
intrinsic HeckeSpan(V::ModTupFld, M::ModTupFld) -> ModTupFld
1186
{This function computes
1187
the Hecke module generated by a basis of V.
1188
The result is returned as a subspace
1189
with Z-basis.}
1190
1191
S := [SparseRepresentation(v) : v in Basis(V)];
1192
b := HeckeBound(M);
1193
H := [Heilbronn(n) : n in [1..b]];
1194
B := &cat[[TnSparse(M, H[n], s) : n in [1..b]] : s in S];
1195
return VectorSpaceZBasis(B);
1196
end intrinsic;
1197
1198
1199
/******************************************************
1200
* Computation of T_p on dual space. *
1201
******************************************************/
1202
CFastData := recformat< V, e, VEinv>;
1203
1204
intrinsic FastTnData(M::ModTupFld, V::SeqEnum) -> Rec
1205
{Compute data needed by FastTn.}
1206
1207
// Step 1: find a set of very simple vectors e[1],...,e[n]
1208
// in M such that det(v[i]*e[j]) =/= 0.
1209
// 1. [Compute e] e = set of positions so that elements of the space
1210
// spanned by the columns of V are determined by the entries in these
1211
// spots. This is accomplished by row reducing, and setting e equal to
1212
// the sequence of column numbers for which the columns are pivotal.
1213
1214
n := #V;
1215
B := Basis(sub<M|V>);
1216
assert #B eq n;
1217
// Find pivot columns.
1218
e := Pivots(B);
1219
1220
// Step 2: Compute the matrix V*E of inner products.
1221
VE := RMatrixSpace(M`F,n,n)![V[i][e[j]] : i in [1..n], j in [1..n]];
1222
VEinv := VE^(-1);
1223
1224
return rec<CFastData| V:=V, e:=e, VEinv:=VEinv>;
1225
end intrinsic;
1226
1227
intrinsic FastTnData(M::ModTupFld, V::ModTupFld) -> Rec
1228
{}
1229
return FastTnData(M, Basis(V));
1230
end intrinsic;
1231
1232
intrinsic FastTn(M::ModTupFld, FastData::Rec, n::RngIntElt)
1233
-> AlgMatElt
1234
{}
1235
return FastTn(M,FastData,n,Heilbronn(n));
1236
end intrinsic;
1237
1238
intrinsic FastTn(M::ModTupFld, FastData::Rec, n::RngIntElt, H::SeqEnum)
1239
-> AlgMatElt
1240
{Compute action of Transpose(Tn) on the Hecke-stable
1241
subspace V.}
1242
F := M`F;
1243
V := FastData`V;
1244
n := #V;
1245
m := Dimension(M);
1246
e := FastData`e;
1247
VEinv := FastData`VEinv;
1248
// The next step is where all of the time is spent.
1249
TE := [TnSparse(M, H, [<1,e[i]>]) : i in [1..n]];
1250
Vmat := RMatrixSpace(F, n, m) ! V;
1251
TEmat := RMatrixSpace(F, n, m) ! TE;
1252
return MatrixAlgebra(F,n)!(Vmat*Transpose(TEmat)*VEinv);
1253
end intrinsic;
1254
1255
intrinsic FastTn(FastData::Rec, n::RngIntElt, M::ModTupFld)
1256
-> AlgMatElt
1257
{}
1258
return FastTn(M,FastData,n,Heilbronn(n));
1259
end intrinsic;
1260
1261
intrinsic FastTn(M::ModTupFld, V::ModTupFld, n::RngIntElt)
1262
-> AlgMatElt, Rec
1263
{Compute action of Transpose(Tn) on the Hecke-stable
1264
subspace V.}
1265
FastData := FastTnData(M, V);
1266
return FastTn(M, FastData, n);
1267
end intrinsic;
1268
1269
intrinsic FastTn(M::ModTupFld, V::ModTupFld, n::RngIntElt, H::SeqEnum)
1270
-> AlgMatElt, Rec
1271
{Compute action of Transpose(Tn) on the Hecke-stable
1272
subspace V.}
1273
FastData := FastTnData(V,M);
1274
return FastTn(M, FastData, n, H);
1275
end intrinsic;
1276
1277
intrinsic FastTn( M::ModTupFld, V::ModTupFld, nlist::SeqEnum,
1278
H::SeqEnum)
1279
-> SeqEnum, Rec
1280
{Compute action of Transpose(Tn), n in plist, on the Hecke-stable
1281
subspace V.}
1282
FastData := FastTnData(M, V);
1283
return [FastTn(M, FastData, n, H[n]): n in nlist];
1284
end intrinsic;
1285
1286
intrinsic FastTn(M::ModTupFld, V::ModTupFld, nlist::SeqEnum)
1287
-> SeqEnum, Rec
1288
{Compute action of Transpose(Tn), n in nlist, on the Hecke-stable
1289
subspace V.}
1290
FastData := FastTnData(M,V);
1291
return [FastTn(M, FastData, n): n in nlist];
1292
end intrinsic;
1293
1294
1295
1296
/******************************************************
1297
Action of T_n on modular symbols basis.
1298
******************************************************/
1299
1300
function ActionOnModularSymbolsBasis(g, M)
1301
// 1. Compute basis of modular symbols for M.
1302
B := ModularSymbolsBasis(M);
1303
// 2. Apply g to each basis element.
1304
gB := [ModularSymbolApply(M, g,B[i]) : i in [1..#B]];
1305
// 3. Map the result back to M.
1306
gM := [ConvFromModularSymbol(M,gB[i]) : i in [1..#gB]];
1307
return MatrixAlgebra(M`F,Dimension(M))!gM;
1308
end function;
1309
1310
1311
1312
// Compute the action of the Atkin-Lehner involution on M,
1313
// when this makes sense.
1314
intrinsic Wq(M::ModTupFld, q::RngIntElt) -> AlgMatElt
1315
{Compute the action of the Atkin-Lehner involution Wq on M,
1316
when this makes sense (i.e., trivial character, even weight).
1317
The Atkin-Lehner map Wq is rescaled so that it is an
1318
involution, except when k>2 and char(F) divides q.}
1319
if GetCategory(M) eq ModSymFac then
1320
return Restrict(Transpose(Wq(ModSymParent(M),q)),M);
1321
end if;
1322
N := M`N;
1323
k := M`k;
1324
assert q ne 0;
1325
assert N mod q eq 0;
1326
assert k mod 2 eq 0;
1327
assert IsTrivial(M`eps);
1328
repeat
1329
d := Gcd(Integers()!(N/q),q);
1330
if d eq 1 then break; end if;
1331
q *:= d;
1332
until false;
1333
assert (N mod q) eq 0;
1334
// 1. Compute matrix to act by.
1335
d, x, y:= XGCD(q,-Integers()!(N/q));
1336
g := [q*x, y, N, q];
1337
A := ActionOnModularSymbolsBasis(g, M);
1338
p := Characteristic(M`F);
1339
if p eq 0 or q mod p ne 0 then
1340
A /:= q^(Integers()!(k/2)-1);
1341
end if;
1342
return A;
1343
end intrinsic;
1344
1345
intrinsic StarInvolution(M::ModTupFld) -> AlgMatElt
1346
{Compute the conjugation involution * on V. This involution
1347
is defined by the 2x2 matrix [-1,0,0,1]; it sends
1348
X^i*Y^j\{u,v\} to (-1)^j*X^i*Y^j \{-u,-v\}.}
1349
return ActionOnModularSymbolsBasis([-1,0,0,1], M);
1350
end intrinsic;
1351
1352
intrinsic Tnpoly(n::RngIntElt, M::ModTupFld) -> SeqEnum
1353
{Compute the characteristic polynomial of the p-th Hecke
1354
operator Tn on the space M of modular symbols. Uses the modular
1355
algorithm, without proof.}
1356
return ModularCharpoly(HeckeOperator(n,M));
1357
end intrinsic;
1358
1359
intrinsic Restrict (A::AlgMatElt, L::Lat) -> AlgMatElt
1360
{ Suppose A is a linear transformation of V
1361
which leaves the lattice L invariant.
1362
Returns A restricted to W, with respect to
1363
the basis Basis(W).}
1364
Z := Basis(L);
1365
V := VectorSpace(Parent(A[1,1]), Dimension(L));
1366
B := [V!Z[i] : i in [1..Dimension(V)]];
1367
return Restrict (A, B);
1368
end intrinsic;
1369
1370
intrinsic Restrict (A::AlgMatElt, W::ModTupFld) -> AlgMatElt
1371
{ Suppose A is a linear transformation of V
1372
which leaves the subspace W invariant.
1373
Returns A restricted to W, with respect to
1374
the basis Basis(W). }
1375
B := Basis(W);
1376
return Restrict (A, B);
1377
end intrinsic;
1378
1379
intrinsic Restrict (A::AlgMatElt, W::ModTupRng) -> AlgMatElt
1380
{ Suppose A leaves W invariant.
1381
Returns A restricted to W, with respect to
1382
the basis Basis(W).}
1383
B := Basis(W);
1384
return Restrict (A, B);
1385
end intrinsic;
1386
1387
intrinsic Restrict (A::AlgMatElt, B::SeqEnum) -> AlgMatElt
1388
{ Suppose A is a linear transformation of V
1389
which leaves the subspace W spanned by the
1390
vectors listed in B invariant.
1391
Returns A restricted to W, with respect to
1392
the basis B.}
1393
S := RSpaceWithBasis(B);
1394
return MatrixAlgebra(Parent(A[1,1]),#B) !
1395
&cat[Coordinates(S, S.i*A) : i in [1..#B]];
1396
end intrinsic;
1397
1398
1399
intrinsic KernelOn (A::AlgMatElt, B::SeqEnum) -> ModTupFld
1400
{Suppose B is a basis for an n-dimensional subspace
1401
of some ambient space and A is an nxn matrix.
1402
Then A defines a linear transformation of the space
1403
spanned by B. This function returns the
1404
kernel of that transformation.}
1405
n := #B;
1406
if n eq 0 then
1407
return B;
1408
end if;
1409
assert Nrows(A) eq Ncols(A) and Nrows(A) eq n;
1410
K := Kernel(A);
1411
return VectorSpaceWithBasis(LinearCombinations(Basis(K),B));
1412
end intrinsic;
1413
1414
intrinsic KernelOn (A::AlgMatElt, W::ModTupFld) -> ModTupFld
1415
{}
1416
return KernelOn (A, Basis(W));
1417
end intrinsic;
1418
1419
intrinsic HeckeOperatorOn(M::ModTupFld, V::ModTupFld, n::RngIntElt)
1420
-> AlgMatElt
1421
{Compute the action of the Hecke operator Tn with
1422
respect to the basis for the subspace V of M.}
1423
return Restrict(HeckeOperator(M,n), V);
1424
end intrinsic;
1425
1426
intrinsic HeckeOperatorMkZ(M::ModTupFld, n::RngIntElt) -> AlgMatElt
1427
{Compute the action of Tn on the integral modular symbols.}
1428
return Restrict(HeckeOperator(M,n), IntegralModularSymbols(M));
1429
end intrinsic;
1430
1431
intrinsic HeckeOperatorSkZ(M::ModTupFld, n::RngIntElt) -> AlgMatElt
1432
{Compute the action of T_p on a subspace of integral modular symbols.}
1433
return Restrict(HeckeOperator(M,n), SkZ(M));
1434
end intrinsic;
1435
1436
1437
1438
/**********************************************************
1439
* *
1440
* BOUNDARY SYMBOLS: Compute the boundary map delta. *
1441
* *
1442
**********************************************************/
1443
1444
1445
///////////////////////////////////////////////////////////////////////////
1446
//////////// IMPLEMENTATION 2: CUSPS FOR NONTRIVIAL CHARACTER /////////////
1447
///////////////////////////////////////////////////////////////////////////
1448
function ReduceCusp(a)
1449
d := Gcd(a);
1450
return [Integers()|x/d : x in a];
1451
end function;
1452
1453
function CuspEquiv(N,a,b)
1454
u1, v1 := Explode(ReduceCusp(a));
1455
u2, v2 := Explode(ReduceCusp(b));
1456
s1 := 0;
1457
s2 := 0;
1458
if [u1,v1] ne [0,1] then
1459
s1 := (v1 eq 0 or v1 eq 1) select 1 else InverseMod(u1,Abs(v1));
1460
end if;
1461
if [u2,v2] ne [0,1] then
1462
s2 := (v2 eq 0 or v2 eq 1) select 1 else InverseMod(u2,Abs(v2));
1463
end if;
1464
g := Gcd(v1*v2,N);
1465
a := s1*v2 - s2*v1;
1466
if a mod g ne 0 then
1467
return false, 1;
1468
end if;
1469
1470
// Now we know the cusps are equivalent. Use the proof of Prop2.2.3
1471
// of Cremona to find a matrix in Gamma_0(N) relating them.
1472
dum,s2,r2 := Xgcd(u2,-v2);
1473
assert dum eq 1;
1474
dum,s1,r1 := Xgcd(u1,-v1);
1475
assert dum eq 1;
1476
a := s1*v2 - s2*v1;
1477
assert a mod g eq 0;
1478
// solve x*v1*v2 + a = 0 (mod N).
1479
d,x0,y0 := Xgcd(v1*v2,N); // x0*v1*v2 + y0*N = d = g.
1480
// so x0*v1*v2 - g = 0 (mod N)
1481
x := -x0 * Integers()!(a/g);
1482
// now x*v1*v2 + a = 0 (mod N)
1483
s1p := s1+x*v1;
1484
return true, (u2*s1p-r2*v1) mod N;
1485
end function;
1486
1487
function CuspToFreeHelper(M, sign, a)
1488
if not assigned M`cusplist then
1489
M`cusplist := [];
1490
end if;
1491
1492
list := M`cusplist;
1493
F := M`F;
1494
eps := M`eps;
1495
N := M`N;
1496
k := M`k;
1497
1498
a := ReduceCusp(a);
1499
if a[2] lt 0 then
1500
a[1] *:= F!-1;
1501
a[2] *:= F!-1;
1502
end if;
1503
1504
// Check if we've already encountered this cusp.
1505
for i in [1..#list] do
1506
b := list[i];
1507
equiv, alp := CuspEquiv(N, b[1], a); // [gam_alp(b[1])]=?=[a].
1508
if equiv then
1509
if b[2] eq 0 then
1510
return <F!0,1>;
1511
end if;
1512
if IsTrivial(Character(M)) then
1513
return <1,i>;
1514
else
1515
return <Evaluate(eps,alp)^(-1),i>;
1516
end if;
1517
end if;
1518
if sign ne 0 then
1519
equiv, alp := CuspEquiv(N, b[1], [-a[1],a[2]]);
1520
if equiv then
1521
if b[2] eq 0 then
1522
return <F!0,1>;
1523
end if;
1524
if IsTrivial(Character(M)) then
1525
return <sign,i>;
1526
else
1527
return <sign*Evaluate(eps,alp),i>;
1528
end if;
1529
end if;
1530
end if;
1531
end for;
1532
1533
// Determine if this cusp class is killed by the relations.
1534
c := F!1;
1535
if not IsTrivial(Character(M)) then
1536
u := a[1]; v := a[2];
1537
g := Gcd(N,v);
1538
x := Integers()!(N/Gcd(N,v));
1539
for j in [0..g-1] do
1540
alp := 1-j*x;
1541
if Gcd(alp,N) eq 1 then
1542
if (v*(1-alp)) mod N eq 0 and (u*(1-alp)) mod g eq 0 then
1543
if Evaluate(eps,alp) ne 1 then
1544
c := F!0;
1545
break;
1546
end if;
1547
end if;
1548
end if;
1549
end for;
1550
end if;
1551
1552
Append(~list,<a,c>);
1553
M`cusplist := list;
1554
i := #list;
1555
1556
if sign ne 0 then
1557
// Check is sign relation kills this cusp.
1558
ans := CuspToFreeHelper(M,0,[-a[1],a[2]]);
1559
if ans[2] eq i and ans[1] ne sign then
1560
M`cusplist[i][2] := 0;
1561
c := F!0;
1562
end if;
1563
end if;
1564
1565
return <c,i>;
1566
end function;
1567
1568
intrinsic CuspToFree(M::ModTupFld, a::SeqEnum) -> Tup
1569
{Given a cusp a=[u,v] this function finds the index i and a
1570
scalar alpha such that a = alpha*(i-th standard cusp).
1571
It then returns alpha, i.}
1572
return CuspToFreeHelper(M,Sign(M),a);
1573
end intrinsic;
1574
1575
forward LiftToCosetRep;
1576
intrinsic BoundaryMap(M::ModTupFld) -> ModMatFldElt
1577
{Compute the Boundary map.}
1578
if not assigned M`BoundaryMap then
1579
if Dimension(M) eq 0 then
1580
M`BoundaryMap := RMatrixSpace(M`F,0,0)!0;
1581
return M`BoundaryMap;
1582
end if;
1583
Tgens := M`quot`Tgens;
1584
Sgens := M`quot`Sgens;
1585
F := M`F;
1586
n := #Tgens;
1587
D := [ [] : i in [1..n]];
1588
for j in [1..n] do
1589
i := Sgens[Tgens[j]];
1590
uv, w, ind := UnwindManinSymbol(i,M`mlist);
1591
g := LiftToCosetRep(uv, M`N);
1592
if w eq M`k-2 then
1593
Append(~D[j], CuspToFree(M,[g[1],g[3]]));
1594
end if;
1595
if w eq 0 then // substract the second term.
1596
t := CuspToFree(M,[g[2],g[4]]);
1597
t[1] *:= -1;
1598
Append(~D[j], t);
1599
end if;
1600
end for;
1601
if &cat D eq [] then
1602
M`BoundaryMap := RMatrixSpace(M`F,Dimension(M),0)!0;
1603
return M`BoundaryMap;
1604
end if;
1605
m := Max([x[2] : x in &cat D]);
1606
V := VectorSpace(F,m);
1607
Drows := [&+[V| x[1]*V.x[2] : x in D[i]] : i in [1..n]];
1608
M`BoundaryMap := RMatrixSpace(M`F,n,m) ! Drows;
1609
end if;
1610
return M`BoundaryMap;
1611
end intrinsic;
1612
1613
1614
1615
1616
1617
1618
1619
intrinsic CuspidalSymbols(M::ModTupFld) -> ModTupFld
1620
{Return the subspace of S_k(N,Q) of cuspidal modular symbols.}
1621
if not assigned M`SkF then
1622
M`SkF := Kernel(BoundaryMap(M));
1623
end if;
1624
return M`SkF;
1625
end intrinsic;
1626
1627
intrinsic CuspidalSymbols(M::ModTupFld) -> ModTupFld
1628
{Return the subspace of S_k(N,Q) of cuspidal modular symbols.}
1629
if not assigned M`SkF then
1630
D := BoundaryMap(M);
1631
if HeckeSuperverbose then
1632
"Computing kernel of boundary map: ";
1633
t := Cputime();
1634
end if;
1635
M`SkF := Kernel(D);
1636
if HeckeSuperverbose then
1637
Cputime(t), " seconds.";
1638
end if;
1639
end if;
1640
return M`SkF;
1641
end intrinsic;
1642
1643
intrinsic Sk(M::ModTupFld) -> ModTupFld
1644
{}
1645
return CuspidalSymbols(M);
1646
end intrinsic;
1647
1648
intrinsic IntegralCuspidalSymbols(M::ModTupFld) -> ModTupFld
1649
{}
1650
if not assigned M`SkZ then
1651
Z := IntegralModularSymbols(M);
1652
D := BoundaryMap(M);
1653
DofZ := [v*D : v in Basis(Z)];
1654
DZ := RMatrixSpace(M`F,Nrows(D),Ncols(D)) ! DofZ;
1655
M`SkZ := VectorSpaceWithBasis(
1656
LinearCombinations(Basis(IntegerKernel(DZ)), Basis(Z))
1657
);
1658
end if;
1659
return M`SkZ;
1660
end intrinsic;
1661
1662
1663
intrinsic SkZ(M::ModTupFld) -> ModTupFld
1664
{}
1665
case GetCategory(M):
1666
when ModSym: return IntegralCuspidalSymbols(M);
1667
when ModSymFac: return DecompZ(M);
1668
else error "SkZ only takes a ModSym or ModSymFac as argument.";
1669
end case;
1670
end intrinsic;
1671
1672
intrinsic SkZPlus(M::ModTupFld) -> ModTupFld
1673
{}
1674
if not assigned M`SkZplus then
1675
S := SkZ(M);
1676
star := Restrict(StarInvolution(M),S);
1677
M`SkZplus := IntegerKernelOn(star-1, S);
1678
end if;
1679
return M`SkZplus;
1680
end intrinsic;
1681
1682
intrinsic SkZMinus(M::ModTupFld) -> ModTupFld
1683
{}
1684
if not assigned M`SkZminus then
1685
S := SkZ(M);
1686
star := Restrict(StarInvolution(M),S);
1687
M`SkZminus := IntegerKernelOn(star+1, S);
1688
end if;
1689
return M`SkZminus;
1690
end intrinsic;
1691
1692
/*
1693
function EisensteinSymbols(M)
1694
end function;
1695
*/
1696
1697
1698
/*******************************************************************
1699
DEGENERACY COSET REPRESENTATIVES:
1700
Let N be a positive integer and M a divisor of N.
1701
Let t be a divisor of N/M, and let T be the 2x2 matrix T=[0,0, 0,t].
1702
Find coset reps for Gamma_0(N) \ T Gamma_0(M).
1703
1704
FACTS: T^(-1)*(a,b,c,d)*T = (a,bt,c/t,d)
1705
T^(-1)*Gamma_0(N)*T is contained in Gamma_0(M)
1706
Gamma_0(N)*T is contained in T*Gamma_0(M)
1707
1708
1709
SOLUTION:
1710
(1) Computes representatives for Gamma_0(N/t,t) inside
1711
of Gamma_0(M):
1712
COSET EQUIVALENCE:
1713
Two right cosets represented by (a,b;c,d) &
1714
(a',b';c',d') of Gamma_0(N/t,t) in SL_2(Z) are equivalent iff
1715
(a,b)=(a',b') as points of P^1(t), i.e., ab'=ba'(mod t),
1716
and (c,d)=(c',d') as points of P^1(N/t).
1717
ALGORITHM:
1718
(A) Compute the number of cosets.
1719
(B) Compute a random element x of Gamma_0(M).
1720
(C) Check if x is equivalent to anything generated so
1721
far; if not, add x to the list.
1722
(D) Continue until the list is as long as the bound
1723
computed in A.
1724
1725
(2) There is a natural bijection
1726
Gamma_0(N)\T*Gamma_0(M) <---> Gamma_0(N/t,t)\Gamma_0(M)
1727
given by
1728
Tr <---------> r
1729
Consequently we obtain coset representatives for
1730
Gamma_0(N)\T*Gamma_0(M) by left multiplying by T each
1731
coset representative of Gamma_0(N/t,t)\Gamma_0(M) found
1732
in step 1.
1733
********************************************************************/
1734
intrinsic DegeneracyCosetReps(M, N, d) -> .
1735
{}
1736
n := idxG0(N)/idxG0(M); // number of coset representatives.
1737
Ndivd := N div d;
1738
R := []; // coset reps found so far.
1739
max := 4*(n+10);
1740
halfmax := Round(max/2);
1741
while #R lt n do
1742
// try to find another coset representative.
1743
cc := M*Random(-halfmax, halfmax);
1744
dd := Random(-halfmax, halfmax);
1745
g, bb, aa := XGCD(-cc,dd);
1746
if g eq 0 then continue; end if;
1747
cc div:= g;
1748
dd div:= g;
1749
if cc mod M ne 0 then continue; end if;
1750
// Test if we've found a new coset representative.
1751
isnew:=true;
1752
for r in R do
1753
if ((r[2]*aa - r[1]*bb) mod d eq 0) and
1754
((r[4]*cc - r[3]*dd) mod Ndivd eq 0) then
1755
isnew := false;
1756
break ;
1757
end if;
1758
end for;
1759
// If it is new add it to the list.
1760
if isnew then
1761
Append(~R,[aa,bb,cc,dd]);
1762
end if;
1763
end while;
1764
// Return the list left multiplied by T.
1765
return [[r[1],r[2],r[3]*d,r[4]*d] : r in R];
1766
end intrinsic;
1767
1768
1769
/**********************************************************
1770
DEGENERACY AND INCLUSION MAPS -- newforms.
1771
If possible compute the map M1 --> M2 corresponding
1772
to the integer d.
1773
1774
WARNING: There might be a problem here when
1775
the characteristic of the base field divides d,
1776
because d occurs in the denominators of the
1777
DegeneracyReps.
1778
1779
d:=1;c:=3;M:=11;N:=M*d*c;
1780
A:=Mk(M,2); B:=Mk(N,2);
1781
bet:=dm(A,B,d); alp:=dm(B,A,d);
1782
bet*alp; // must be a scalar.
1783
1784
**********************************************************/
1785
intrinsic DegeneracyMap(M1::ModTupFld, M2::ModTupFld)
1786
-> AlgMatElt
1787
{If possible compute the map M1 --> M2 corresponding
1788
to the integer d.}
1789
return DegeneracyMap(M1,M2,1);
1790
end intrinsic;
1791
1792
intrinsic DegeneracyMap(M1::ModTupFld, M2::ModTupFld, d::RngIntElt)
1793
-> AlgMatElt
1794
{If possible compute the degeneracy map M1 --> M2 corresponding
1795
to the integer d. Here M1 and M2 are spaces of modular symbols,
1796
of the same weight and d is a divisor of the quotient of
1797
the two levels N1 and N2. If the N1 divides N2 then the
1798
"raising" map is computed, if N1 is divisible by N2,
1799
then the "lowering" map is computed.}
1800
assert M1`F eq M2`F;
1801
assert Weight(M1) eq Weight(M2);
1802
N1 := Level(M1);
1803
N2 := Level(M2);
1804
if N1 eq N2 then
1805
assert d eq 1;
1806
assert M1 eq M2; // we could write down the map between
1807
// different presentations of M_k(N), but
1808
// we won't for now, since there should
1809
// never be a need.
1810
F := BaseField(M1);
1811
return Hom(M1,M1)!MatrixAlgebra(F,Degree(M1))!1;
1812
end if;
1813
1814
if N1 mod N2 eq 0 then // N2 divides N1 -- lower
1815
assert (N1 div N2) mod d eq 0;
1816
B := ModularSymbolsBasis(M1);
1817
D := [d,0,0,1];
1818
DB := [ModularSymbolApply(M1,D, B[i]) : i in [1..#B] ];
1819
A := [ConvFromModularSymbol(M2,DB[i]) : i in [1..#DB]];
1820
return Hom(M1, M2) ! A;
1821
1822
elif N2 mod N1 eq 0 then// N1 divides N2 -- raise level
1823
assert (N2 div N1) mod d eq 0;
1824
B := ModularSymbolsBasis(M1);
1825
R := DegeneracyCosetReps(N1, N2, d);
1826
eps := Character(M1);
1827
if IsTrivial(eps) then
1828
RB := [ &cat[ModularSymbolApply(M1, r, B[i]) : r in R]
1829
: i in [1..#B]];
1830
A := [ConvFromModularSymbol(M2,RB[i]) : i in [1..#RB]];
1831
else
1832
A := [ &+[Evaluate(eps,r)^(-1)*ConvFromModularSymbol(M2,
1833
ModularSymbolApply(M1, r, B[i])) : r in R]
1834
: i in [1..#B]];
1835
end if;
1836
return Hom(M1, M2) ! A;
1837
else
1838
error "DegeneracyMap: N1 must be divisible by N2, or vice-versa.";
1839
end if;
1840
end intrinsic;
1841
1842
intrinsic OldModularSymbols(M::ModTupFld, NN::RngIntElt) -> ModTupFld
1843
{Returns the space Mk(NN,eps') associated to Mk(N,eps).
1844
Here NN must be a divisor of N.}
1845
N := Level(M);
1846
divs := Divisors(N);
1847
if not assigned M`old then
1848
M`old := SequenceToList(divs);
1849
end if;
1850
pos := Index(divs,NN);
1851
if pos eq 0 then
1852
error "NN =",NN,"is not a divisor of the level =",N;
1853
end if;
1854
if Type(M`old[pos]) eq RngIntElt then
1855
NN := Integers()!NN;
1856
eps := Character(M);
1857
if not CanReduceModM(eps,NN) then
1858
M`old[pos] := TrivialSpace(Weight(M),eps,Sign(M));
1859
else
1860
epsNN := AssociatedModMCharacter(eps,NN);
1861
M`old[pos] := ModularSymbols(epsNN,Weight(M),Sign(M));
1862
end if;
1863
end if;
1864
return M`old[pos];
1865
end intrinsic;
1866
1867
/**********************************************************
1868
For each prime p dividing the level there are two maps
1869
alp_1,alp_p: Mk(N,e) ----> Mk(N/p,e')
1870
The intersection
1871
Kernel(alp_1) meet Kernel(alp_p)
1872
is called the p-new subspace Mkpnew(N) of Mk(N).
1873
If e doesn't factor through (Z/(N/p)Z)^* then
1874
e' is by definition 0.
1875
********************************************************/
1876
intrinsic pNewSubspace(M::ModTupFld, p::RngIntElt) -> ModTupFld
1877
{Returns the p-new subspace of M.}
1878
assert IsPrime(p);
1879
N := Level(M);
1880
k := Weight(M);
1881
assert N mod p eq 0;
1882
1883
eps := Character(M);
1884
NN := Integers()!(N/p);
1885
1886
if not CanReduceModM(eps,NN) then
1887
return M;
1888
end if;
1889
1890
old := OldModularSymbols(M,NN);
1891
1892
if Dimension(old) eq 0 then
1893
return M;
1894
end if;
1895
h1 := DegeneracyMap(M, old, 1);
1896
hp := DegeneracyMap(M, old, p);
1897
return Kernel(h1) meet Kernel(hp);
1898
end intrinsic;
1899
1900
1901
intrinsic pNewDualSubspace(M::ModTupFld, p::RngIntElt) -> ModTupFld
1902
{Returns the p-new subspace of M.}
1903
assert IsPrime(p);
1904
N := Level(M);
1905
k := Weight(M);
1906
assert N mod p eq 0;
1907
1908
eps := Character(M);
1909
NN := Integers()!(N/p);
1910
1911
if not CanReduceModM(eps,NN) then
1912
return M;
1913
end if;
1914
1915
old := OldModularSymbols(M,NN);
1916
1917
h1 := DegeneracyMap(old, M, 1);
1918
hp := DegeneracyMap(old, M, p);
1919
return Kernel(Transpose(h1)) meet Kernel(Transpose(hp));
1920
end intrinsic;
1921
1922
1923
1924
intrinsic Sknew(M::ModTupFld) -> ModTupFld
1925
{}
1926
return CuspidalNewSubspace(M);
1927
end intrinsic;
1928
1929
intrinsic CuspidalNewSubspace(M::ModTupFld) -> ModTupFld
1930
{}
1931
if not assigned M`sknew then
1932
M`sknew := NewSubspace(M) meet CuspidalSymbols(M);
1933
end if;
1934
return M`sknew;
1935
end intrinsic;
1936
1937
intrinsic NewSubspace(M::ModTupFld) -> ModTupFld
1938
{Returns the p-new subspace of M.}
1939
if not assigned M`mknew then
1940
if Level(M) eq 1 then
1941
M`mknew := M;
1942
else
1943
M`mknew := &meet[pNewSubspace(M,p[1])
1944
: p in Factorization(Level(M))];
1945
end if;
1946
end if;
1947
return M`mknew;
1948
end intrinsic;
1949
1950
1951
1952
intrinsic Mknewdual(M::ModTupFld) -> ModTupFld
1953
{}
1954
return NewDualSubspace(M);
1955
end intrinsic;
1956
1957
intrinsic Sknewdual(M::ModTupFld) -> ModTupFld
1958
{}
1959
return CuspidalNewDualSubspace(M);
1960
end intrinsic;
1961
1962
intrinsic CuspidalNewDualSubspace(M::ModTupFld) -> ModTupFld
1963
{}
1964
if not assigned M`sknewdual then
1965
M`sknewdual := NewDualSubspace(M);
1966
// cut out the cuspidal part using Hecke operators.
1967
S := Sknew(M);
1968
if Dimension(S) eq 0 then
1969
M`sknewdual := S;
1970
else
1971
p := 2;
1972
while Dimension(M`sknewdual) gt Dimension(S) do
1973
T := HeckeOperator(M,p);
1974
f := ModularCharpoly(Restrict(T,S));
1975
Ton := Restrict(Evaluate(f,Transpose(T)),M`sknewdual);
1976
M`sknewdual := KernelOn(Ton,M`sknewdual);
1977
p := NextPrime(p);
1978
end while;
1979
end if;
1980
end if;
1981
return M`sknewdual;
1982
end intrinsic;
1983
1984
intrinsic NewDualSubspace(M::ModTupFld) -> ModTupFld
1985
{Returns the p-new subspace of M dual.}
1986
if not assigned M`mknewdual then
1987
M`mknewdual := &meet ([pNewDualSubspace(M,p[1])
1988
: p in Factorization(Level(M))] cat
1989
[M]);
1990
end if;
1991
return M`mknewdual;
1992
end intrinsic;
1993
1994
1995
/*****************************************************************
1996
THE THETA OPERATOR:
1997
On q-expansions, the theta operator is q*d/dq. It takes
1998
the q-expansion of a mod ell modular form of weight k to
1999
a mod ell modular form of weight k + ell + 1.
2000
On modular symbols the theta operator is simply multiplication
2001
by X^{ell}*Y - X*Y^{ell}.
2002