-
Notifications
You must be signed in to change notification settings - Fork 1
/
hecke.h
349 lines (258 loc) · 9.84 KB
/
hecke.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
// FILE HECKE.H: class matop for Hecke and other operators
#if !defined(_HECKE_H)
#define _HECKE_H 1 //flags that this file has been included
#include <assert.h>
#include "mat22.h"
// Atkin-Lehner and Hecke operators are implemented in the class matop
// which consists of a list of 2x2 matrices and a string holding the
// operator's name.
class matop; // details below
// We first define various functions returning the matrix lists.
// These are where all the hard work is done: the later functions
// returning matop objects are simple wrappers which include the
// operator name.
// The general principle is that we can only implement *principal*
// operators on a homspace: for the general case we would have to
// implement a more general homspace with h (=class number)
// components, each the quotient of H_3 by a twisted form of
// Gamma_0(N). These principal operators (at level N) are generated
// by these three kinds:
// Unramified character operators:
// - T(A,A, N) where A^2=(g) is principal and A is coprime to N: one
// matrix of determinant g (an (A,A)-matrix of level N);
mat22 Char(Qideal& A, const Qideal& N);
// - T(B, N) where B=(g) is principal and coprime to N, where the
// matrices all have determinant g;
// Pure Hecke operators:
// T(P) =T(P,N) where P is a principal prime (the N(P)+1 matrices here
// do not depend on N)
vector<mat22> HeckeP(Quadprime& P);
// T(PQ, N) for PQ principal, P,Q distinct primes not dividing N
vector<mat22> HeckePQ(Quadprime& P, Quadprime& Q, Qideal& N);
// more general T(B, N) with B square-free
vector<mat22> HeckeB(Qideal& B, Qideal& N);
// T(P^2), when P^2 is principal (and P not), P not dividing N,
vector<mat22> HeckeP2(Quadprime& P, Qideal& N);
// Pure Atkin-Lehner operators
// - W(M1,M2) where M1=(g) is principal and coprime to M2. Here,
// N=M1*M2: one matrix of determinant g. As a special case we have
// W(Q,N) where Q is a prime with Q^e||N, which is W(Q^e,N/Q^e).
// W(M1) at level N=M1*M2, where M1 is principal and M1,M2 coprime
mat22 AtkinLehner(Qideal& M1, Qideal& M2);
// W(Q^e) at level N where Q^e||N and Q^e is principal
mat22 AtkinLehnerQ(const Quadprime& Q, const Qideal& N);
// We also need certain products of these. All the operators above
// have version where the relevant ideal is not principal but has
// square ideal class; these can be made into principal operators by
// composing with T(A,A) for suitable A, for use in situations where
// the central character values (eigenvalues of T(A,A)) are known, in
// particular when it is known that all the T(A,A) act trivially.
// Adjusted Hecke operators:
// T(A,A)T(P,N) where [P] is square, A^2*Pprincipal, P prime and A
// coprime to N
vector<mat22> HeckeP_Chi(Quadprime& P, Qideal&A, Qideal& N);
// T(A,A)T(PQ, N) for P,Q distinct primes not dividing N with [PQ]
// square, A coprime to N with A^2PQ principal
vector<mat22> HeckePQ_Chi(Quadprime& P, Quadprime& Q, Qideal&A, Qideal& N);
// T(A,A)T(B, N) with B square-free, coprime to N, and A^2B principal
vector<mat22> HeckeB_Chi(Qideal& B, Qideal& A, Qideal& N);
// T(A,A)T(P^2), for any prime P not dividing N, (AP)^2 principal
vector<mat22> HeckeP2_Chi(Quadprime& P, Qideal& A, Qideal& N);
// Adjusted Atkin-Lehner operators
// - T(A,A)W(M1,M2) where M1 is coprime to M2, where A^2*M1 is
// principal. Here, N=M1*M2: one matrix of determinant g. As a
// special case we have T(A,A)W(Q,N) where Q is a prime with Q^e||N,
// where A^2*Q^e is principal, which is W(Q^e,N/Q^e).
// W(M1) at level N=M1*M2, where M1 is principal and M1,M2 coprime
mat22 AtkinLehner_Chi(const Qideal& M1, const Qideal& M2, const Qideal& A);
// W(Q^e) at level N where Q^e||N and Q^e is principal
mat22 AtkinLehnerQ_Chi(const Quadprime& Q, const Qideal& A, const Qideal& N);
// Products of Hecke and Atkin-Lehner operators
// T(P)W(M1) at level N for P*M1 principal, P not dividing N=M1*M2
vector<mat22> HeckePAL(Quadprime& P, Qideal& M1, Qideal& M2);
// T(P)W(Q^e) at level N for P*Q^e principal, P not dividing N, Q^e||N
vector<mat22> HeckePALQ(Quadprime& P, const Quadprime& Q, const Qideal& N);
// NB We will also need adjusted versions of these: not yet implemented.
// Utilities for contructing names
inline string opname(const Quad& p, const Quad& n)
{
ostringstream ans;
ans << (div(p,n) ? "W" : "T") << "(" << p << ")";
return ans.str();
}
inline string opname(const Quadprime& P, const Qideal& N)
{
ostringstream ans;
ans << (P.divides(N) ? "W" : "T") << "(" << P << ")";
return ans.str();
}
inline string opname(Qideal& N)
{
ostringstream ans;
ans << "W(" << ideal_label(N) << ")";
return ans.str();
}
inline string opnameAA(Qideal& A)
{
ostringstream ans;
string s = ideal_label(A);
ans << "T(" << s << "," << s << ")";
return ans.str();
}
// For use only over fields of class number 1, probably now redundant.
// T(P) for P=(p) principal prime
vector<mat22> HeckeP(const Quad& p);
// W(P) for P=(p) principal prime dividing n
mat22 AtkinLehner(const Quad& p, const Quad& n);
// W(P) for P=(p) principal prime dividing N
mat22 AtkinLehner(const Quad& p, Qideal& N);
// For use over general fields
inline mat22 Fricke(const Quad& n)
{
return mat22(Quad::zero,-Quad::one, n,Quad::zero);
}
inline mat22 Fricke(Qideal& N) // assumes N principal
{
Qideal One(Quad::one);
return AtkinLehner(N, One);
}
class matop { // formal sum of 2x2 matrices
public:
vector<mat22> mats;
string the_name;
matop() {;}
explicit matop(const mat22& m, const string& n="") :mats({m}), the_name(n) {;}
explicit matop(const vector<mat22>& mlist, const string& n="") :mats(mlist), the_name(n) {;}
mat22 operator[](int i) const {return mats[i];}
int length() const {return mats.size();}
string name() const {return the_name;}
};
// Constructors for various matops
inline matop AtkinLehnerOp(const Quad& p, const Quad& n)
{
return matop(AtkinLehner(p,n), opname(p,n));
}
// For M1 principal and M1,M2 coprime:
// operator W(M1,M1) at level N=M1*M2
inline matop AtkinLehnerOp(Qideal& M1, Qideal& M2)
{
ostringstream s;
s << "W(" << ideal_label(M1) << ")";
return matop(AtkinLehner(M1,M2), s.str());
}
// For [M1] square with A^2*M1 principal and M1,M2 coprime, A,N coprime:
// operator T(A,A)*W(M1,M2) at level N=M1*M2
inline matop AtkinLehner_ChiOp(Qideal& M1, const Qideal& M2, Qideal& A)
{
ostringstream s;
s << "W(" << ideal_label(M1) << ") * " + opnameAA(A);
return matop(AtkinLehner_Chi(M1,M2, A), s.str());
}
// For Q prime, Q^e||N, Q^e principal:
// operator W(Q^e) at level N
inline matop AtkinLehnerQOp(const Quadprime& Q, const Qideal& N)
{
return matop(AtkinLehnerQ(Q,N), opname(Q,N));
}
// For Q prime, Q^e||N, [Q^e] square with A^2*Q^e principal, A coprime
// to N:
// operator T(A,A)W(Q^e) at level N
inline matop AtkinLehnerQChiOp(const Quadprime& Q, Qideal& A, const Qideal& N)
{
ostringstream s;
s << "W(" << Q << ") * " + opnameAA(A);
return matop(AtkinLehnerQ_Chi(Q,A,N), opname(Q,N));
}
// For P prime not dividing N, P principal:
// The operator T(P) at level N
inline matop HeckePOp(Quadprime& P, const Qideal& N)
{
return matop(HeckeP(P), opname(P,N));
}
// For P prime not dividing N, [P] square with A^2*P principalm A
// coprime to N:
// The operator T(A,A)T(P) at level N
inline matop HeckePChiOp(Quadprime& P, Qideal& A, Qideal& N)
{
ostringstream s;
s << "T(" << P << ") * " + opnameAA(A);
return matop(HeckeP_Chi(P,A,N), opname(P,N));
}
// For P prime not dividing N with P^2 principal:
// The operator T(P^2) at level N
inline matop HeckeP2Op(Quadprime& P, Qideal& N)
{
ostringstream s;
s << "T(" << P << "^2)";
return matop(HeckeP2(P,N), s.str());
}
// For P prime not dividing N and A coprime to N with (AP)^2 principal:
// The operator T(A,A)*T(P^2) at level N
inline matop HeckeP2ChiOp(Quadprime& P, Qideal& A, Qideal& N)
{
ostringstream s;
s << "T(" << P << "^2) * " + opnameAA(A);
return matop(HeckeP2_Chi(P,A,N), s.str());
}
// For P,Q distinct primes not dividing N, with P*Q principal:
// The operator T(PQ) at level N
inline matop HeckePQOp(Quadprime& P, Quadprime& Q, Qideal& N)
{
ostringstream s;
s << "T(" << P << "*" << Q << ")";
return matop(HeckePQ(P,Q,N), s.str());
}
// For P,Q distinct primes not dividing N, with [P*Q] square, A^2*P*Q
// principal with A coprime to N:
// The operator T(A,A) T(PQ) at level N
inline matop HeckePQChiOp(Quadprime& P, Quadprime& Q, Qideal& A, Qideal& N)
{
ostringstream s;
s << "T(" << P << "*" << Q << ") * " + opnameAA(A);
return matop(HeckePQ_Chi(P,Q,A,N), s.str());
}
// For B squarefree principal coprime to N:
// The operator T(B) at level N
inline matop HeckeBOp(Qideal& B, Qideal& N)
{
ostringstream s;
s << "T(" << B << ")";
return matop(HeckeB(B,N), s.str());
}
// For B squarefree coprime to N, with [B] square, A^2*B
// principal with A coprime to N:
// The operator T(A,A) T(B) at level N
inline matop HeckeBChiOp(Qideal& B, Qideal& A, Qideal& N)
{
ostringstream s;
s << "T(" << B << ") * " + opnameAA(A);
return matop(HeckeB_Chi(B,A,N), s.str());
}
// The operator T(P)W(Q) where P does not divide N, Q^e||N,
// P*Q^e principal.
// Later we'll implement a more general version giving T(A,A)T(P)W(Q^e) when [P*Q^e] is square
inline matop HeckePALQOp(Quadprime& P, const Quadprime& Q, const Qideal& N)
{
ostringstream s;
s << "T(" << P << ")*W(" << Q << ")";
return matop(HeckePALQ(P,Q,N), s.str());
}
// The operator T(P)W(M1) where P does not divide N=M1*M2, M1,M2 coprime and P*M1 principal
// Later we'll implement a more general version giving T(A,A)T(P)W(M1) when [P*M1] is square
inline matop HeckePALOp(Quadprime& P, Qideal& M1, Qideal& M2)
{
ostringstream s;
s << "T(" << P << ")*W(" << ideal_label(M1) << ")";
return matop(HeckePAL(P,M1,M2), s.str());
}
inline matop FrickeOp(Qideal& N)
{
return matop(Fricke(N), opname(N));
}
inline matop CharOp(Qideal& A, const Qideal& N)
{
ostringstream s;
s << "nu";
return matop(Char(A,N), s.str());
}
#endif