1 /* Copyright (C) 2016  The PARI group.
2 
3 This file is part of the PARI/GP package.
4 
5 PARI/GP is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 2 of the License, or (at your option) any later
8 version. It is distributed in the hope that it will be useful, but WITHOUT
9 ANY WARRANTY WHATSOEVER.
10 
11 Check the License for details. You should have received a copy of it, along
12 with the package; see the file 'COPYING'. If not, write to the Free Software
13 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
14 
15 /*************************************************************************/
16 /*                                                                       */
17 /*              Modular forms package based on trace formulas            */
18 /*                                                                       */
19 /*************************************************************************/
20 #include "pari.h"
21 #include "paripriv.h"
22 
23 enum {
24   MF_SPLIT = 1,
25   MF_EISENSPACE,
26   MF_FRICKE,
27   MF_MF2INIT,
28   MF_SPLITN
29 };
30 
31 typedef struct {
32   GEN vnew, vfull, DATA, VCHIP;
33   long n, newHIT, newTOTAL, cuspHIT, cuspTOTAL;
34 } cachenew_t;
35 
36 static void init_cachenew(cachenew_t *c, long n, long N, GEN f);
37 static GEN mfinit_i(GEN NK, long space);
38 static GEN mfinit_Nkchi(long N, long k, GEN CHI, long space, long flraw);
39 static GEN mf2init_Nkchi(long N, long k, GEN CHI, long space, long flraw);
40 static GEN mf2basis(long N, long r, GEN CHI, GEN *pCHI1, long space);
41 static GEN mfeisensteinbasis(long N, long k, GEN CHI);
42 static GEN mfeisensteindec(GEN mf, GEN F);
43 static GEN initwt1newtrace(GEN mf);
44 static GEN initwt1trace(GEN mf);
45 static GEN myfactoru(long N);
46 static GEN mydivisorsu(long N);
47 static GEN Qab_Czeta(long k, long ord, GEN C, long vt);
48 static GEN mfcoefs_i(GEN F, long n, long d);
49 static GEN bhnmat_extend(GEN M, long m,long l, GEN S, cachenew_t *cache);
50 static GEN initnewtrace(long N, GEN CHI);
51 static void dbg_cachenew(cachenew_t *C);
52 static GEN hecke_i(long m, long l, GEN V, GEN F, GEN DATA);
53 static GEN c_Ek(long n, long d, GEN F);
54 static GEN RgV_heckef2(long n, long d, GEN V, GEN F, GEN DATA);
55 static GEN mfcusptrace_i(long N, long k, long n, GEN Dn, GEN TDATA);
56 static GEN mfnewtracecache(long N, long k, long n, cachenew_t *cache);
57 static GEN colnewtrace(long n0, long n, long d, long N, long k, cachenew_t *c);
58 static GEN dihan(GEN bnr, GEN w, GEN k0j, ulong n);
59 static GEN sigchi(long k, GEN CHI, long n);
60 static GEN sigchi2(long k, GEN CHI1, GEN CHI2, long n, long ord);
61 static GEN mflineardivtomat(long N, GEN vF, long n);
62 static GEN mfdihedralcusp(long N, GEN CHI);
63 static long mfdihedralcuspdim(long N, GEN CHI);
64 static GEN mfdihedralnew(long N, GEN CHI);
65 static GEN mfdihedralall(GEN LIM);
66 static long mfwt1cuspdim(long N, GEN CHI);
67 static long mf2dim_Nkchi(long N, long k, GEN CHI, ulong space);
68 static long mfdim_Nkchi(long N, long k, GEN CHI, long space);
69 static GEN charLFwtk(long N, long k, GEN CHI, long ord, long t);
70 static GEN mfeisensteingacx(GEN E,long w,GEN ga,long n,long prec);
71 static GEN mfgaexpansion(GEN mf, GEN F, GEN gamma, long n, long prec);
72 static GEN mfEHmat(long n, long r);
73 static GEN mfEHcoef(long r, long N);
74 static GEN mftobasis_i(GEN mf, GEN F);
75 
76 static GEN
mkgNK(GEN N,GEN k,GEN CHI,GEN P)77 mkgNK(GEN N, GEN k, GEN CHI, GEN P) { return mkvec4(N, k, CHI, P); }
78 static GEN
mkNK(long N,long k,GEN CHI)79 mkNK(long N, long k, GEN CHI) { return mkgNK(stoi(N), stoi(k), CHI, pol_x(1)); }
80 GEN
MF_get_CHI(GEN mf)81 MF_get_CHI(GEN mf) { return gmael(mf,1,3); }
82 GEN
MF_get_gN(GEN mf)83 MF_get_gN(GEN mf) { return gmael(mf,1,1); }
84 long
MF_get_N(GEN mf)85 MF_get_N(GEN mf) { return itou(MF_get_gN(mf)); }
86 GEN
MF_get_gk(GEN mf)87 MF_get_gk(GEN mf) { return gmael(mf,1,2); }
88 long
MF_get_k(GEN mf)89 MF_get_k(GEN mf)
90 {
91   GEN gk = MF_get_gk(mf);
92   if (typ(gk)!=t_INT) pari_err_IMPL("half-integral weight");
93   return itou(gk);
94 }
95 long
MF_get_r(GEN mf)96 MF_get_r(GEN mf)
97 {
98   GEN gk = MF_get_gk(mf);
99   if (typ(gk) == t_INT) pari_err_IMPL("integral weight");
100   return itou(gel(gk, 1)) >> 1;
101 }
102 long
MF_get_space(GEN mf)103 MF_get_space(GEN mf) { return itos(gmael(mf,1,4)); }
104 GEN
MF_get_E(GEN mf)105 MF_get_E(GEN mf) { return gel(mf,2); }
106 GEN
MF_get_S(GEN mf)107 MF_get_S(GEN mf) { return gel(mf,3); }
108 GEN
MF_get_basis(GEN mf)109 MF_get_basis(GEN mf) { return shallowconcat(gel(mf,2), gel(mf,3)); }
110 long
MF_get_dim(GEN mf)111 MF_get_dim(GEN mf)
112 {
113   switch(MF_get_space(mf))
114   {
115     case mf_FULL:
116       return lg(MF_get_S(mf)) - 1 + lg(MF_get_E(mf))-1;
117     case mf_EISEN:
118       return lg(MF_get_E(mf))-1;
119     default: /* mf_NEW, mf_CUSP, mf_OLD */
120       return lg(MF_get_S(mf)) - 1;
121   }
122 }
123 GEN
MFnew_get_vj(GEN mf)124 MFnew_get_vj(GEN mf) { return gel(mf,4); }
125 GEN
MFcusp_get_vMjd(GEN mf)126 MFcusp_get_vMjd(GEN mf) { return gel(mf,4); }
127 GEN
MF_get_M(GEN mf)128 MF_get_M(GEN mf) { return gmael(mf,5,3); }
129 GEN
MF_get_Minv(GEN mf)130 MF_get_Minv(GEN mf) { return gmael(mf,5,2); }
131 GEN
MF_get_Mindex(GEN mf)132 MF_get_Mindex(GEN mf) { return gmael(mf,5,1); }
133 
134 /* ordinary gtocol forgets about initial 0s */
135 GEN
sertocol(GEN S)136 sertocol(GEN S) { return gtocol0(S, -(lg(S) - 2 + valp(S))); }
137 /*******************************************************************/
138 /*     Linear algebra in cyclotomic fields (TODO: export this)     */
139 /*******************************************************************/
140 /* return r and split prime p giving projection Q(zeta_n) -> Fp, zeta -> r */
141 static ulong
QabM_init(long n,ulong * p)142 QabM_init(long n, ulong *p)
143 {
144   ulong pinit = 1000000007;
145   forprime_t T;
146   if (n <= 1) { *p = pinit; return 0; }
147   u_forprime_arith_init(&T, pinit, ULONG_MAX, 1, n);
148   *p = u_forprime_next(&T);
149   return Flx_oneroot(ZX_to_Flx(polcyclo(n, 0), *p), *p);
150 }
151 static ulong
Qab_to_Fl(GEN P,ulong r,ulong p)152 Qab_to_Fl(GEN P, ulong r, ulong p)
153 {
154   ulong t;
155   GEN den;
156   P = Q_remove_denom(liftpol_shallow(P), &den);
157   if (typ(P) == t_POL) { GEN Pp = ZX_to_Flx(P, p); t = Flx_eval(Pp, r, p); }
158   else t = umodiu(P, p);
159   if (den) t = Fl_div(t, umodiu(den, p), p);
160   return t;
161 }
162 static GEN
QabC_to_Flc(GEN C,ulong r,ulong p)163 QabC_to_Flc(GEN C, ulong r, ulong p)
164 {
165   long i, l = lg(C);
166   GEN A = cgetg(l, t_VECSMALL);
167   for (i = 1; i < l; i++) uel(A,i) = Qab_to_Fl(gel(C,i), r, p);
168   return A;
169 }
170 static GEN
QabM_to_Flm(GEN M,ulong r,ulong p)171 QabM_to_Flm(GEN M, ulong r, ulong p)
172 {
173   long i, l;
174   GEN A = cgetg_copy(M, &l);
175   for (i = 1; i < l; i++)
176     gel(A, i) = QabC_to_Flc(gel(M, i), r, p);
177   return A;
178 }
179 /* A a t_POL */
180 static GEN
QabX_to_Flx(GEN A,ulong r,ulong p)181 QabX_to_Flx(GEN A, ulong r, ulong p)
182 {
183   long i, l = lg(A);
184   GEN a = cgetg(l, t_VECSMALL);
185   a[1] = ((ulong)A[1])&VARNBITS;
186   for (i = 2; i < l; i++) uel(a,i) = Qab_to_Fl(gel(A,i), r, p);
187   return Flx_renormalize(a, l);
188 }
189 
190 /* FIXME: remove */
191 static GEN
ZabM_pseudoinv_i(GEN M,GEN P,long n,GEN * pv,GEN * den,int ratlift)192 ZabM_pseudoinv_i(GEN M, GEN P, long n, GEN *pv, GEN *den, int ratlift)
193 {
194   GEN v = ZabM_indexrank(M, P, n);
195   if (pv) *pv = v;
196   M = shallowmatextract(M,gel(v,1),gel(v,2));
197   return ratlift? ZabM_inv_ratlift(M, P, n, den): ZabM_inv(M, P, n, den);
198 }
199 
200 /* M matrix with coeff in Q(\chi)), where Q(\chi) = Q(X)/(P) for
201  * P = cyclotomic Phi_n. Assume M rational if n <= 2 */
202 static GEN
QabM_ker(GEN M,GEN P,long n)203 QabM_ker(GEN M, GEN P, long n)
204 {
205   if (n <= 2) return QM_ker(M);
206   return ZabM_ker(Q_primpart(liftpol_shallow(M)), P, n);
207 }
208 /* pseudo-inverse of M. FIXME: should replace QabM_pseudoinv */
209 static GEN
QabM_pseudoinv_i(GEN M,GEN P,long n,GEN * pv,GEN * pden)210 QabM_pseudoinv_i(GEN M, GEN P, long n, GEN *pv, GEN *pden)
211 {
212   GEN cM, Mi;
213   if (n <= 2)
214   {
215     M = Q_primitive_part(M, &cM);
216     Mi = ZM_pseudoinv(M, pv, pden); /* M^(-1) = Mi / (cM * den) */
217   }
218   else
219   {
220     M = Q_primitive_part(liftpol_shallow(M), &cM);
221     Mi = ZabM_pseudoinv(M, P, n, pv, pden);
222   }
223   *pden = mul_content(*pden, cM);
224   return Mi;
225 }
226 /* FIXME: delete */
227 static GEN
QabM_pseudoinv(GEN M,GEN P,long n,GEN * pv,GEN * pden)228 QabM_pseudoinv(GEN M, GEN P, long n, GEN *pv, GEN *pden)
229 {
230   GEN Mi = QabM_pseudoinv_i(M, P, n, pv, pden);
231   return P? gmodulo(Mi, P): Mi;
232 }
233 
234 static GEN
QabM_indexrank(GEN M,GEN P,long n)235 QabM_indexrank(GEN M, GEN P, long n)
236 {
237   GEN z;
238   if (n <= 2)
239   {
240     M = vec_Q_primpart(M);
241     z = ZM_indexrank(M); /* M^(-1) = Mi / (cM * den) */
242   }
243   else
244   {
245     M = vec_Q_primpart(liftpol_shallow(M));
246     z = ZabM_indexrank(M, P, n);
247   }
248   return z;
249 }
250 
251 /*********************************************************************/
252 /*                    Simple arithmetic functions                    */
253 /*********************************************************************/
254 /* TODO: most of these should be exported and used in ifactor1.c */
255 /* phi(n) */
256 static ulong
myeulerphiu(ulong n)257 myeulerphiu(ulong n)
258 {
259   pari_sp av;
260   if (n == 1) return 1;
261   av = avma; return gc_ulong(av, eulerphiu_fact(myfactoru(n)));
262 }
263 static long
mymoebiusu(ulong n)264 mymoebiusu(ulong n)
265 {
266   pari_sp av;
267   if (n == 1) return 1;
268   av = avma; return gc_long(av, moebiusu_fact(myfactoru(n)));
269 }
270 
271 static long
mynumdivu(long N)272 mynumdivu(long N)
273 {
274   pari_sp av;
275   if (N == 1) return 1;
276   av = avma; return gc_long(av, numdivu_fact(myfactoru(N)));
277 }
278 
279 /* N\prod_{p|N} (1+1/p) */
280 static long
mypsiu(ulong N)281 mypsiu(ulong N)
282 {
283   pari_sp av = avma;
284   GEN P = gel(myfactoru(N), 1);
285   long j, l = lg(P), res = N;
286   for (j = 1; j < l; j++) res += res/P[j];
287   return gc_long(av,res);
288 }
289 /* write n = mf^2. Return m, set f. */
290 static ulong
mycore(ulong n,long * pf)291 mycore(ulong n, long *pf)
292 {
293   pari_sp av = avma;
294   GEN fa = myfactoru(n), P = gel(fa,1), E = gel(fa,2);
295   long i, l = lg(P), m = 1, f = 1;
296   for (i = 1; i < l; i++)
297   {
298     long j, p = P[i], e = E[i];
299     if (e & 1) m *= p;
300     for (j = 2; j <= e; j+=2) f *= p;
301   }
302   *pf = f; return gc_long(av,m);
303 }
304 
305 /* fa = factorization of -D > 0, return -D0 > 0 (where D0 is fundamental) */
306 static long
corediscs_fact(GEN fa)307 corediscs_fact(GEN fa)
308 {
309   GEN P = gel(fa,1), E = gel(fa,2);
310   long i, l = lg(P), m = 1;
311   for (i = 1; i < l; i++)
312   {
313     long p = P[i], e = E[i];
314     if (e & 1) m *= p;
315   }
316   if ((m&3L) != 3) m <<= 2;
317   return m;
318 }
319 static long
mubeta(long n)320 mubeta(long n)
321 {
322   pari_sp av = avma;
323   GEN E = gel(myfactoru(n), 2);
324   long i, s = 1, l = lg(E);
325   for (i = 1; i < l; i++)
326   {
327     long e = E[i];
328     if (e >= 3) return gc_long(av,0);
329     if (e == 1) s *= -2;
330   }
331   return gc_long(av,s);
332 }
333 
334 /* n = n1*n2, n1 = ppo(n, m); return mubeta(n1)*moebiusu(n2).
335  * N.B. If n from newt_params we, in fact, never return 0 */
336 static long
mubeta2(long n,long m)337 mubeta2(long n, long m)
338 {
339   pari_sp av = avma;
340   GEN fa = myfactoru(n), P = gel(fa,1), E = gel(fa,2);
341   long i, s = 1, l = lg(P);
342   for (i = 1; i < l; i++)
343   {
344     long p = P[i], e = E[i];
345     if (m % p)
346     { /* p^e in n1 */
347       if (e >= 3) return gc_long(av,0);
348       if (e == 1) s *= -2;
349     }
350     else
351     { /* in n2 */
352       if (e >= 2) return gc_long(av,0);
353       s = -s;
354     }
355   }
356   return gc_long(av,s);
357 }
358 
359 /* write N = prod p^{ep} and n = df^2, d squarefree.
360  * set g  = ppo(gcd(sqfpart(N), f), FC)
361  *     N2 = prod p^if(e==1 || p|n, ep-1, ep-2) */
362 static void
newt_params(long N,long n,long FC,long * pg,long * pN2)363 newt_params(long N, long n, long FC, long *pg, long *pN2)
364 {
365   GEN fa = myfactoru(N), P = gel(fa,1), E = gel(fa,2);
366   long i, g = 1, N2 = 1, l = lg(P);
367   for (i = 1; i < l; i++)
368   {
369     long p = P[i], e = E[i];
370     if (e == 1)
371     { if (FC % p && n % (p*p) == 0) g *= p; }
372     else
373       N2 *= upowuu(p,(n % p)? e-2: e-1);
374   }
375   *pg = g; *pN2 = N2;
376 }
377 /* simplified version of newt_params for n = 1 (newdim) */
378 static void
newd_params(long N,long * pN2)379 newd_params(long N, long *pN2)
380 {
381   GEN fa = myfactoru(N), P = gel(fa,1), E = gel(fa,2);
382   long i, N2 = 1, l = lg(P);
383   for (i = 1; i < l; i++)
384   {
385     long p = P[i], e = E[i];
386     if (e > 2) N2 *= upowuu(p, e-2);
387   }
388   *pN2 = N2;
389 }
390 
391 static long
newd_params2(long N)392 newd_params2(long N)
393 {
394   GEN fa = myfactoru(N), P = gel(fa,1), E = gel(fa,2);
395   long i, N2 = 1, l = lg(P);
396   for (i = 1; i < l; i++)
397   {
398     long p = P[i], e = E[i];
399     if (e >= 2) N2 *= upowuu(p, e);
400   }
401   return N2;
402 }
403 
404 /*******************************************************************/
405 /*   Relative trace between cyclotomic fields (TODO: export this)  */
406 /*******************************************************************/
407 /* g>=1; return g * prod_{p | g, (p,q) = 1} (1-1/p) */
408 static long
phipart(long g,long q)409 phipart(long g, long q)
410 {
411   if (g > 1)
412   {
413     GEN P = gel(myfactoru(g), 1);
414     long i, l = lg(P);
415     for (i = 1; i < l; i++) { long p = P[i]; if (q % p) g -= g / p; }
416   }
417   return g;
418 }
419 /* Set s,v s.t. Trace(zeta_N^k) from Q(zeta_N) to Q(\zeta_N) = s * zeta_M^v
420  * With k > 0, N = M*d and N, M != 2 mod 4 */
421 static long
tracerelz(long * pv,long d,long M,long k)422 tracerelz(long *pv, long d, long M, long k)
423 {
424   long s, g, q, muq;
425   if (d == 1) { *pv = k; return 1; }
426   *pv = 0; g = ugcd(k, d); q = d / g;
427   muq = mymoebiusu(q); if (!muq) return 0;
428   if (M != 1)
429   {
430     long v = Fl_invsafe(q % M, M);
431     if (!v) return 0;
432     *pv = (v * (k/g)) % M;
433   }
434   s = phipart(g, M*q); if (muq < 0) s = -s;
435   return s;
436 }
437 /* Pi = polcyclo(i), i = m or n. Let Ki = Q(zeta_i), initialize Tr_{Kn/Km} */
438 GEN
Qab_trace_init(long n,long m,GEN Pn,GEN Pm)439 Qab_trace_init(long n, long m, GEN Pn, GEN Pm)
440 {
441   long a, i, j, N, M, vt, d, D;
442   GEN T, G;
443 
444   if (m == n || n <= 2) return mkvec(Pm);
445   vt = varn(Pn);
446   d = degpol(Pn);
447   /* if (N != n) zeta_N = zeta_n^2 and zeta_n = - zeta_N^{(N+1)/2} */
448   N = ((n & 3) == 2)? n >> 1: n;
449   M = ((m & 3) == 2)? m >> 1: m; /* M | N | n */
450   a = N / M;
451   T = const_vec(d, NULL);
452   D = d / degpol(Pm); /* relative degree */
453   if (D == 1) G = NULL;
454   else
455   { /* zeta_M = zeta_n^A; s_j(zeta_M) = zeta_M <=> j = 1 (mod J) */
456     long lG, A = (N == n)? a: (a << 1), J = n / ugcd(n, A);
457     G = coprimes_zv(n);
458     for (j = lG = 1; j < n; j += J)
459       if (G[j]) G[lG++] = j;
460     setlg(G, lG); /* Gal(Q(zeta_n) / Q(zeta_m)) */
461   }
462   T = const_vec(d, NULL);
463   gel(T,1) = utoipos(D); /* Tr 1 */
464   for (i = 1; i < d; i++)
465   { /* if n = 2N, zeta_n^i = (-1)^i zeta_N^k */
466     long s, v, k;
467     GEN t;
468 
469     if (gel(T, i+1)) continue;
470     k = (N == n)? i: ((odd(i)? i + N: i) >> 1);
471     if ((s = tracerelz(&v, a, M, k)))
472     {
473       if (m != M) v *= 2;/* Tr = s * zeta_m^v */
474       if (n != N && odd(i)) s = -s;
475       t = Qab_Czeta(v, m, stoi(s), vt);
476     }
477     else
478       t = gen_0;
479     /* t = Tr_{Kn/Km} zeta_n^i; fill using Galois action */
480     if (!G)
481       gel(T, i + 1) = t;
482     else
483       for (j = 1; j <= D; j++)
484       {
485         long z = Fl_mul(i,G[j], n);
486         if (z < d) gel(T, z + 1) = t;
487       }
488   }
489   return mkvec3(Pm, Pn, T);
490 }
491 /* x a t_POL modulo Phi_n */
492 static GEN
tracerel_i(GEN T,GEN x)493 tracerel_i(GEN T, GEN x)
494 {
495   long k, l = lg(x);
496   GEN S;
497   if (l == 2) return gen_0;
498   S = gmul(gel(T,1), gel(x,2));
499   for (k = 3; k < l; k++) S = gadd(S, gmul(gel(T,k-1), gel(x,k)));
500   return S;
501 }
502 static GEN
tracerel(GEN a,GEN v,GEN z)503 tracerel(GEN a, GEN v, GEN z)
504 {
505   a = liftpol_shallow(a);
506   a = simplify_shallow(z? gmul(z,a): a);
507   if (typ(a) == t_POL)
508   {
509     GEN T = gel(v,3);
510     long degrel = itou(gel(T,1));
511     a = tracerel_i(T, RgX_rem(a, gel(v,2)));
512     if (degrel != 1) a = gdivgs(a, degrel);
513     if (typ(a) == t_POL) a = RgX_rem(a, gel(v,1));
514   }
515   return a;
516 }
517 static GEN
tracerel_z(GEN v,long t)518 tracerel_z(GEN v, long t)
519 {
520   GEN Pn = gel(v,2);
521   return t? pol_xn(t, varn(Pn)): NULL;
522 }
523 /* v = Qab_trace_init(n,m); x is a t_VEC of polmodulo Phi_n; Kn = Q(zeta_n)
524  * [Kn:Km]^(-1) Tr_{Kn/Km} (zeta_n^t * x); 0 <= t < [Kn:Km] */
525 GEN
Qab_tracerel(GEN v,long t,GEN a)526 Qab_tracerel(GEN v, long t, GEN a)
527 {
528   if (lg(v) != 4) return a; /* => t = 0 */
529   return tracerel(a, v, tracerel_z(v, t));
530 }
531 GEN
QabV_tracerel(GEN v,long t,GEN x)532 QabV_tracerel(GEN v, long t, GEN x)
533 {
534   GEN z;
535   if (lg(v) != 4) return x; /* => t = 0 */
536   z = tracerel_z(v, t);
537   pari_APPLY_same(tracerel(gel(x,i), v, z));
538 }
539 GEN
QabM_tracerel(GEN v,long t,GEN x)540 QabM_tracerel(GEN v, long t, GEN x)
541 {
542   if (lg(v) != 4) return x;
543   pari_APPLY_same(QabV_tracerel(v, t, gel(x,i)));
544 }
545 
546 /* C*zeta_o^k mod X^o - 1 */
547 static GEN
Qab_Czeta(long k,long o,GEN C,long vt)548 Qab_Czeta(long k, long o, GEN C, long vt)
549 {
550   if (!k) return C;
551   if (!odd(o))
552   { /* optimization: reduce max degree by a factor 2 for free */
553     o >>= 1;
554     if (k >= o) { k -= o; C = gneg(C); if (!k) return C; }
555   }
556   return monomial(C, k, vt);
557 }
558 /* zeta_o^k */
559 static GEN
Qab_zeta(long k,long o,long vt)560 Qab_zeta(long k, long o, long vt) { return Qab_Czeta(k, o, gen_1, vt); }
561 
562 /*              Operations on Dirichlet characters                       */
563 
564 /* A Dirichlet character can be given in GP in different formats, but in this
565  * package, it will be a vector CHI=[G,chi,ord], where G is the (Z/MZ)^* to
566  * which the character belongs, chi is the character in Conrey format, ord is
567  * the order */
568 
569 static GEN
gmfcharorder(GEN CHI)570 gmfcharorder(GEN CHI) { return gel(CHI, 3); }
571 long
mfcharorder(GEN CHI)572 mfcharorder(GEN CHI) { return itou(gmfcharorder(CHI)); }
573 static long
mfcharistrivial(GEN CHI)574 mfcharistrivial(GEN CHI) { return !CHI || mfcharorder(CHI) == 1; }
575 static GEN
gmfcharmodulus(GEN CHI)576 gmfcharmodulus(GEN CHI) { return gmael3(CHI, 1, 1, 1); }
577 long
mfcharmodulus(GEN CHI)578 mfcharmodulus(GEN CHI) { return itou(gmfcharmodulus(CHI)); }
579 GEN
mfcharpol(GEN CHI)580 mfcharpol(GEN CHI) { return gel(CHI,4); }
581 
582 /* vz[i+1] = image of (zeta_o)^i in Fp */
583 static ulong
Qab_Czeta_Fl(long k,GEN vz,ulong C,ulong p)584 Qab_Czeta_Fl(long k, GEN vz, ulong C, ulong p)
585 {
586   long o;
587   if (!k) return C;
588   o = lg(vz)-2;
589   if ((k << 1) == o) return Fl_neg(C,p);
590   return Fl_mul(C, vz[k+1], p);
591 }
592 
593 static long
znchareval_i(GEN CHI,long n,GEN ord)594 znchareval_i(GEN CHI, long n, GEN ord)
595 { return itos(znchareval(gel(CHI,1), gel(CHI,2), stoi(n), ord)); }
596 
597 /* n coprime with the modulus of CHI */
598 static GEN
mfchareval(GEN CHI,long n)599 mfchareval(GEN CHI, long n)
600 {
601   GEN Pn, C, go = gmfcharorder(CHI);
602   long k, o = go[2];
603   if (o == 1) return gen_1;
604   k = znchareval_i(CHI, n, go);
605   Pn = mfcharpol(CHI);
606   C = Qab_zeta(k, o, varn(Pn));
607   if (typ(C) != t_POL) return C;
608   return gmodulo(C, Pn);
609 }
610 /* d a multiple of ord(CHI); n coprime with char modulus;
611  * return x s.t. CHI(n) = \zeta_d^x] */
612 static long
mfcharevalord(GEN CHI,long n,long d)613 mfcharevalord(GEN CHI, long n, long d)
614 {
615   if (mfcharorder(CHI) == 1) return 0;
616   return znchareval_i(CHI, n, utoi(d));
617 }
618 
619 /* G a znstar, L a Conrey log: return a 'mfchar' */
620 static GEN
mfcharGL(GEN G,GEN L)621 mfcharGL(GEN G, GEN L)
622 {
623   GEN o = zncharorder(G,L);
624   long ord = itou(o), vt = fetch_user_var("t");
625   return mkvec4(G, L, o, polcyclo(ord,vt));
626 }
627 static GEN
mfchartrivial()628 mfchartrivial()
629 { return mfcharGL(znstar0(gen_1,1), cgetg(1,t_COL)); }
630 /* convert a generic character into an 'mfchar' */
631 static GEN
get_mfchar(GEN CHI)632 get_mfchar(GEN CHI)
633 {
634   GEN G, L;
635   if (typ(CHI) != t_VEC) CHI = znchar(CHI);
636   else
637   {
638     long l = lg(CHI);
639     if ((l != 3 && l != 5) || !checkznstar_i(gel(CHI,1)))
640       pari_err_TYPE("checkNF [chi]", CHI);
641     if (l == 5) return CHI;
642   }
643   G = gel(CHI,1);
644   L = gel(CHI,2); if (typ(L) != t_COL) L = znconreylog(G,L);
645   return mfcharGL(G, L);
646 }
647 
648 /* parse [N], [N,k], [N,k,CHI]. If 'joker' is set, allow wildcard for CHI */
649 static GEN
checkCHI(GEN NK,long N,int joker)650 checkCHI(GEN NK, long N, int joker)
651 {
652   GEN CHI;
653   if (lg(NK) == 3)
654     CHI = mfchartrivial();
655   else
656   {
657     long i, l;
658     CHI = gel(NK,3); l = lg(CHI);
659     if (isintzero(CHI) && joker)
660       CHI = NULL; /* all character orbits */
661     else if (isintm1(CHI) && joker > 1)
662       CHI = gen_m1; /* sum over all character orbits */
663     else if ((typ(CHI) == t_VEC &&
664              (l == 1 || l != 3 || !checkznstar_i(gel(CHI,1)))) && joker)
665     {
666       CHI = shallowtrans(CHI); /* list of characters */
667       for (i = 1; i < l; i++) gel(CHI,i) = get_mfchar(gel(CHI,i));
668     }
669     else
670     {
671       CHI = get_mfchar(CHI); /* single char */
672       if (N % mfcharmodulus(CHI)) pari_err_TYPE("checkNF [chi]", NK);
673     }
674   }
675   return CHI;
676 }
677 /* support half-integral weight */
678 static void
checkNK2(GEN NK,long * N,long * nk,long * dk,GEN * CHI,int joker)679 checkNK2(GEN NK, long *N, long *nk, long *dk, GEN *CHI, int joker)
680 {
681   long l = lg(NK);
682   GEN T;
683   if (typ(NK) != t_VEC || l < 3 || l > 4) pari_err_TYPE("checkNK", NK);
684   T = gel(NK,1); if (typ(T) != t_INT) pari_err_TYPE("checkNF [N]", NK);
685   *N = itos(T); if (*N <= 0) pari_err_TYPE("checkNF [N <= 0]", NK);
686   T = gel(NK,2);
687   switch(typ(T))
688   {
689     case t_INT:  *nk = itos(T); *dk = 1; break;
690     case t_FRAC:
691       *nk = itos(gel(T,1));
692       *dk = itou(gel(T,2)); if (*dk == 2) break;
693     default: pari_err_TYPE("checkNF [k]", NK);
694   }
695   *CHI = checkCHI(NK, *N, joker);
696 }
697 /* don't support half-integral weight */
698 static void
checkNK(GEN NK,long * N,long * k,GEN * CHI,int joker)699 checkNK(GEN NK, long *N, long *k, GEN *CHI, int joker)
700 {
701   long d;
702   checkNK2(NK, N, k, &d, CHI, joker);
703   if (d != 1) pari_err_TYPE("checkNF [k]", NK);
704 }
705 
706 static GEN
mfchargalois(long N,int odd,GEN flagorder)707 mfchargalois(long N, int odd, GEN flagorder)
708 {
709   GEN G = znstar0(utoi(N), 1), L = chargalois(G, flagorder);
710   long l = lg(L), i, j;
711   for (i = j = 1; i < l; i++)
712   {
713     GEN chi = znconreyfromchar(G, gel(L,i));
714     if (zncharisodd(G,chi) == odd) gel(L,j++) = mfcharGL(G,chi);
715   }
716   setlg(L, j); return L;
717 }
718 /* possible characters for nontrivial S_1(N, chi) */
719 static GEN
mfwt1chars(long N,GEN vCHI)720 mfwt1chars(long N, GEN vCHI)
721 {
722   if (vCHI) return vCHI; /*do not filter, user knows best*/
723   /* Tate's theorem */
724   return mfchargalois(N, 1, uisprime(N)? mkvecsmall2(2,4): NULL);
725 }
726 static GEN
mfchars(long N,long k,long dk,GEN vCHI)727 mfchars(long N, long k, long dk, GEN vCHI)
728 { return vCHI? vCHI: mfchargalois(N, (dk == 2)? 0: (k & 1), NULL); }
729 
730 /* wrappers from mfchar to znchar */
731 static long
mfcharparity(GEN CHI)732 mfcharparity(GEN CHI)
733 {
734   if (!CHI) return 1;
735   return zncharisodd(gel(CHI,1), gel(CHI,2)) ? -1 : 1;
736 }
737 /* if CHI is primitive, return CHI itself, not a copy */
738 static GEN
mfchartoprimitive(GEN CHI,long * pF)739 mfchartoprimitive(GEN CHI, long *pF)
740 {
741   pari_sp av;
742   GEN chi, F;
743   if (!CHI) { if (pF) *pF = 1; return mfchartrivial(); }
744   av = avma; F = znconreyconductor(gel(CHI,1), gel(CHI,2), &chi);
745   if (typ(F) == t_INT) set_avma(av);
746   else
747   {
748     CHI = leafcopy(CHI);
749     gel(CHI,1) = znstar0(F, 1);
750     gel(CHI,2) = chi;
751   }
752   if (pF) *pF = mfcharmodulus(CHI);
753   return CHI;
754 }
755 static long
mfcharconductor(GEN CHI)756 mfcharconductor(GEN CHI)
757 {
758   pari_sp av = avma;
759   GEN res = znconreyconductor(gel(CHI,1), gel(CHI,2), NULL);
760   if (typ(res) == t_VEC) res = gel(res, 1);
761   return gc_long(av, itos(res));
762 }
763 
764 /*                      Operations on mf closures                    */
765 static GEN
tagparams(long t,GEN NK)766 tagparams(long t, GEN NK) { return mkvec2(mkvecsmall(t), NK); }
767 static GEN
lfuntag(long t,GEN x)768 lfuntag(long t, GEN x) { return mkvec2(mkvecsmall(t), x); }
769 static GEN
tag0(long t,GEN NK)770 tag0(long t, GEN NK) { retmkvec(tagparams(t,NK)); }
771 static GEN
tag(long t,GEN NK,GEN x)772 tag(long t, GEN NK, GEN x) { retmkvec2(tagparams(t,NK), x); }
773 static GEN
tag2(long t,GEN NK,GEN x,GEN y)774 tag2(long t, GEN NK, GEN x, GEN y) { retmkvec3(tagparams(t,NK), x,y); }
775 static GEN
tag3(long t,GEN NK,GEN x,GEN y,GEN z)776 tag3(long t, GEN NK, GEN x,GEN y,GEN z) { retmkvec4(tagparams(t,NK), x,y,z); }
777 static GEN
tag4(long t,GEN NK,GEN x,GEN y,GEN z,GEN a)778 tag4(long t, GEN NK, GEN x,GEN y,GEN z,GEN a)
779 { retmkvec5(tagparams(t,NK), x,y,z,a); }
780 /* is F a "modular form" ? */
781 int
checkmf_i(GEN F)782 checkmf_i(GEN F)
783 { return typ(F) == t_VEC
784     && lg(F) > 1 && typ(gel(F,1)) == t_VEC
785     && lg(gel(F,1)) == 3
786     && typ(gmael(F,1,1)) == t_VECSMALL
787     && typ(gmael(F,1,2)) == t_VEC; }
mf_get_type(GEN F)788 long mf_get_type(GEN F) { return gmael(F,1,1)[1]; }
mf_get_gN(GEN F)789 GEN mf_get_gN(GEN F) { return gmael3(F,1,2,1); }
mf_get_gk(GEN F)790 GEN mf_get_gk(GEN F) { return gmael3(F,1,2,2); }
791 /* k - 1/2, assume k in 1/2 + Z */
mf_get_r(GEN F)792 long mf_get_r(GEN F) { return itou(gel(mf_get_gk(F),1)) >> 1; }
mf_get_N(GEN F)793 long mf_get_N(GEN F) { return itou(mf_get_gN(F)); }
mf_get_k(GEN F)794 long mf_get_k(GEN F)
795 {
796   GEN gk = mf_get_gk(F);
797   if (typ(gk)!=t_INT) pari_err_IMPL("half-integral weight");
798   return itou(gk);
799 }
mf_get_CHI(GEN F)800 GEN mf_get_CHI(GEN F) { return gmael3(F,1,2,3); }
mf_get_field(GEN F)801 GEN mf_get_field(GEN F) { return gmael3(F,1,2,4); }
mf_get_NK(GEN F)802 GEN mf_get_NK(GEN F) { return gmael(F,1,2); }
803 static void
mf_setfield(GEN f,GEN P)804 mf_setfield(GEN f, GEN P)
805 {
806   gel(f,1) = leafcopy(gel(f,1));
807   gmael(f,1,2) = leafcopy(gmael(f,1,2));
808   gmael3(f,1,2,4) = P;
809 }
810 
811 /* UTILITY FUNCTIONS */
812 GEN
mftocol(GEN F,long lim,long d)813 mftocol(GEN F, long lim, long d)
814 { GEN c = mfcoefs_i(F, lim, d); settyp(c,t_COL); return c; }
815 GEN
mfvectomat(GEN vF,long lim,long d)816 mfvectomat(GEN vF, long lim, long d)
817 {
818   long j, l = lg(vF);
819   GEN M = cgetg(l, t_MAT);
820   for (j = 1; j < l; j++) gel(M,j) = mftocol(gel(vF,j), lim, d);
821   return M;
822 }
823 
824 static GEN
RgV_to_ser_full(GEN x)825 RgV_to_ser_full(GEN x) { return RgV_to_ser(x, 0, lg(x)+1); }
826 /* TODO: delete */
827 static GEN
mfcoefsser(GEN F,long n)828 mfcoefsser(GEN F, long n) { return RgV_to_ser_full(mfcoefs_i(F,n,1)); }
829 static GEN
sertovecslice(GEN S,long n)830 sertovecslice(GEN S, long n)
831 {
832   GEN v = gtovec0(S, -(lg(S) - 2 + valp(S)));
833   long l = lg(v), n2 = n + 2;
834   if (l < n2) pari_err_BUG("sertovecslice [n too large]");
835   return (l == n2)? v: vecslice(v, 1, n2-1);
836 }
837 
838 /* a, b two RgV of the same length, multiply as truncated power series */
839 static GEN
RgV_mul_RgXn(GEN a,GEN b)840 RgV_mul_RgXn(GEN a, GEN b)
841 {
842   long n = lg(a)-1;
843   GEN c;
844   a = RgV_to_RgX(a,0);
845   b = RgV_to_RgX(b,0); c = RgXn_mul(a, b, n);
846   c = RgX_to_RgC(c,n); settyp(c,t_VEC); return c;
847 }
848 /* divide as truncated power series */
849 static GEN
RgV_div_RgXn(GEN a,GEN b)850 RgV_div_RgXn(GEN a, GEN b)
851 {
852   long n = lg(a)-1;
853   GEN c;
854   a = RgV_to_RgX(a,0);
855   b = RgV_to_RgX(b,0); c = RgXn_mul(a, RgXn_inv(b,n), n);
856   c = RgX_to_RgC(c,n); settyp(c,t_VEC); return c;
857 }
858 /* a^b */
859 static GEN
RgV_pows_RgXn(GEN a,long b)860 RgV_pows_RgXn(GEN a, long b)
861 {
862   long n = lg(a)-1;
863   GEN c;
864   a = RgV_to_RgX(a,0);
865   if (b < 0) { a = RgXn_inv(a, n); b = -b; }
866   c = RgXn_powu_i(a,b,n);
867   c = RgX_to_RgC(c,n); settyp(c,t_VEC); return c;
868 }
869 
870 /* assume lg(V) >= n*d + 2 */
871 static GEN
c_deflate(long n,long d,GEN v)872 c_deflate(long n, long d, GEN v)
873 {
874   long i, id, l = n+2;
875   GEN w;
876   if (d == 1) return lg(v) == l ? v: vecslice(v, 1, l-1);
877   w = cgetg(l, typ(v));
878   for (i = id = 1; i < l; i++, id += d) gel(w, i) = gel(v, id);
879   return w;
880 }
881 
882 static void
err_cyclo(void)883 err_cyclo(void)
884 { pari_err_IMPL("changing cyclotomic fields in mf"); }
885 /* Q(zeta_a) = Q(zeta_b) ? */
886 static int
same_cyc(long a,long b)887 same_cyc(long a, long b)
888 { return (a == b) || (odd(a) && b == (a<<1)) || (odd(b) && a == (b<<1)); }
889 /* need to combine elements in Q(CHI1) and Q(CHI2) with result in Q(CHI),
890  * CHI = CHI1 * CHI2 or CHI / CHI2 times some character of order 2 */
891 static GEN
chicompat(GEN CHI,GEN CHI1,GEN CHI2)892 chicompat(GEN CHI, GEN CHI1, GEN CHI2)
893 {
894   long o1 = mfcharorder(CHI1);
895   long o2 = mfcharorder(CHI2), O, o;
896   GEN T1, T2, P, Po;
897   if (o1 <= 2 && o2 <= 2) return NULL;
898   o = mfcharorder(CHI);
899   Po = mfcharpol(CHI);
900   P = mfcharpol(CHI1);
901   if (o1 == o2)
902   {
903     if (o1 == o) return NULL;
904     if (!same_cyc(o1,o)) err_cyclo();
905     return mkvec4(P, gen_1,gen_1, Qab_trace_init(o1, o, P, Po));
906   }
907   O = ulcm(o1, o2);
908   if (!same_cyc(O,o)) err_cyclo();
909   if (O != o1) P = (O == o2)? mfcharpol(CHI2): polcyclo(O, varn(P));
910   T1 = o1 <= 2? gen_1: utoipos(O / o1);
911   T2 = o2 <= 2? gen_1: utoipos(O / o2);
912   return mkvec4(P, T1, T2, O == o? gen_1: Qab_trace_init(O, o, P, Po));
913 }
914 /* *F a vector of cyclotomic numbers */
915 static void
compatlift(GEN * F,long o,GEN P)916 compatlift(GEN *F, long o, GEN P)
917 {
918   long i, l;
919   GEN f = *F, g = cgetg_copy(f,&l);
920   for (i = 1; i < l; i++)
921   {
922     GEN fi = lift_shallow(gel(f,i));
923     gel(g,i) = gmodulo(typ(fi)==t_POL? RgX_inflate(fi,o): fi, P);
924   }
925   *F = g;
926 }
927 static void
chicompatlift(GEN T,GEN * F,GEN * G)928 chicompatlift(GEN T, GEN *F, GEN *G)
929 {
930   long o1 = itou(gel(T,2)), o2 = itou(gel(T,3));
931   GEN P = gel(T,1);
932   if (o1 != 1) compatlift(F, o1, P);
933   if (o2 != 1 && G) compatlift(G, o2, P);
934 }
935 static GEN
chicompatfix(GEN T,GEN F)936 chicompatfix(GEN T, GEN F)
937 {
938   GEN V = gel(T,4);
939   if (typ(V) == t_VEC) F = gmodulo(QabV_tracerel(V, 0, F), gel(V,1));
940   return F;
941 }
942 
943 static GEN
c_mul(long n,long d,GEN S)944 c_mul(long n, long d, GEN S)
945 {
946   pari_sp av = avma;
947   long nd = n*d;
948   GEN F = gel(S,2), G = gel(S,3);
949   F = mfcoefs_i(F, nd, 1);
950   G = mfcoefs_i(G, nd, 1);
951   if (lg(S) == 5) chicompatlift(gel(S,4),&F,&G);
952   F = c_deflate(n, d, RgV_mul_RgXn(F,G));
953   if (lg(S) == 5) F = chicompatfix(gel(S,4), F);
954   return gerepilecopy(av, F);
955 }
956 static GEN
c_pow(long n,long d,GEN S)957 c_pow(long n, long d, GEN S)
958 {
959   pari_sp av = avma;
960   long nd = n*d;
961   GEN F = gel(S,2), a = gel(S,3), f = mfcoefs_i(F,nd,1);
962   if (lg(S) == 5) chicompatlift(gel(S,4),&F, NULL);
963   f = RgV_pows_RgXn(f, itos(a));
964   f = c_deflate(n, d, f);
965   if (lg(S) == 5) f = chicompatfix(gel(S,4), f);
966   return gerepilecopy(av, f);
967 }
968 
969 /* F * Theta */
970 static GEN
mfmultheta(GEN F)971 mfmultheta(GEN F)
972 {
973   if (typ(mf_get_gk(F)) == t_FRAC && mf_get_type(F) == t_MF_DIV)
974   {
975     GEN T = gel(F,3); /* hopefully mfTheta() */
976     if (mf_get_type(T) == t_MF_THETA && mf_get_N(T) == 4) return gel(F,2);
977   }
978   return mfmul(F, mfTheta(NULL));
979 }
980 
981 static GEN
c_bracket(long n,long d,GEN S)982 c_bracket(long n, long d, GEN S)
983 {
984   pari_sp av = avma;
985   long i, nd = n*d;
986   GEN F = gel(S,2), G = gel(S,3), tF, tG, C, mpow, res, gk, gl;
987   GEN VF = mfcoefs_i(F, nd, 1);
988   GEN VG = mfcoefs_i(G, nd, 1);
989   ulong j, m = itou(gel(S,4));
990 
991   if (!n)
992   {
993     if (m > 0) { set_avma(av); return mkvec(gen_0); }
994     return gerepilecopy(av, mkvec(gmul(gel(VF, 1), gel(VG, 1))));
995   }
996   tF = cgetg(nd+2, t_VEC);
997   tG = cgetg(nd+2, t_VEC);
998   res = NULL; gk = mf_get_gk(F); gl = mf_get_gk(G);
999   /* pow[i,j+1] = i^j */
1000   if (lg(S) == 6) chicompatlift(gel(S,5),&VF,&VG);
1001   mpow = cgetg(m+2, t_MAT);
1002   gel(mpow,1) = const_col(nd, gen_1);
1003   for (j = 1; j <= m; j++)
1004   {
1005     GEN c = cgetg(nd+1, t_COL);
1006     gel(mpow,j+1) = c;
1007     for (i = 1; i <= nd; i++) gel(c,i) = muliu(gcoeff(mpow,i,j), i);
1008   }
1009   C = binomial(gaddgs(gk, m-1), m);
1010   if (odd(m)) C = gneg(C);
1011   for (j = 0; j <= m; j++)
1012   { /* C = (-1)^(m-j) binom(m+l-1, j) binom(m+k-1,m-j) */
1013     GEN c;
1014     gel(tF,1) = j == 0? gel(VF,1): gen_0;
1015     gel(tG,1) = j == m? gel(VG,1): gen_0;
1016     gel(tF,2) = gel(VF,2); /* assume nd >= 1 */
1017     gel(tG,2) = gel(VG,2);
1018     for (i = 2; i <= nd; i++)
1019     {
1020       gel(tF, i+1) = gmul(gcoeff(mpow,i,j+1),   gel(VF, i+1));
1021       gel(tG, i+1) = gmul(gcoeff(mpow,i,m-j+1), gel(VG, i+1));
1022     }
1023     c = gmul(C, c_deflate(n, d, RgV_mul_RgXn(tF, tG)));
1024     res = res? gadd(res, c): c;
1025     if (j < m)
1026       C = gdiv(gmul(C, gmulsg(m-j, gaddgs(gl,m-j-1))),
1027                gmulsg(-(j+1), gaddgs(gk,j)));
1028   }
1029   if (lg(S) == 6) res = chicompatfix(gel(S,5), res);
1030   return gerepileupto(av, res);
1031 }
1032 /* linear combination \sum L[j] vecF[j] */
1033 static GEN
c_linear(long n,long d,GEN F,GEN L,GEN dL)1034 c_linear(long n, long d, GEN F, GEN L, GEN dL)
1035 {
1036   pari_sp av = avma;
1037   long j, l = lg(L);
1038   GEN S = NULL;
1039   for (j = 1; j < l; j++)
1040   {
1041     GEN c = gel(L,j);
1042     if (gequal0(c)) continue;
1043     c = gmul(c, mfcoefs_i(gel(F,j), n, d));
1044     S = S? gadd(S,c): c;
1045   }
1046   if (!S) return zerovec(n+1);
1047   if (!is_pm1(dL)) S = gdiv(S, dL);
1048   return gerepileupto(av, S);
1049 }
1050 
1051 /* B_d(T_j Trace^new) as t_MF_BD(t_MF_HECKE(t_MF_NEWTRACE)) or
1052  * t_MF_HECKE(t_MF_NEWTRACE)
1053  * or t_MF_NEWTRACE in level N. Set d and j, return t_MF_NEWTRACE component*/
1054 static GEN
bhn_parse(GEN f,long * d,long * j)1055 bhn_parse(GEN f, long *d, long *j)
1056 {
1057   long t = mf_get_type(f);
1058   *d = *j = 1;
1059   if (t == t_MF_BD) { *d = itos(gel(f,3)); f = gel(f,2); t = mf_get_type(f); }
1060   if (t == t_MF_HECKE) { *j = gel(f,2)[1]; f = gel(f,3); }
1061   return f;
1062 }
1063 /* f as above, return the t_MF_NEWTRACE component */
1064 static GEN
bhn_newtrace(GEN f)1065 bhn_newtrace(GEN f)
1066 {
1067   long t = mf_get_type(f);
1068   if (t == t_MF_BD) { f = gel(f,2); t = mf_get_type(f); }
1069   if (t == t_MF_HECKE) f = gel(f,3);
1070   return f;
1071 }
1072 static int
ok_bhn_linear(GEN vf)1073 ok_bhn_linear(GEN vf)
1074 {
1075   long i, N0 = 0, l = lg(vf);
1076   GEN CHI, gk;
1077   if (l == 1) return 1;
1078   gk = mf_get_gk(gel(vf,1));
1079   CHI = mf_get_CHI(gel(vf,1));
1080   for (i = 1; i < l; i++)
1081   {
1082     GEN f = bhn_newtrace(gel(vf,i));
1083     long N = mf_get_N(f);
1084     if (mf_get_type(f) != t_MF_NEWTRACE) return 0;
1085     if (N < N0) return 0; /* largest level must come last */
1086     N0 = N;
1087     if (!gequal(gk,mf_get_gk(f))) return 0; /* same k */
1088     if (!gequal(gel(mf_get_CHI(f),2), gel(CHI,2))) return 0; /* same CHI */
1089   }
1090   return 1;
1091 }
1092 
1093 /* vF not empty, same hypotheses as bhnmat_extend */
1094 static GEN
bhnmat_extend_nocache(GEN M,long N,long n,long d,GEN vF)1095 bhnmat_extend_nocache(GEN M, long N, long n, long d, GEN vF)
1096 {
1097   cachenew_t cache;
1098   long l = lg(vF);
1099   GEN f;
1100   if (l == 1) return M? M: cgetg(1, t_MAT);
1101   f = bhn_newtrace(gel(vF,1)); /* N.B. mf_get_N(f) divides N */
1102   init_cachenew(&cache, n*d, N, f);
1103   M = bhnmat_extend(M, n, d, vF, &cache);
1104   dbg_cachenew(&cache); return M;
1105 }
1106 /* c_linear of "bhn" mf closures, same hypotheses as bhnmat_extend */
1107 static GEN
c_linear_bhn(long n,long d,GEN F)1108 c_linear_bhn(long n, long d, GEN F)
1109 {
1110   pari_sp av;
1111   GEN M, v, vF = gel(F,2), L = gel(F,3), dL = gel(F,4);
1112   if (lg(L) == 1) return zerovec(n+1);
1113   av = avma;
1114   M = bhnmat_extend_nocache(NULL, mf_get_N(F), n, d, vF);
1115   v = RgM_RgC_mul(M,L); settyp(v, t_VEC);
1116   if (!is_pm1(dL)) v = gdiv(v, dL);
1117   return gerepileupto(av, v);
1118 }
1119 
1120 /* c in K, K := Q[X]/(T) vz = vector of consecutive powers of root z of T
1121  * attached to an embedding s: K -> C. Return s(c) in C */
1122 static GEN
Rg_embed1(GEN c,GEN vz)1123 Rg_embed1(GEN c, GEN vz)
1124 {
1125   long t = typ(c);
1126   if (t == t_POLMOD) { c = gel(c,2); t = typ(c); }
1127   if (t == t_POL) c = RgX_RgV_eval(c, vz);
1128   return c;
1129 }
1130 /* return s(P) in C[X] */
1131 static GEN
RgX_embed1(GEN P,GEN vz)1132 RgX_embed1(GEN P, GEN vz)
1133 {
1134   long i, l;
1135   GEN Q = cgetg_copy(P, &l);
1136   Q[1] = P[1];
1137   for (i = 2; i < l; i++) gel(Q,i) = Rg_embed1(gel(P,i), vz);
1138   return normalizepol_lg(Q,l); /* normally a no-op */
1139 }
1140 /* return s(P) in C^n */
1141 static GEN
vecembed1(GEN P,GEN vz)1142 vecembed1(GEN P, GEN vz)
1143 {
1144   long i, l;
1145   GEN Q = cgetg_copy(P, &l);
1146   for (i = 1; i < l; i++) gel(Q,i) = Rg_embed1(gel(P,i), vz);
1147   return Q;
1148 }
1149 /* P in L = K[X]/(U), K = Q[t]/T; s an embedding of K -> C attached
1150  * to a root of T, extended to an embedding of L -> C attached to a root
1151  * of s(U); vT powers of the root of T, vU powers of the root of s(U).
1152  * Return s(P) in C^n */
1153 static GEN
Rg_embed2(GEN P,long vt,GEN vT,GEN vU)1154 Rg_embed2(GEN P, long vt, GEN vT, GEN vU)
1155 {
1156   long i, l;
1157   GEN Q;
1158   P = liftpol_shallow(P);
1159   if (typ(P) != t_POL) return P;
1160   if (varn(P) == vt) return Rg_embed1(P, vT);
1161   /* varn(P) == vx */
1162   Q = cgetg_copy(P, &l); Q[1] = P[1];
1163   for (i = 2; i < l; i++) gel(Q,i) = Rg_embed1(gel(P,i), vT);
1164   return Rg_embed1(Q, vU);
1165 }
1166 static GEN
vecembed2(GEN P,long vt,GEN vT,GEN vU)1167 vecembed2(GEN P, long vt, GEN vT, GEN vU)
1168 {
1169   long i, l;
1170   GEN Q = cgetg_copy(P, &l);
1171   for (i = 1; i < l; i++) gel(Q,i) = Rg_embed2(gel(P,i), vt, vT, vU);
1172   return Q;
1173 }
1174 static GEN
RgX_embed2(GEN P,long vt,GEN vT,GEN vU)1175 RgX_embed2(GEN P, long vt, GEN vT, GEN vU)
1176 {
1177   long i, l;
1178   GEN Q = cgetg_copy(P, &l);
1179   for (i = 2; i < l; i++) gel(Q,i) = Rg_embed2(gel(P,i), vt, vT, vU);
1180   Q[1] = P[1]; return normalizepol_lg(Q,l);
1181 }
1182 /* embed polynomial f in variable vx [ may be a scalar ], E from getembed */
1183 static GEN
RgX_embed(GEN f,long vx,GEN E)1184 RgX_embed(GEN f, long vx, GEN E)
1185 {
1186   GEN vT;
1187   if (typ(f) != t_POL || varn(f) != vx) return mfembed(E, f);
1188   if (lg(E) == 1) return f;
1189   vT = gel(E,2);
1190   if (lg(E) == 3)
1191     f = RgX_embed1(f, vT);
1192   else
1193     f = RgX_embed2(f, varn(gel(E,1)), vT, gel(E,3));
1194   return f;
1195 }
1196 /* embed vector, E from getembed */
1197 GEN
mfvecembed(GEN E,GEN v)1198 mfvecembed(GEN E, GEN v)
1199 {
1200   GEN vT;
1201   if (lg(E) == 1) return v;
1202   vT = gel(E,2);
1203   if (lg(E) == 3)
1204     v = vecembed1(v, vT);
1205   else
1206     v = vecembed2(v, varn(gel(E,1)), vT, gel(E,3));
1207   return v;
1208 }
1209 GEN
mfmatembed(GEN E,GEN f)1210 mfmatembed(GEN E, GEN f)
1211 {
1212   long i, l;
1213   GEN g;
1214   if (lg(E) == 1) return f;
1215   g = cgetg_copy(f, &l);
1216   for (i = 1; i < l; i++) gel(g,i) = mfvecembed(E, gel(f,i));
1217   return g;
1218 }
1219 /* embed vector of polynomials in var vx */
1220 static GEN
RgXV_embed(GEN f,long vx,GEN E)1221 RgXV_embed(GEN f, long vx, GEN E)
1222 {
1223   long i, l;
1224   GEN v;
1225   if (lg(E) == 1) return f;
1226   v = cgetg_copy(f, &l);
1227   for (i = 1; i < l; i++) gel(v,i) = RgX_embed(gel(f,i), vx, E);
1228   return v;
1229 }
1230 
1231 /* embed scalar */
1232 GEN
mfembed(GEN E,GEN f)1233 mfembed(GEN E, GEN f)
1234 {
1235   GEN vT;
1236   if (lg(E) == 1) return f;
1237   vT = gel(E,2);
1238   if (lg(E) == 3)
1239     f = Rg_embed1(f, vT);
1240   else
1241     f = Rg_embed2(f, varn(gel(E,1)), vT, gel(E,3));
1242   return f;
1243 }
1244 /* vector of the sigma(f), sigma in vE */
1245 static GEN
RgX_embedall(GEN f,long vx,GEN vE)1246 RgX_embedall(GEN f, long vx, GEN vE)
1247 {
1248   long i, l = lg(vE);
1249   GEN v;
1250   if (l == 2) return RgX_embed(f, vx, gel(vE,1));
1251   v = cgetg(l, t_VEC);
1252   for (i = 1; i < l; i++) gel(v,i) = RgX_embed(f, vx, gel(vE,i));
1253   return v;
1254 }
1255 /* matrix whose colums are the sigma(v), sigma in vE */
1256 static GEN
RgC_embedall(GEN v,GEN vE)1257 RgC_embedall(GEN v, GEN vE)
1258 {
1259   long j, l = lg(vE);
1260   GEN M = cgetg(l, t_MAT);
1261   for (j = 1; j < l; j++) gel(M,j) = mfvecembed(gel(vE,j), v);
1262   return M;
1263 }
1264 /* vector of the sigma(v), sigma in vE */
1265 static GEN
Rg_embedall_i(GEN v,GEN vE)1266 Rg_embedall_i(GEN v, GEN vE)
1267 {
1268   long j, l = lg(vE);
1269   GEN M = cgetg(l, t_VEC);
1270   for (j = 1; j < l; j++) gel(M,j) = mfembed(gel(vE,j), v);
1271   return M;
1272 }
1273 /* vector of the sigma(v), sigma in vE; if #vE == 1, return v */
1274 static GEN
Rg_embedall(GEN v,GEN vE)1275 Rg_embedall(GEN v, GEN vE)
1276 { return (lg(vE) == 2)? mfembed(gel(vE,1), v): Rg_embedall_i(v, vE); }
1277 
1278 static GEN
c_div_i(long n,GEN S)1279 c_div_i(long n, GEN S)
1280 {
1281   GEN F = gel(S,2), G = gel(S,3);
1282   GEN a0, a0i, H;
1283   F = mfcoefs_i(F, n, 1);
1284   G = mfcoefs_i(G, n, 1);
1285   if (lg(S) == 5) chicompatlift(gel(S,4),&F,&G);
1286   F = RgV_to_ser_full(F);
1287   G = RgV_to_ser_full(G);
1288   a0 = polcoef_i(G, 0, -1); /* != 0 */
1289   if (gequal1(a0)) a0 = a0i = NULL;
1290   else
1291   {
1292     a0i = ginv(a0);
1293     G = gmul(ser_unscale(G,a0), a0i);
1294     F = gmul(ser_unscale(F,a0), a0i);
1295   }
1296   H = gdiv(F, G);
1297   if (a0) H = ser_unscale(H,a0i);
1298   H = sertovecslice(H, n);
1299   if (lg(S) == 5) H = chicompatfix(gel(S,4), H);
1300   return H;
1301 }
1302 static GEN
c_div(long n,long d,GEN S)1303 c_div(long n, long d, GEN S)
1304 {
1305   pari_sp av = avma;
1306   GEN D = (d==1)? c_div_i(n, S): c_deflate(n, d, c_div_i(n*d, S));
1307   return gerepilecopy(av, D);
1308 }
1309 
1310 static GEN
c_shift(long n,long d,GEN F,GEN gsh)1311 c_shift(long n, long d, GEN F, GEN gsh)
1312 {
1313   pari_sp av = avma;
1314   GEN vF;
1315   long sh = itos(gsh), n1 = n*d + sh;
1316   if (n1 < 0) return zerovec(n+1);
1317   vF = mfcoefs_i(F, n1, 1);
1318   if (sh < 0) vF = shallowconcat(zerovec(-sh), vF);
1319   else vF = vecslice(vF, sh+1, n1+1);
1320   return gerepilecopy(av, c_deflate(n, d, vF));
1321 }
1322 
1323 static GEN
c_deriv(long n,long d,GEN F,GEN gm)1324 c_deriv(long n, long d, GEN F, GEN gm)
1325 {
1326   pari_sp av = avma;
1327   GEN V = mfcoefs_i(F, n, d), res;
1328   long i, m = itos(gm);
1329   if (!m) return V;
1330   res = cgetg(n+2, t_VEC); gel(res,1) = gen_0;
1331   if (m < 0)
1332   { for (i=1; i <= n; i++) gel(res, i+1) = gdiv(gel(V, i+1), powuu(i,-m)); }
1333   else
1334   { for (i=1; i <= n; i++) gel(res, i+1) = gmul(gel(V,i+1), powuu(i,m)); }
1335   return gerepileupto(av, res);
1336 }
1337 
1338 static GEN
c_derivE2(long n,long d,GEN F,GEN gm)1339 c_derivE2(long n, long d, GEN F, GEN gm)
1340 {
1341   pari_sp av = avma;
1342   GEN VF, VE, res, tmp, gk;
1343   long i, m = itos(gm), nd;
1344   if (m == 0) return mfcoefs_i(F, n, d);
1345   nd = n*d;
1346   VF = mfcoefs_i(F, nd, 1); VE = mfcoefs_i(mfEk(2), nd, 1);
1347   gk = mf_get_gk(F);
1348   if (m == 1)
1349   {
1350     res = cgetg(n+2, t_VEC);
1351     for (i = 0; i <= n; i++) gel(res, i+1) = gmulsg(i, gel(VF, i*d+1));
1352     tmp = c_deflate(n, d, RgV_mul_RgXn(VF, VE));
1353     return gerepileupto(av, gsub(res, gmul(gdivgs(gk, 12), tmp)));
1354   }
1355   else
1356   {
1357     long j;
1358     for (j = 1; j <= m; j++)
1359     {
1360       tmp = RgV_mul_RgXn(VF, VE);
1361       for (i = 0; i <= nd; i++) gel(VF, i+1) = gmulsg(i, gel(VF, i+1));
1362       VF = gsub(VF, gmul(gdivgs(gaddgs(gk, 2*(j-1)), 12), tmp));
1363     }
1364     return gerepilecopy(av, c_deflate(n, d, VF));
1365   }
1366 }
1367 
1368 /* Twist by the character (D/.) */
1369 static GEN
c_twist(long n,long d,GEN F,GEN D)1370 c_twist(long n, long d, GEN F, GEN D)
1371 {
1372   pari_sp av = avma;
1373   GEN V = mfcoefs_i(F, n, d), res = cgetg(n+2, t_VEC);
1374   long i;
1375   for (i = 0; i <= n; i++)
1376     gel(res, i + 1) = gmulsg(krois(D, i), gel(V, i+1));
1377   return gerepileupto(av, res);
1378 }
1379 
1380 /* form F given by closure, compute T(n)(F) as closure */
1381 static GEN
c_hecke(long m,long l,GEN DATA,GEN F)1382 c_hecke(long m, long l, GEN DATA, GEN F)
1383 {
1384   pari_sp av = avma;
1385   return gerepilecopy(av, hecke_i(m, l, NULL, F, DATA));
1386 }
1387 static GEN
c_const(long n,long d,GEN C)1388 c_const(long n, long d, GEN C)
1389 {
1390   GEN V = zerovec(n+1);
1391   long i, j, l = lg(C);
1392   if (l > d*n+2) l = d*n+2;
1393   for (i = j = 1; i < l; i+=d, j++) gel(V, j) = gcopy(gel(C,i));
1394   return V;
1395 }
1396 
1397 /* m > 0 */
1398 static GEN
eta3_ZXn(long m)1399 eta3_ZXn(long m)
1400 {
1401   long l = m+2, n, k;
1402   GEN P = cgetg(l,t_POL);
1403   P[1] = evalsigne(1)|evalvarn(0);
1404   for (n = 2; n < l; n++) gel(P,n) = gen_0;
1405   for (n = k = 0;; n++)
1406   {
1407     if (k + n >= m) { setlg(P, k+3); return P; }
1408     k += n;
1409     /* now k = n(n+1) / 2 */
1410     gel(P, k+2) = odd(n)? utoineg(2*n+1): utoipos(2*n+1);
1411   }
1412 }
1413 
1414 static GEN
c_delta(long n,long d)1415 c_delta(long n, long d)
1416 {
1417   pari_sp ltop = avma;
1418   long N = n*d;
1419   GEN e;
1420   if (!N) return mkvec(gen_0);
1421   e = eta3_ZXn(N);
1422   e = ZXn_sqr(e,N);
1423   e = ZXn_sqr(e,N);
1424   e = ZXn_sqr(e,N); /* eta(x)^24 */
1425   settyp(e, t_VEC);
1426   gel(e,1) = gen_0; /* Delta(x) = x*eta(x)^24 as a t_VEC */
1427   return gerepilecopy(ltop, c_deflate(n, d, e));
1428 }
1429 
1430 /* return s(d) such that s|f <=> d | f^2 */
1431 static long
mysqrtu(ulong d)1432 mysqrtu(ulong d)
1433 {
1434   GEN fa = myfactoru(d), P = gel(fa,1), E = gel(fa,2);
1435   long l = lg(P), i, s = 1;
1436   for (i = 1; i < l; i++) s *= upowuu(P[i], (E[i]+1)>>1);
1437   return s;
1438 }
1439 static GEN
c_theta(long n,long d,GEN psi)1440 c_theta(long n, long d, GEN psi)
1441 {
1442   long lim = usqrt(n*d), F = mfcharmodulus(psi), par = mfcharparity(psi);
1443   long f, d2 = d == 1? 1: mysqrtu(d);
1444   GEN V = zerovec(n + 1);
1445   for (f = d2; f <= lim; f += d2)
1446     if (ugcd(F, f) == 1)
1447     {
1448       pari_sp av = avma;
1449       GEN c = mfchareval(psi, f);
1450       gel(V, f*f/d + 1) = gerepileupto(av, par < 0 ? gmulgs(c,2*f) : gmul2n(c,1));
1451     }
1452   if (F == 1) gel(V, 1) = gen_1;
1453   return V; /* no gerepile needed */
1454 }
1455 
1456 static GEN
c_etaquo(long n,long d,GEN eta,GEN gs)1457 c_etaquo(long n, long d, GEN eta, GEN gs)
1458 {
1459   pari_sp av = avma;
1460   long s = itos(gs), nd = n*d, nds = nd - s + 1;
1461   GEN c;
1462   if (nds <= 0) return zerovec(n+1);
1463   c = RgX_to_RgC(eta_product_ZXn(eta, nds), nds); settyp(c, t_VEC);
1464   if (s > 0) c = shallowconcat(zerovec(s), c);
1465   return gerepilecopy(av, c_deflate(n, d, c));
1466 }
1467 
1468 static GEN
c_ell(long n,long d,GEN E)1469 c_ell(long n, long d, GEN E)
1470 {
1471   pari_sp av = avma;
1472   GEN v;
1473   if (d == 1) return concat(gen_0, anell(E, n));
1474   v = shallowconcat(gen_0, anell(E, n*d));
1475   return gerepilecopy(av, c_deflate(n, d, v));
1476 }
1477 
1478 static GEN
c_cusptrace(long n,long d,GEN F)1479 c_cusptrace(long n, long d, GEN F)
1480 {
1481   pari_sp av = avma;
1482   GEN D = gel(F,2), res = cgetg(n+2, t_VEC);
1483   long i, N = mf_get_N(F), k = mf_get_k(F);
1484   gel(res, 1) = gen_0;
1485   for (i = 1; i <= n; i++)
1486     gel(res, i+1) = mfcusptrace_i(N, k, i*d, mydivisorsu(i*d), D);
1487   return gerepilecopy(av, res);
1488 }
1489 
1490 static GEN
c_newtrace(long n,long d,GEN F)1491 c_newtrace(long n, long d, GEN F)
1492 {
1493   pari_sp av = avma;
1494   cachenew_t cache;
1495   long N = mf_get_N(F);
1496   GEN v;
1497   init_cachenew(&cache, n*d, N, F);
1498   v = colnewtrace(0, n, d, N, mf_get_k(F), &cache);
1499   settyp(v, t_VEC); return gerepilecopy(av, v);
1500 }
1501 
1502 static GEN
c_Bd(long n,long d,GEN F,GEN A)1503 c_Bd(long n, long d, GEN F, GEN A)
1504 {
1505   pari_sp av = avma;
1506   long a = itou(A), ad = ugcd(a,d), aad = a/ad, i, j;
1507   GEN w, v = mfcoefs_i(F, n/aad, d/ad);
1508   if (a == 1) return v;
1509   n++; w = zerovec(n);
1510   for (i = j = 1; j <= n; i++, j += aad) gel(w,j) = gcopy(gel(v,i));
1511   return gerepileupto(av, w);
1512 }
1513 
1514 static GEN
c_dihedral(long n,long d,GEN bnr,GEN w,GEN k0j)1515 c_dihedral(long n, long d, GEN bnr, GEN w, GEN k0j)
1516 {
1517   pari_sp av = avma;
1518   GEN V = dihan(bnr, w, k0j, n*d);
1519   GEN Tinit = gel(w,3), Pm = gel(Tinit,1);
1520   GEN A = c_deflate(n, d, V);
1521   if (degpol(Pm) == 1 || RgV_is_ZV(A)) return gerepilecopy(av, A);
1522   return gerepileupto(av, gmodulo(A, Pm));
1523 }
1524 
1525 static GEN
c_mfEH(long n,long d,GEN F)1526 c_mfEH(long n, long d, GEN F)
1527 {
1528   pari_sp av = avma;
1529   GEN v, M, A;
1530   long i, r = mf_get_r(F);
1531   if (n == 1)
1532     return gerepilecopy(av, mkvec2(mfEHcoef(r,0),mfEHcoef(r,d)));
1533   /* speedup mfcoef */
1534   if (r == 1)
1535   {
1536     v = cgetg(n+2, t_VEC);
1537     gel(v,1) = sstoQ(-1,12);
1538     for (i = 1; i <= n; i++)
1539     {
1540       long id = i*d, a = id & 3;
1541       gel(v,i+1) = (a==1 || a==2)? gen_0: sstoQ(hclassno6u(id), 6);
1542     }
1543     return v; /* no gerepile needed */
1544   }
1545   M = mfEHmat(n*d+1,r);
1546   if (d > 1)
1547   {
1548     long l = lg(M);
1549     for (i = 1; i < l; i++) gel(M,i) = c_deflate(n, d, gel(M,i));
1550   }
1551   A = gel(F,2); /* [num(B), den(B)] */
1552   v = RgC_Rg_div(RgM_RgC_mul(M, gel(A,1)), gel(A,2));
1553   settyp(v,t_VEC); return gerepileupto(av, v);
1554 }
1555 
1556 static GEN
c_mfeisen(long n,long d,GEN F)1557 c_mfeisen(long n, long d, GEN F)
1558 {
1559   pari_sp av = avma;
1560   GEN v, vchi, E0, P, T, CHI, gk = mf_get_gk(F);
1561   long i, k;
1562   if (typ(gk) != t_INT) return c_mfEH(n, d, F);
1563   k = itou(gk);
1564   vchi = gel(F,2);
1565   E0 = gel(vchi,1);
1566   T = gel(vchi,2);
1567   P = gel(T,1);
1568   CHI = gel(vchi,3);
1569   v = cgetg(n+2, t_VEC);
1570   gel(v, 1) = gcopy(E0); /* E(0) */
1571   if (lg(vchi) == 5)
1572   { /* E_k(chi1,chi2) */
1573     GEN CHI2 = gel(vchi,4), F3 = gel(F,3);
1574     long ord = F3[1], j = F3[2];
1575     for (i = 1; i <= n; i++) gel(v, i+1) = sigchi2(k, CHI, CHI2, i*d, ord);
1576     v = QabV_tracerel(T, j, v);
1577   }
1578   else
1579   { /* E_k(chi) */
1580     for (i = 1; i <= n; i++) gel(v, i+1) = sigchi(k, CHI, i*d);
1581   }
1582   if (degpol(P) != 1 && !RgV_is_QV(v)) return gerepileupto(av, gmodulo(v, P));
1583   return gerepilecopy(av, v);
1584 }
1585 
1586 /* L(chi_D, 1-k) */
1587 static GEN
lfunquadneg_naive(long D,long k)1588 lfunquadneg_naive(long D, long k)
1589 {
1590   GEN B, dS, S = gen_0;
1591   long r, N = labs(D);
1592   pari_sp av;
1593   if (k == 1 && N == 1) return gneg(ghalf);
1594   /* B = N^k * denom(B) * B(x/N) */
1595   B = ZX_rescale(Q_remove_denom(bernpol(k, 0), &dS), utoi(N));
1596   dS = mul_denom(dS, stoi(-N*k));
1597   av = avma;
1598   for (r = 0; r < N; r++)
1599   {
1600     long c = kross(D, r);
1601     if (c)
1602     {
1603       GEN tmp = poleval(B, utoi(r));
1604       S = c > 0 ? addii(S, tmp) : subii(S, tmp);
1605       S = gerepileuptoint(av, S);
1606     }
1607   }
1608   return gdiv(S, dS);
1609 }
1610 
1611 /* Returns vector of coeffs from F[0], F[d], ..., F[d*n] */
1612 static GEN
mfcoefs_i(GEN F,long n,long d)1613 mfcoefs_i(GEN F, long n, long d)
1614 {
1615   if (n < 0) return gen_0;
1616   switch(mf_get_type(F))
1617   {
1618     case t_MF_CONST: return c_const(n, d, gel(F,2));
1619     case t_MF_EISEN: return c_mfeisen(n, d, F);
1620     case t_MF_Ek: return c_Ek(n, d, F);
1621     case t_MF_DELTA: return c_delta(n, d);
1622     case t_MF_THETA: return c_theta(n, d, gel(F,2));
1623     case t_MF_ETAQUO: return c_etaquo(n, d, gel(F,2), gel(F,3));
1624     case t_MF_ELL: return c_ell(n, d, gel(F,2));
1625     case t_MF_MUL: return c_mul(n, d, F);
1626     case t_MF_POW: return c_pow(n, d, F);
1627     case t_MF_BRACKET: return c_bracket(n, d, F);
1628     case t_MF_LINEAR: return c_linear(n, d, gel(F,2), gel(F,3), gel(F,4));
1629     case t_MF_LINEAR_BHN: return c_linear_bhn(n, d, F);
1630     case t_MF_DIV: return c_div(n, d, F);
1631     case t_MF_SHIFT: return c_shift(n, d, gel(F,2), gel(F,3));
1632     case t_MF_DERIV: return c_deriv(n, d, gel(F,2), gel(F,3));
1633     case t_MF_DERIVE2: return c_derivE2(n, d, gel(F,2), gel(F,3));
1634     case t_MF_TWIST: return c_twist(n, d, gel(F,2), gel(F,3));
1635     case t_MF_HECKE: return c_hecke(n, d, gel(F,2), gel(F,3));
1636     case t_MF_BD: return c_Bd(n, d, gel(F,2), gel(F,3));
1637     case t_MF_TRACE: return c_cusptrace(n, d, F);
1638     case t_MF_NEWTRACE: return c_newtrace(n, d, F);
1639     case t_MF_DIHEDRAL: return c_dihedral(n, d, gel(F,2), gel(F,3), gel(F,4));
1640     default: pari_err_TYPE("mfcoefs",F); return NULL;/*LCOV_EXCL_LINE*/
1641   }
1642 }
1643 
1644 static GEN
matdeflate(long n,long d,GEN M)1645 matdeflate(long n, long d, GEN M)
1646 {
1647   long i, l;
1648   GEN A;
1649   /*  if (d == 1) return M; */
1650   A = cgetg_copy(M,&l);
1651   for (i = 1; i < l; i++) gel(A,i) = c_deflate(n,d,gel(M,i));
1652   return A;
1653 }
1654 static int
space_is_cusp(long space)1655 space_is_cusp(long space) { return space != mf_FULL && space != mf_EISEN; }
1656 /* safe with flraw mf */
1657 static GEN
mfcoefs_mf(GEN mf,long n,long d)1658 mfcoefs_mf(GEN mf, long n, long d)
1659 {
1660   GEN MS, ME, E = MF_get_E(mf), S = MF_get_S(mf), M = MF_get_M(mf);
1661   long lE = lg(E), lS = lg(S), l = lE+lS-1;
1662 
1663   if (l == 1) return cgetg(1, t_MAT);
1664   if (typ(M) == t_MAT && lg(M) != 1 && (n+1)*d < nbrows(M))
1665     return matdeflate(n, d, M); /*cached; lg = 1 is possible from mfinit */
1666   ME = (lE == 1)? cgetg(1, t_MAT): mfvectomat(E, n, d);
1667   if (lS == 1)
1668     MS = cgetg(1, t_MAT);
1669   else if (mf_get_type(gel(S,1)) == t_MF_DIV) /*k 1/2-integer or k=1 (exotic)*/
1670     MS = matdeflate(n,d, mflineardivtomat(MF_get_N(mf), S, n*d));
1671   else if (MF_get_k(mf) == 1) /* k = 1 (dihedral) */
1672   {
1673     GEN M = mfvectomat(gmael(S,1,2), n, d);
1674     long i;
1675     MS = cgetg(lS, t_MAT);
1676     for (i = 1; i < lS; i++)
1677     {
1678       GEN f = gel(S,i), dc = gel(f,4), c = RgM_RgC_mul(M, gel(f,3));
1679       if (!equali1(dc)) c = RgC_Rg_div(c,dc);
1680       gel(MS,i) = c;
1681     }
1682   }
1683   else /* k >= 2 integer */
1684     MS = bhnmat_extend_nocache(NULL, MF_get_N(mf), n, d, S);
1685   return shallowconcat(ME,MS);
1686 }
1687 GEN
mfcoefs(GEN F,long n,long d)1688 mfcoefs(GEN F, long n, long d)
1689 {
1690   if (!checkmf_i(F))
1691   {
1692     pari_sp av = avma;
1693     GEN mf = checkMF_i(F); if (!mf) pari_err_TYPE("mfcoefs", F);
1694     return gerepilecopy(av, mfcoefs_mf(mf,n,d));
1695   }
1696   if (d <= 0) pari_err_DOMAIN("mfcoefs", "d", "<=", gen_0, stoi(d));
1697   if (n < 0) return cgetg(1, t_VEC);
1698   return mfcoefs_i(F, n, d);
1699 }
1700 
1701 /* assume k >= 0 */
1702 static GEN
mfak_i(GEN F,long k)1703 mfak_i(GEN F, long k)
1704 {
1705   if (!k) return gel(mfcoefs_i(F,0,1), 1);
1706   return gel(mfcoefs_i(F,1,k), 2);
1707 }
1708 GEN
mfcoef(GEN F,long n)1709 mfcoef(GEN F, long n)
1710 {
1711   pari_sp av = avma;
1712   if (!checkmf_i(F)) pari_err_TYPE("mfcoef",F);
1713   return n < 0? gen_0: gerepilecopy(av, mfak_i(F, n));
1714 }
1715 
1716 static GEN
paramconst()1717 paramconst() { return tagparams(t_MF_CONST, mkNK(1,0,mfchartrivial())); }
1718 static GEN
mftrivial(void)1719 mftrivial(void) { retmkvec2(paramconst(), cgetg(1,t_VEC)); }
1720 static GEN
mf1(void)1721 mf1(void) { retmkvec2(paramconst(), mkvec(gen_1)); }
1722 
1723 /* induce mfchar CHI to G */
1724 static GEN
induce(GEN G,GEN CHI)1725 induce(GEN G, GEN CHI)
1726 {
1727   GEN o, chi;
1728   if (typ(CHI) == t_INT) /* Kronecker */
1729   {
1730     chi = znchar_quad(G, CHI);
1731     o = ZV_equal0(chi)? gen_1: gen_2;
1732     CHI = mkvec4(G,chi,o,cgetg(1,t_VEC));
1733   }
1734   else
1735   {
1736     if (mfcharmodulus(CHI) == itos(znstar_get_N(G))) return CHI;
1737     CHI = leafcopy(CHI);
1738     chi = zncharinduce(gel(CHI,1), gel(CHI,2), G);
1739     gel(CHI,1) = G;
1740     gel(CHI,2) = chi;
1741   }
1742   return CHI;
1743 }
1744 /* induce mfchar CHI to znstar(G) */
1745 static GEN
induceN(long N,GEN CHI)1746 induceN(long N, GEN CHI)
1747 {
1748   if (mfcharmodulus(CHI) != N) CHI = induce(znstar0(utoipos(N),1), CHI);
1749   return CHI;
1750 }
1751 /* *pCHI1 and *pCHI2 are mfchar, induce to common modulus */
1752 static void
char2(GEN * pCHI1,GEN * pCHI2)1753 char2(GEN *pCHI1, GEN *pCHI2)
1754 {
1755   GEN CHI1 = *pCHI1, G1 = gel(CHI1,1), N1 = znstar_get_N(G1);
1756   GEN CHI2 = *pCHI2, G2 = gel(CHI2,1), N2 = znstar_get_N(G2);
1757   if (!equalii(N1,N2))
1758   {
1759     GEN G, d = gcdii(N1,N2);
1760     if      (equalii(N2,d)) *pCHI2 = induce(G1, CHI2);
1761     else if (equalii(N1,d)) *pCHI1 = induce(G2, CHI1);
1762     else
1763     {
1764       if (!equali1(d)) N2 = diviiexact(N2,d);
1765       G = znstar0(mulii(N1,N2), 1);
1766       *pCHI1 = induce(G, CHI1);
1767       *pCHI2 = induce(G, CHI2);
1768     }
1769   }
1770 }
1771 /* mfchar or charinit wrt same modulus; outputs a mfchar */
1772 static GEN
mfcharmul_i(GEN CHI1,GEN CHI2)1773 mfcharmul_i(GEN CHI1, GEN CHI2)
1774 {
1775   GEN G = gel(CHI1,1), chi3 = zncharmul(G, gel(CHI1,2), gel(CHI2,2));
1776   return mfcharGL(G, chi3);
1777 }
1778 /* mfchar or charinit; outputs a mfchar */
1779 static GEN
mfcharmul(GEN CHI1,GEN CHI2)1780 mfcharmul(GEN CHI1, GEN CHI2)
1781 {
1782   char2(&CHI1, &CHI2); return mfcharmul_i(CHI1,CHI2);
1783 }
1784 /* mfchar or charinit; outputs a mfchar */
1785 static GEN
mfcharpow(GEN CHI,GEN n)1786 mfcharpow(GEN CHI, GEN n)
1787 {
1788   GEN G, chi;
1789   G = gel(CHI,1); chi = zncharpow(G, gel(CHI,2), n);
1790   return mfchartoprimitive(mfcharGL(G, chi), NULL);
1791 }
1792 /* mfchar or charinit wrt same modulus; outputs a mfchar */
1793 static GEN
mfchardiv_i(GEN CHI1,GEN CHI2)1794 mfchardiv_i(GEN CHI1, GEN CHI2)
1795 {
1796   GEN G = gel(CHI1,1), chi3 = znchardiv(G, gel(CHI1,2), gel(CHI2,2));
1797   return mfcharGL(G, chi3);
1798 }
1799 /* mfchar or charinit; outputs a mfchar */
1800 static GEN
mfchardiv(GEN CHI1,GEN CHI2)1801 mfchardiv(GEN CHI1, GEN CHI2)
1802 {
1803   char2(&CHI1, &CHI2); return mfchardiv_i(CHI1,CHI2);
1804 }
1805 static GEN
mfcharconj(GEN CHI)1806 mfcharconj(GEN CHI)
1807 {
1808   CHI = leafcopy(CHI);
1809   gel(CHI,2) = zncharconj(gel(CHI,1), gel(CHI,2));
1810   return CHI;
1811 }
1812 
1813 /* CHI mfchar, assume 4 | N. Multiply CHI by \chi_{-4} */
1814 static GEN
mfchilift(GEN CHI,long N)1815 mfchilift(GEN CHI, long N)
1816 {
1817   CHI = induceN(N, CHI);
1818   return mfcharmul_i(CHI, induce(gel(CHI,1), stoi(-4)));
1819 }
1820 /* CHI defined mod N, N4 = N/4;
1821  * if CHI is defined mod N4 return CHI;
1822  * else if CHI' = CHI*(-4,.) is defined mod N4, return CHI' (primitive)
1823  * else error */
1824 static GEN
mfcharchiliftprim(GEN CHI,long N4)1825 mfcharchiliftprim(GEN CHI, long N4)
1826 {
1827   long FC = mfcharconductor(CHI);
1828   GEN CHIP;
1829   if (N4 % FC == 0) return CHI;
1830   CHIP = mfchartoprimitive(mfchilift(CHI, N4 << 2), &FC);
1831   if (N4 % FC) pari_err_TYPE("mfkohnenbasis [incorrect CHI]", CHI);
1832   return CHIP;
1833 }
1834 /* ensure CHI(-1) = (-1)^k [k integer] or 1 [half-integer], by multiplying
1835  * by (-4/.) if needed */
1836 static GEN
mfchiadjust(GEN CHI,GEN gk,long N)1837 mfchiadjust(GEN CHI, GEN gk, long N)
1838 {
1839   long par = mfcharparity(CHI);
1840   if (typ(gk) == t_INT &&  mpodd(gk)) par = -par;
1841   return par == 1 ? CHI : mfchilift(CHI, N);
1842 }
1843 
1844 static GEN
mfsamefield(GEN T,GEN P,GEN Q)1845 mfsamefield(GEN T, GEN P, GEN Q)
1846 {
1847   if (degpol(P) == 1) return Q;
1848   if (degpol(Q) == 1) return P;
1849   if (!gequal(P,Q)) pari_err_TYPE("mfsamefield [different fields]",mkvec2(P,Q));
1850   if (T) err_cyclo();
1851   return P;
1852 }
1853 
1854 GEN
mfmul(GEN f,GEN g)1855 mfmul(GEN f, GEN g)
1856 {
1857   pari_sp av = avma;
1858   GEN T, N, K, NK, CHI, CHIf, CHIg;
1859   if (!checkmf_i(f)) pari_err_TYPE("mfmul",f);
1860   if (!checkmf_i(g)) pari_err_TYPE("mfmul",g);
1861   N = lcmii(mf_get_gN(f), mf_get_gN(g));
1862   K = gadd(mf_get_gk(f), mf_get_gk(g));
1863   CHIf = mf_get_CHI(f);
1864   CHIg = mf_get_CHI(g);
1865   CHI = mfchiadjust(mfcharmul(CHIf,CHIg), K, itos(N));
1866   T = chicompat(CHI, CHIf, CHIg);
1867   NK = mkgNK(N, K, CHI, mfsamefield(T, mf_get_field(f), mf_get_field(g)));
1868   return gerepilecopy(av, T? tag3(t_MF_MUL,NK,f,g,T): tag2(t_MF_MUL,NK,f,g));
1869 }
1870 GEN
mfpow(GEN f,long n)1871 mfpow(GEN f, long n)
1872 {
1873   pari_sp av = avma;
1874   GEN T, KK, NK, gn, CHI, CHIf;
1875   if (!checkmf_i(f)) pari_err_TYPE("mfpow",f);
1876   if (!n) return mf1();
1877   if (n == 1) return gcopy(f);
1878   KK = gmulsg(n,mf_get_gk(f));
1879   gn = stoi(n);
1880   CHIf = mf_get_CHI(f);
1881   CHI = mfchiadjust(mfcharpow(CHIf,gn), KK, mf_get_N(f));
1882   T = chicompat(CHI, CHIf, CHIf);
1883   NK = mkgNK(mf_get_gN(f), KK, CHI, mf_get_field(f));
1884   return gerepilecopy(av, T? tag3(t_MF_POW,NK,f,gn,T): tag2(t_MF_POW,NK,f,gn));
1885 }
1886 GEN
mfbracket(GEN f,GEN g,long m)1887 mfbracket(GEN f, GEN g, long m)
1888 {
1889   pari_sp av = avma;
1890   GEN T, N, K, NK, CHI, CHIf, CHIg;
1891   if (!checkmf_i(f)) pari_err_TYPE("mfbracket",f);
1892   if (!checkmf_i(g)) pari_err_TYPE("mfbracket",g);
1893   if (m < 0) pari_err_TYPE("mfbracket [m<0]",stoi(m));
1894   K = gaddgs(gadd(mf_get_gk(f), mf_get_gk(g)), 2*m);
1895   if (gsigne(K) < 0) pari_err_IMPL("mfbracket for this form");
1896   N = lcmii(mf_get_gN(f), mf_get_gN(g));
1897   CHIf = mf_get_CHI(f);
1898   CHIg = mf_get_CHI(g);
1899   CHI = mfcharmul(CHIf, CHIg);
1900   CHI = mfchiadjust(CHI, K, itou(N));
1901   T = chicompat(CHI, CHIf, CHIg);
1902   NK = mkgNK(N, K, CHI, mfsamefield(T, mf_get_field(f), mf_get_field(g)));
1903   return gerepilecopy(av, T? tag4(t_MF_BRACKET, NK, f, g, utoi(m), T)
1904                            : tag3(t_MF_BRACKET, NK, f, g, utoi(m)));
1905 }
1906 
1907 /* remove 0 entries in L */
1908 static int
mflinear_strip(GEN * pF,GEN * pL)1909 mflinear_strip(GEN *pF, GEN *pL)
1910 {
1911   pari_sp av = avma;
1912   GEN F = *pF, L = *pL;
1913   long i, j, l = lg(L);
1914   GEN F2 = cgetg(l, t_VEC), L2 = cgetg(l, t_VEC);
1915   for (i = j = 1; i < l; i++)
1916   {
1917     if (gequal0(gel(L,i))) continue;
1918     gel(F2,j) = gel(F,i);
1919     gel(L2,j) = gel(L,i); j++;
1920   }
1921   if (j == l) set_avma(av);
1922   else
1923   {
1924     setlg(F2,j); *pF = F2;
1925     setlg(L2,j); *pL = L2;
1926   }
1927   return (j > 1);
1928 }
1929 static GEN
taglinear_i(long t,GEN NK,GEN F,GEN L)1930 taglinear_i(long t, GEN NK, GEN F, GEN L)
1931 {
1932   GEN dL;
1933   L = Q_remove_denom(L, &dL); if (!dL) dL = gen_1;
1934   return tag3(t, NK, F, L, dL);
1935 }
1936 static GEN
taglinear(GEN NK,GEN F,GEN L)1937 taglinear(GEN NK, GEN F, GEN L)
1938 {
1939   long t = ok_bhn_linear(F)? t_MF_LINEAR_BHN: t_MF_LINEAR;
1940    return taglinear_i(t, NK, F, L);
1941 }
1942 /* assume F has parameters NK = [N,K,CHI] */
1943 static GEN
mflinear_i(GEN NK,GEN F,GEN L)1944 mflinear_i(GEN NK, GEN F, GEN L)
1945 {
1946   if (!mflinear_strip(&F,&L)) return mftrivial();
1947   return taglinear(NK, F,L);
1948 }
1949 static GEN
mflinear_bhn(GEN mf,GEN L)1950 mflinear_bhn(GEN mf, GEN L)
1951 {
1952   long i, l;
1953   GEN P, NK, F = MF_get_S(mf);
1954   if (!mflinear_strip(&F,&L)) return mftrivial();
1955   l = lg(L); P = pol_x(1);
1956   for (i = 1; i < l; i++)
1957   {
1958     GEN c = gel(L,i);
1959     if (typ(c) == t_POLMOD && varn(gel(c,1)) == 1)
1960       P = mfsamefield(NULL, P, gel(c,1));
1961   }
1962   NK = mkgNK(MF_get_gN(mf), MF_get_gk(mf), MF_get_CHI(mf), P);
1963   return taglinear_i(t_MF_LINEAR_BHN,  NK, F,L);
1964 }
1965 
1966 /* F vector of forms with same weight and character but varying level, return
1967  * global [N,k,chi,P] */
1968 static GEN
vecmfNK(GEN F)1969 vecmfNK(GEN F)
1970 {
1971   long i, l = lg(F);
1972   GEN N, f;
1973   if (l == 1) return mkNK(1, 0, mfchartrivial());
1974   f = gel(F,1); N = mf_get_gN(f);
1975   for (i = 2; i < l; i++) N = lcmii(N, mf_get_gN(gel(F,i)));
1976   return mkgNK(N, mf_get_gk(f), mf_get_CHI(f), mf_get_field(f));
1977 }
1978 /* do not use mflinear: mflineardivtomat rely on F being constant across the
1979  * basis where mflinear strips the ones matched by 0 coeffs. Assume k and CHI
1980  * constant, N is allowed to vary. */
1981 static GEN
vecmflinear(GEN F,GEN C)1982 vecmflinear(GEN F, GEN C)
1983 {
1984   long i, t, l = lg(C);
1985   GEN NK, v = cgetg(l, t_VEC);
1986   if (l == 1) return v;
1987   t = ok_bhn_linear(F)? t_MF_LINEAR_BHN: t_MF_LINEAR;
1988   NK = vecmfNK(F);
1989   for (i = 1; i < l; i++) gel(v,i) = taglinear_i(t, NK, F, gel(C,i));
1990   return v;
1991 }
1992 /* vecmflinear(F,C), then divide everything by E, which has valuation 0 */
1993 static GEN
vecmflineardiv0(GEN F,GEN C,GEN E)1994 vecmflineardiv0(GEN F, GEN C, GEN E)
1995 {
1996   GEN v = vecmflinear(F, C);
1997   long i, l = lg(v);
1998   if (l == 1) return v;
1999   gel(v,1) = mfdiv_val(gel(v,1), E, 0);
2000   for (i = 2; i < l; i++)
2001   { /* v[i] /= E */
2002     GEN f = shallowcopy(gel(v,1));
2003     gel(f,2) = gel(v,i);
2004     gel(v,i) = f;
2005   }
2006   return v;
2007 }
2008 
2009 /* Non empty linear combination of linear combinations of same
2010  * F_j=\sum_i \mu_{i,j}G_i so R = \sum_i (\sum_j(\la_j\mu_{i,j})) G_i */
2011 static GEN
mflinear_linear(GEN F,GEN L,int strip)2012 mflinear_linear(GEN F, GEN L, int strip)
2013 {
2014   long l = lg(F), j;
2015   GEN vF, M = cgetg(l, t_MAT);
2016   L = shallowcopy(L);
2017   for (j = 1; j < l; j++)
2018   {
2019     GEN f = gel(F,j), c = gel(f,3), d = gel(f,4);
2020     if (typ(c) == t_VEC) c = shallowtrans(c);
2021     if (!isint1(d)) gel(L,j) = gdiv(gel(L,j),d);
2022     gel(M,j) = c;
2023   }
2024   vF = gmael(F,1,2); L = RgM_RgC_mul(M,L);
2025   if (strip && !mflinear_strip(&vF,&L)) return mftrivial();
2026   return taglinear(vecmfNK(vF), vF, L);
2027 }
2028 /* F nonempty vector of forms of the form mfdiv(mflinear(B,v), E) where E
2029  * does not vanish at oo, or mflinear(B,v). Apply mflinear(F, L) */
2030 static GEN
mflineardiv_linear(GEN F,GEN L,int strip)2031 mflineardiv_linear(GEN F, GEN L, int strip)
2032 {
2033   long l = lg(F), j;
2034   GEN v, E, f;
2035   if (lg(L) != l) pari_err_DIM("mflineardiv_linear");
2036   f = gel(F,1); /* l > 1 */
2037   if (mf_get_type(f) != t_MF_DIV) return mflinear_linear(F,L,strip);
2038   E = gel(f,3);
2039   v = cgetg(l, t_VEC);
2040   for (j = 1; j < l; j++) { GEN f = gel(F,j); gel(v,j) = gel(f,2); }
2041   return mfdiv_val(mflinear_linear(v,L,strip), E, 0);
2042 }
2043 static GEN
vecmflineardiv_linear(GEN F,GEN M)2044 vecmflineardiv_linear(GEN F, GEN M)
2045 {
2046   long i, l = lg(M);
2047   GEN v = cgetg(l, t_VEC);
2048   for (i = 1; i < l; i++) gel(v,i) = mflineardiv_linear(F, gel(M,i), 0);
2049   return v;
2050 }
2051 
2052 static GEN
tobasis(GEN mf,GEN F,GEN L)2053 tobasis(GEN mf, GEN F, GEN L)
2054 {
2055   if (checkmf_i(L) && mf) return mftobasis(mf, L, 0);
2056   if (typ(F) != t_VEC) pari_err_TYPE("mflinear",F);
2057   if (!is_vec_t(typ(L))) pari_err_TYPE("mflinear",L);
2058   if (lg(L) != lg(F)) pari_err_DIM("mflinear");
2059   return L;
2060 }
2061 GEN
mflinear(GEN F,GEN L)2062 mflinear(GEN F, GEN L)
2063 {
2064   pari_sp av = avma;
2065   GEN G, NK, P, mf = checkMF_i(F), N = NULL, K = NULL, CHI = NULL;
2066   long i, l;
2067   if (mf)
2068   {
2069     GEN gk = MF_get_gk(mf);
2070     F = MF_get_basis(F);
2071     if (typ(gk) != t_INT)
2072       return gerepilecopy(av, mflineardiv_linear(F, L, 1));
2073     if (itou(gk) > 1 && space_is_cusp(MF_get_space(mf)))
2074     {
2075       L = tobasis(mf, F, L);
2076       return gerepilecopy(av, mflinear_bhn(mf, L));
2077     }
2078   }
2079   L = tobasis(mf, F, L);
2080   if (!mflinear_strip(&F,&L)) return mftrivial();
2081 
2082   l = lg(F);
2083   if (l == 2 && gequal1(gel(L,1))) return gerepilecopy(av, gel(F,1));
2084   P = pol_x(1);
2085   for (i = 1; i < l; i++)
2086   {
2087     GEN f = gel(F,i), c = gel(L,i), Ni, Ki;
2088     if (!checkmf_i(f)) pari_err_TYPE("mflinear", f);
2089     Ni = mf_get_gN(f); N = N? lcmii(N, Ni): Ni;
2090     Ki = mf_get_gk(f);
2091     if (!K) K = Ki;
2092     else if (!gequal(K, Ki))
2093       pari_err_TYPE("mflinear [different weights]", mkvec2(K,Ki));
2094     P = mfsamefield(NULL, P, mf_get_field(f));
2095     if (typ(c) == t_POLMOD && varn(gel(c,1)) == 1)
2096       P = mfsamefield(NULL, P, gel(c,1));
2097   }
2098   G = znstar0(N,1);
2099   for (i = 1; i < l; i++)
2100   {
2101     GEN CHI2 = mf_get_CHI(gel(F,i));
2102     CHI2 = induce(G, CHI2);
2103     if (!CHI) CHI = CHI2;
2104     else if (!gequal(CHI, CHI2))
2105       pari_err_TYPE("mflinear [different characters]", mkvec2(CHI,CHI2));
2106   }
2107   NK = mkgNK(N, K, CHI, P);
2108   return gerepilecopy(av, taglinear(NK,F,L));
2109 }
2110 
2111 GEN
mfshift(GEN F,long sh)2112 mfshift(GEN F, long sh)
2113 {
2114   pari_sp av = avma;
2115   if (!checkmf_i(F)) pari_err_TYPE("mfshift",F);
2116   return gerepilecopy(av, tag2(t_MF_SHIFT, mf_get_NK(F), F, stoi(sh)));
2117 }
2118 static long
mfval(GEN F)2119 mfval(GEN F)
2120 {
2121   pari_sp av = avma;
2122   long i = 0, n, sb;
2123   GEN gk, gN;
2124   if (!checkmf_i(F)) pari_err_TYPE("mfval", F);
2125   gN = mf_get_gN(F);
2126   gk = mf_get_gk(F);
2127   sb = mfsturmNgk(itou(gN), gk);
2128   for (n = 1; n <= sb;)
2129   {
2130     GEN v;
2131     if (n > 0.5*sb) n = sb+1;
2132     v = mfcoefs_i(F, n, 1);
2133     for (; i <= n; i++)
2134       if (!gequal0(gel(v, i+1))) return gc_long(av,i);
2135     n <<= 1;
2136   }
2137   return gc_long(av,-1);
2138 }
2139 
2140 GEN
mfdiv_val(GEN f,GEN g,long vg)2141 mfdiv_val(GEN f, GEN g, long vg)
2142 {
2143   GEN T, N, K, NK, CHI, CHIf, CHIg;
2144   if (vg) { f = mfshift(f,vg); g = mfshift(g,vg); }
2145   N = lcmii(mf_get_gN(f), mf_get_gN(g));
2146   K = gsub(mf_get_gk(f), mf_get_gk(g));
2147   CHIf = mf_get_CHI(f);
2148   CHIg = mf_get_CHI(g);
2149   CHI = mfchiadjust(mfchardiv(CHIf, CHIg), K, itos(N));
2150   T = chicompat(CHI, CHIf, CHIg);
2151   NK = mkgNK(N, K, CHI, mfsamefield(T, mf_get_field(f), mf_get_field(g)));
2152   return T? tag3(t_MF_DIV, NK, f, g, T): tag2(t_MF_DIV, NK, f, g);
2153 }
2154 GEN
mfdiv(GEN F,GEN G)2155 mfdiv(GEN F, GEN G)
2156 {
2157   pari_sp av = avma;
2158   long v = mfval(G);
2159   if (!checkmf_i(F)) pari_err_TYPE("mfdiv", F);
2160   if (v < 0 || (v && !gequal0(mfcoefs(F, v-1, 1))))
2161     pari_err_DOMAIN("mfdiv", "ord(G)", ">", strtoGENstr("ord(F)"),
2162                     mkvec2(F, G));
2163   return gerepilecopy(av, mfdiv_val(F, G, v));
2164 }
2165 GEN
mfderiv(GEN F,long m)2166 mfderiv(GEN F, long m)
2167 {
2168   pari_sp av = avma;
2169   GEN NK, gk;
2170   if (!checkmf_i(F)) pari_err_TYPE("mfderiv",F);
2171   gk = gaddgs(mf_get_gk(F), 2*m);
2172   NK = mkgNK(mf_get_gN(F), gk, mf_get_CHI(F), mf_get_field(F));
2173   return gerepilecopy(av, tag2(t_MF_DERIV, NK, F, stoi(m)));
2174 }
2175 GEN
mfderivE2(GEN F,long m)2176 mfderivE2(GEN F, long m)
2177 {
2178   pari_sp av = avma;
2179   GEN NK, gk;
2180   if (!checkmf_i(F)) pari_err_TYPE("mfderivE2",F);
2181   if (m < 0) pari_err_DOMAIN("mfderivE2","m","<",gen_0,stoi(m));
2182   gk = gaddgs(mf_get_gk(F), 2*m);
2183   NK = mkgNK(mf_get_gN(F), gk, mf_get_CHI(F), mf_get_field(F));
2184   return gerepilecopy(av, tag2(t_MF_DERIVE2, NK, F, stoi(m)));
2185 }
2186 
2187 GEN
mftwist(GEN F,GEN D)2188 mftwist(GEN F, GEN D)
2189 {
2190   pari_sp av = avma;
2191   GEN NK, CHI, NT, Da;
2192   long q;
2193   if (!checkmf_i(F)) pari_err_TYPE("mftwist", F);
2194   if (typ(D) != t_INT) pari_err_TYPE("mftwist", D);
2195   Da = mpabs_shallow(D);
2196   CHI = mf_get_CHI(F); q = mfcharconductor(CHI);
2197   NT = glcm(glcm(mf_get_gN(F), mulsi(q, Da)), sqri(Da));
2198   NK = mkgNK(NT, mf_get_gk(F), CHI, mf_get_field(F));
2199   return gerepilecopy(av, tag2(t_MF_TWIST, NK, F, D));
2200 }
2201 
2202 /***************************************************************/
2203 /*                 Generic cache handling                      */
2204 /***************************************************************/
2205 enum { cache_FACT, cache_DIV, cache_H, cache_D, cache_DIH };
2206 typedef struct {
2207   const char *name;
2208   GEN cache;
2209   ulong minself, maxself;
2210   void (*init)(long);
2211   ulong miss, maxmiss;
2212   long compressed;
2213 } cache;
2214 
2215 static void constfact(long lim);
2216 static void constdiv(long lim);
2217 static void consttabh(long lim);
2218 static void consttabdihedral(long lim);
2219 static void constcoredisc(long lim);
2220 static THREAD cache caches[] = {
2221 { "Factors",  NULL,  50000,    50000, &constfact, 0, 0, 0 },
2222 { "Divisors", NULL,  50000,    50000, &constdiv, 0, 0, 0 },
2223 { "H",        NULL, 100000, 10000000, &consttabh, 0, 0, 1 },
2224 { "CorediscF",NULL, 100000, 10000000, &constcoredisc, 0, 0, 0 },
2225 { "Dihedral", NULL,   1000,     3000, &consttabdihedral, 0, 0, 0 },
2226 };
2227 
2228 static void
cache_reset(long id)2229 cache_reset(long id) { caches[id].miss = caches[id].maxmiss = 0; }
2230 static void
cache_delete(long id)2231 cache_delete(long id) { guncloneNULL(caches[id].cache); }
2232 static void
cache_set(long id,GEN S)2233 cache_set(long id, GEN S)
2234 {
2235   GEN old = caches[id].cache;
2236   caches[id].cache = gclone(S);
2237   guncloneNULL(old);
2238 }
2239 
2240 /* handle a cache miss: store stats, possibly reset table; return value
2241  * if (now) cached; return NULL on failure. HACK: some caches contain an
2242  * ulong where the 0 value is impossible, and return it (typecast to GEN) */
2243 static GEN
cache_get(long id,ulong D)2244 cache_get(long id, ulong D)
2245 {
2246   cache *S = &caches[id];
2247   const ulong d = S->compressed? D>>1: D;
2248   ulong max, l;
2249 
2250   if (!S->cache)
2251   {
2252     max = maxuu(minuu(D, S->maxself), S->minself);
2253     S->init(max);
2254     l = lg(S->cache);
2255   }
2256   else
2257   {
2258     l = lg(S->cache);
2259     if (l <= d)
2260     {
2261       if (D > S->maxmiss) S->maxmiss = D;
2262       if (DEBUGLEVEL >= 3)
2263         err_printf("miss in cache %s: %lu, max = %lu\n",
2264                    S->name, D, S->maxmiss);
2265       if (S->miss++ >= 5 && D < S->maxself)
2266       {
2267         max = minuu(S->maxself, (long)(S->maxmiss * 1.2));
2268         if (max <= S->maxself)
2269         {
2270           if (DEBUGLEVEL >= 3)
2271             err_printf("resetting cache %s to %lu\n", S->name, max);
2272           S->init(max); l = lg(S->cache);
2273         }
2274       }
2275     }
2276   }
2277   return (l <= d)? NULL: gel(S->cache, d);
2278 }
2279 static GEN
cache_report(long id)2280 cache_report(long id)
2281 {
2282   cache *S = &caches[id];
2283   GEN v = zerocol(5);
2284   gel(v,1) = strtoGENstr(S->name);
2285   if (S->cache)
2286   {
2287     gel(v,2) = utoi(lg(S->cache)-1);
2288     gel(v,3) = utoi(S->miss);
2289     gel(v,4) = utoi(S->maxmiss);
2290     gel(v,5) = utoi(gsizebyte(S->cache));
2291   }
2292   return v;
2293 }
2294 GEN
getcache(void)2295 getcache(void)
2296 {
2297   pari_sp av = avma;
2298   GEN M = cgetg(6, t_MAT);
2299   gel(M,1) = cache_report(cache_FACT);
2300   gel(M,2) = cache_report(cache_DIV);
2301   gel(M,3) = cache_report(cache_H);
2302   gel(M,4) = cache_report(cache_D);
2303   gel(M,5) = cache_report(cache_DIH);
2304   return gerepilecopy(av, shallowtrans(M));
2305 }
2306 
2307 void
pari_close_mf(void)2308 pari_close_mf(void)
2309 {
2310   cache_delete(cache_FACT);
2311   cache_delete(cache_DIV);
2312   cache_delete(cache_H);
2313   cache_delete(cache_D);
2314   cache_delete(cache_DIH);
2315 }
2316 
2317 /*************************************************************************/
2318 /* a odd, update local cache (recycle memory) */
2319 static GEN
update_factor_cache(long a,long lim,long * pb)2320 update_factor_cache(long a, long lim, long *pb)
2321 {
2322   const long step = 16000; /* even; don't increase this: RAM cache thrashing */
2323   if (a + 2*step > lim)
2324     *pb = lim; /* fuse last 2 chunks */
2325   else
2326     *pb = a + step;
2327   return vecfactoroddu_i(a, *pb);
2328 }
2329 /* assume lim < MAX_LONG/8 */
2330 static void
constcoredisc(long lim)2331 constcoredisc(long lim)
2332 {
2333   pari_sp av2, av = avma;
2334   GEN D = caches[cache_D].cache, CACHE = NULL;
2335   long cachea, cacheb, N, LIM = !D ? 4 : lg(D)-1;
2336   if (lim <= 0) lim = 5;
2337   if (lim <= LIM) return;
2338   cache_reset(cache_D);
2339   D = zero_zv(lim);
2340   av2 = avma;
2341   cachea = cacheb = 0;
2342   for (N = 1; N <= lim; N+=2)
2343   { /* N odd */
2344     long i, d, d2;
2345     GEN F;
2346     if (N > cacheb)
2347     {
2348       set_avma(av2); cachea = N;
2349       CACHE = update_factor_cache(N, lim, &cacheb);
2350     }
2351     F = gel(CACHE, ((N-cachea)>>1)+1); /* factoru(N) */
2352     D[N] = d = corediscs_fact(F); /* = 3 mod 4 or 4 mod 16 */
2353     d2 = odd(d)? d<<3: d<<1;
2354     for (i = 1;;)
2355     {
2356       if ((N << i) > lim) break;
2357       D[N<<i] = d2; i++;
2358       if ((N << i) > lim) break;
2359       D[N<<i] = d; i++;
2360     }
2361   }
2362   cache_set(cache_D, D);
2363   set_avma(av);
2364 }
2365 
2366 static void
constfact(long lim)2367 constfact(long lim)
2368 {
2369   pari_sp av;
2370   GEN VFACT = caches[cache_FACT].cache;
2371   long LIM = VFACT? lg(VFACT)-1: 4;
2372   if (lim <= 0) lim = 5;
2373   if (lim <= LIM) return;
2374   cache_reset(cache_FACT); av = avma;
2375   cache_set(cache_FACT, vecfactoru_i(1,lim)); set_avma(av);
2376 }
2377 static void
constdiv(long lim)2378 constdiv(long lim)
2379 {
2380   pari_sp av;
2381   GEN VFACT, VDIV = caches[cache_DIV].cache;
2382   long N, LIM = VDIV? lg(VDIV)-1: 4;
2383   if (lim <= 0) lim = 5;
2384   if (lim <= LIM) return;
2385   constfact(lim);
2386   VFACT = caches[cache_FACT].cache;
2387   cache_reset(cache_DIV); av = avma;
2388   VDIV  = cgetg(lim+1, t_VEC);
2389   for (N = 1; N <= lim; N++) gel(VDIV,N) = divisorsu_fact(gel(VFACT,N));
2390   cache_set(cache_DIV, VDIV); set_avma(av);
2391 }
2392 
2393 /* n > 1, D = divisors(n); sets L = 2*lambda(n), S = sigma(n) */
2394 static void
lamsig(GEN D,long * pL,long * pS)2395 lamsig(GEN D, long *pL, long *pS)
2396 {
2397   pari_sp av = avma;
2398   long i, l = lg(D), L = 1, S = D[l-1]+1;
2399   for (i = 2; i < l; i++) /* skip d = 1 */
2400   {
2401     long d = D[i], nd = D[l-i]; /* nd = n/d */
2402     if (d < nd) { L += d; S += d + nd; }
2403     else
2404     {
2405       L <<= 1; if (d == nd) { L += d; S += d; }
2406       break;
2407     }
2408   }
2409   set_avma(av); *pL = L; *pS = S;
2410 }
2411 /* table of 6 * Hurwitz class numbers D <= lim */
2412 static void
consttabh(long lim)2413 consttabh(long lim)
2414 {
2415   pari_sp av = avma, av2;
2416   GEN VHDH0, VDIV, CACHE = NULL;
2417   GEN VHDH = caches[cache_H].cache;
2418   long r, N, cachea, cacheb, lim0 = VHDH? lg(VHDH)-1: 2, LIM = lim0 << 1;
2419 
2420   if (lim <= 0) lim = 5;
2421   if (lim <= LIM) return;
2422   cache_reset(cache_H);
2423   r = lim&3L; if (r) lim += 4-r;
2424   cache_get(cache_DIV, lim);
2425   VDIV = caches[cache_DIV].cache;
2426   VHDH0 = cgetg(lim/2 + 1, t_VECSMALL);
2427   VHDH0[1] = 2;
2428   VHDH0[2] = 3;
2429   for (N = 3; N <= lim0; N++) VHDH0[N] = VHDH[N];
2430   av2 = avma;
2431   cachea = cacheb = 0;
2432   for (N = LIM + 3; N <= lim; N += 4)
2433   {
2434     long s = 0, limt = usqrt(N>>2), flsq = 0, ind, t, L, S;
2435     GEN DN, DN2;
2436     if (N + 2 >= lg(VDIV))
2437     { /* use local cache */
2438       GEN F;
2439       if (N + 2 > cacheb)
2440       {
2441         set_avma(av2); cachea = N;
2442         CACHE = update_factor_cache(N, lim+2, &cacheb);
2443       }
2444       F = gel(CACHE, ((N-cachea)>>1)+1); /* factoru(N) */
2445       DN = divisorsu_fact(F);
2446       F = gel(CACHE, ((N-cachea)>>1)+2); /* factoru(N+2) */
2447       DN2 = divisorsu_fact(F);
2448     }
2449     else
2450     { /* use global cache */
2451       DN = gel(VDIV,N);
2452       DN2 = gel(VDIV,N+2);
2453     }
2454     ind = N >> 1;
2455     for (t = 1; t <= limt; t++)
2456     {
2457       ind -= (t<<2)-2; /* N/2 - 2t^2 */
2458       if (ind) s += VHDH0[ind]; else flsq = 1;
2459     }
2460     lamsig(DN, &L,&S);
2461     VHDH0[N >> 1] = 2*S - 3*L - 2*s + flsq;
2462     s = 0; flsq = 0; limt = (usqrt(N+2) - 1) >> 1;
2463     ind = (N+1) >> 1;
2464     for (t = 1; t <= limt; t++)
2465     {
2466       ind -= t<<2; /* (N+1)/2 - 2t(t+1) */
2467       if (ind) s += VHDH0[ind]; else flsq = 1;
2468     }
2469     lamsig(DN2, &L,&S);
2470     VHDH0[(N+1) >> 1] = S - 3*(L >> 1) - s - flsq;
2471   }
2472   cache_set(cache_H, VHDH0); set_avma(av);
2473 }
2474 
2475 /*************************************************************************/
2476 /* Core functions using factorizations, divisors of class numbers caches */
2477 /* TODO: myfactoru and factorization cache should be exported */
2478 static GEN
myfactoru(long N)2479 myfactoru(long N)
2480 {
2481   GEN z = cache_get(cache_FACT, N);
2482   return z? gcopy(z): factoru(N);
2483 }
2484 static GEN
mydivisorsu(long N)2485 mydivisorsu(long N)
2486 {
2487   GEN z = cache_get(cache_DIV, N);
2488   return z? leafcopy(z): divisorsu(N);
2489 }
2490 /* write -n = Df^2, D < 0 fundamental discriminant. Return D, set f. */
2491 static long
mycoredisc2neg(ulong n,long * pf)2492 mycoredisc2neg(ulong n, long *pf)
2493 {
2494   ulong m, D = (ulong)cache_get(cache_D, n);
2495   if (D) { *pf = usqrt(n/D); return -(long)D; }
2496   m = mycore(n, pf);
2497   if ((m&3) != 3) { m <<= 2; *pf >>= 1; }
2498   return (long)-m;
2499 }
2500 /* write n = Df^2, D > 0 fundamental discriminant. Return D, set f. */
2501 static long
mycoredisc2pos(ulong n,long * pf)2502 mycoredisc2pos(ulong n, long *pf)
2503 {
2504   ulong m = mycore(n, pf);
2505   if ((m&3) != 1) { m <<= 2; *pf >>= 1; }
2506   return (long)m;
2507 }
2508 
2509 /* 1+p+...+p^e, e >= 1 */
2510 static ulong
usumpow(ulong p,long e)2511 usumpow(ulong p, long e)
2512 {
2513   ulong q = 1+p;
2514   long i;
2515   for (i = 1; i < e; i++) q = p*q + 1;
2516   return q;
2517 }
2518 /* Hurwitz(D0 F^2)/ Hurwitz(D0)
2519  * = \sum_{f|F}  f \prod_{p|f} (1-kro(D0/p)/p)
2520  * = \prod_{p^e || F} (1 + (p^e-1) / (p-1) * (p-kro(D0/p))) */
2521 static long
get_sh(long F,long D0)2522 get_sh(long F, long D0)
2523 {
2524   GEN fa = myfactoru(F), P = gel(fa,1), E = gel(fa,2);
2525   long i, l = lg(P), t = 1;
2526   for (i = 1; i < l; i++)
2527   {
2528     long p = P[i], e = E[i], s = kross(D0,p);
2529     if (e == 1) { t *= 1 + p - s; continue; }
2530     if (s == 1) { t *= upowuu(p,e); continue; }
2531     t *= 1 + usumpow(p,e-1)*(p-s);
2532   }
2533   return t;
2534 }
2535 /* d > 0, d = 0,3 (mod 4). Return 6*hclassno(d); -d must be fundamental
2536  * Faster than quadclassunit up to 5*10^5 or so */
2537 static ulong
hclassno6u_count(ulong d)2538 hclassno6u_count(ulong d)
2539 {
2540   ulong a, b, b2, h = 0;
2541   int f = 0;
2542 
2543   if (d > 500000)
2544     return 6 * itou(gel(quadclassunit0(utoineg(d), 0, NULL, 0), 1));
2545 
2546   /* this part would work with -d non fundamental */
2547   b = d&1; b2 = (1+d)>>2;
2548   if (!b)
2549   {
2550     for (a=1; a*a<b2; a++)
2551       if (b2%a == 0) h++;
2552     f = (a*a==b2); b=2; b2=(4+d)>>2;
2553   }
2554   while (b2*3 < d)
2555   {
2556     if (b2%b == 0) h++;
2557     for (a=b+1; a*a < b2; a++)
2558       if (b2%a == 0) h += 2;
2559     if (a*a == b2) h++;
2560     b += 2; b2 = (b*b+d)>>2;
2561   }
2562   if (b2*3 == d) return 6*h+2;
2563   if (f) return 6*h+3;
2564   return 6*h;
2565 }
2566 /* D > 0; 6 * hclassno(D), using D = D0*F^2 */
2567 static long
hclassno6u_2(ulong D,long D0,long F)2568 hclassno6u_2(ulong D, long D0, long F)
2569 {
2570   long h;
2571   if (F == 1) h = hclassno6u_count(D);
2572   else
2573   { /* second chance */
2574     h = (ulong)cache_get(cache_H, -D0);
2575     if (!h) h = hclassno6u_count(-D0);
2576     h *= get_sh(F,D0);
2577   }
2578   return h;
2579 }
2580 /* D > 0; 6 * hclassno(D) (6*Hurwitz). Beware, cached value for D (=0,3 mod 4)
2581  * is stored at D>>1 */
2582 ulong
hclassno6u(ulong D)2583 hclassno6u(ulong D)
2584 {
2585   ulong z = (ulong)cache_get(cache_H, D);
2586   long D0, F;
2587   if (z) return z;
2588   D0 = mycoredisc2neg(D, &F);
2589   return hclassno6u_2(D,D0,F);
2590 }
2591 /* same, where the decomposition D = D0*F^2 is already known */
2592 static ulong
hclassno6u_i(ulong D,long D0,long F)2593 hclassno6u_i(ulong D, long D0, long F)
2594 {
2595   ulong z = (ulong)cache_get(cache_H, D);
2596   if (z) return z;
2597   return hclassno6u_2(D,D0,F);
2598 }
2599 
2600 #if 0
2601 /* D > 0, return h(-D) [ordinary class number].
2602  * Assume consttabh(D or more) was previously called */
2603 static long
2604 hfromH(long D)
2605 {
2606   pari_sp ltop = avma;
2607   GEN m, d, fa = myfactoru(D), P = gel(fa,1), E = gel(fa,2);
2608   GEN VH = caches[cache_H].cache;
2609   long i, nd, S, l = lg(P);
2610 
2611   /* n = d[i] loops through squarefree divisors of f, where f^2 = largest square
2612    * divisor of N = |D|; m[i] = moebius(n) */
2613   nd = 1 << (l-1);
2614   d = cgetg(nd+1, t_VECSMALL);
2615   m = cgetg(nd+1, t_VECSMALL);
2616   d[1] = 1; S = VH[D >> 1]; /* 6 hclassno(-D) */
2617   m[1] = 1; nd = 1;
2618   i = 1;
2619   if (P[1] == 2 && E[1] <= 3) /* need D/n^2 to be a discriminant */
2620   { if (odd(E[1]) || (E[1] == 2 && (D & 15) == 4)) i = 2; }
2621   for (; i<l; i++)
2622   {
2623     long j, p = P[i];
2624     if (E[i] == 1) continue;
2625     for (j=1; j<=nd; j++)
2626     {
2627       long n, s, hn;
2628       d[nd+j] = n = d[j] * p;
2629       m[nd+j] = s = - m[j]; /* moebius(n) */
2630       hn = VH[(D/(n*n)) >> 1]; /* 6 hclassno(-D/n^2) */
2631       if (s > 0) S += hn; else S -= hn;
2632     }
2633     nd <<= 1;
2634   }
2635   return gc_long(ltop, S/6);
2636 }
2637 #endif
2638 /* D < -4 fundamental, h(D), ordinary class number */
2639 static long
myh(long D)2640 myh(long D)
2641 {
2642   ulong z = (ulong)cache_get(cache_H, -D);
2643   if (z) return z/6; /* should be hfromH(-D) if D nonfundamental */
2644   return itou(quadclassno(stoi(D)));
2645 }
2646 
2647 /*************************************************************************/
2648 /*                          TRACE FORMULAS                               */
2649 /* CHIP primitive, initialize for t_POLMOD output */
2650 static GEN
mfcharinit(GEN CHIP)2651 mfcharinit(GEN CHIP)
2652 {
2653   long n, o, l, vt, N = mfcharmodulus(CHIP);
2654   GEN c, v, V, G, Pn;
2655   if (N == 1) return mkvec2(mkvec(gen_1), pol_x(0));
2656   G = gel(CHIP,1);
2657   v = ncharvecexpo(G, znconrey_normalized(G, gel(CHIP,2)));
2658   l = lg(v); V = cgetg(l, t_VEC);
2659   o = mfcharorder(CHIP);
2660   Pn = mfcharpol(CHIP); vt = varn(Pn);
2661   if (o <= 2)
2662   {
2663     for (n = 1; n < l; n++)
2664     {
2665       if (v[n] < 0) c = gen_0; else c = v[n]? gen_m1: gen_1;
2666       gel(V,n) = c;
2667     }
2668   }
2669   else
2670   {
2671     for (n = 1; n < l; n++)
2672     {
2673       if (v[n] < 0) c = gen_0;
2674       else
2675       {
2676         c = Qab_zeta(v[n], o, vt);
2677         if (typ(c) == t_POL && lg(c) >= lg(Pn)) c = RgX_rem(c, Pn);
2678       }
2679       gel(V,n) = c;
2680     }
2681   }
2682   return mkvec2(V, Pn);
2683 }
2684 static GEN
vchip_lift(GEN VCHI,long x,GEN C)2685 vchip_lift(GEN VCHI, long x, GEN C)
2686 {
2687   GEN V = gel(VCHI,1);
2688   long F = lg(V)-1;
2689   if (F == 1) return C;
2690   x %= F;
2691   if (!x) return C;
2692   if (x <= 0) x += F;
2693   return gmul(C, gel(V, x));
2694 }
2695 static long
vchip_FC(GEN VCHI)2696 vchip_FC(GEN VCHI) { return lg(gel(VCHI,1))-1; }
2697 static GEN
vchip_mod(GEN VCHI,GEN S)2698 vchip_mod(GEN VCHI, GEN S)
2699 { return (typ(S) == t_POL)? RgX_rem(S, gel(VCHI,2)): S; }
2700 static GEN
vchip_polmod(GEN VCHI,GEN S)2701 vchip_polmod(GEN VCHI, GEN S)
2702 { return (typ(S) == t_POL)? mkpolmod(S, gel(VCHI,2)): S; }
2703 
2704 /* ceil(m/d) */
2705 static long
ceildiv(long m,long d)2706 ceildiv(long m, long d)
2707 {
2708   long q;
2709   if (!m) return 0;
2710   q = m/d; return m%d? q+1: q;
2711 }
2712 
2713 /* contribution of scalar matrices in dimension formula */
2714 static GEN
A1(long N,long k)2715 A1(long N, long k)
2716 { return sstoQ(mypsiu(N)*(k-1), 12); }
2717 static long
ceilA1(long N,long k)2718 ceilA1(long N, long k)
2719 { return ceildiv(mypsiu(N) * (k-1), 12); }
2720 
2721 /* sturm bound, slightly larger than dimension */
2722 long
mfsturmNk(long N,long k)2723 mfsturmNk(long N, long k) { return (mypsiu(N) * k) / 12; }
2724 long
mfsturmNgk(long N,GEN k)2725 mfsturmNgk(long N, GEN k)
2726 {
2727   long n,d; Qtoss(k,&n,&d);
2728   return 1 + (mypsiu(N)*n)/(d == 1? 12: 24);
2729 }
2730 static long
mfsturmmf(GEN F)2731 mfsturmmf(GEN F) { return mfsturmNgk(mf_get_N(F), mf_get_gk(F)); }
2732 
2733 /* List of all solutions of x^2 + x + 1 = 0 modulo N, x modulo N */
2734 static GEN
sqrtm3modN(long N)2735 sqrtm3modN(long N)
2736 {
2737   pari_sp av;
2738   GEN fa, P, E, B, mB, A, Q, T, R, v, gen_m3;
2739   long l, i, n, ct, fl3 = 0, Ninit;
2740   if (!odd(N) || (N%9) == 0) return cgetg(1,t_VECSMALL);
2741   Ninit = N;
2742   if ((N%3) == 0) { N /= 3; fl3 = 1; }
2743   fa = myfactoru(N); P = gel(fa, 1); E = gel(fa, 2);
2744   l = lg(P);
2745   for (i = 1; i < l; i++)
2746     if ((P[i]%3) == 2) return cgetg(1,t_VECSMALL);
2747   A = cgetg(l, t_VECSMALL);
2748   B = cgetg(l, t_VECSMALL);
2749   mB= cgetg(l, t_VECSMALL);
2750   Q = cgetg(l, t_VECSMALL); gen_m3 = utoineg(3);
2751   for (i = 1; i < l; i++)
2752   {
2753     long p = P[i], e = E[i];
2754     Q[i] = upowuu(p,e);
2755     B[i] = itou( Zp_sqrt(gen_m3, utoipos(p), e) );
2756     mB[i]= Q[i] - B[i];
2757   }
2758   ct = 1 << (l-1);
2759   T = ZV_producttree(Q);
2760   R = ZV_chinesetree(Q,T);
2761   v = cgetg(ct+1, t_VECSMALL);
2762   av = avma;
2763   for (n = 1; n <= ct; n++)
2764   {
2765     long m = n-1, r;
2766     for (i = 1; i < l; i++)
2767     {
2768       A[i] = (m&1L)? mB[i]: B[i];
2769       m >>= 1;
2770     }
2771     r = itou( ZV_chinese_tree(A, Q, T, R) );
2772     if (fl3) while (r%3) r += N;
2773     set_avma(av); v[n] = odd(r) ? (r-1) >> 1 : (r+Ninit-1) >> 1;
2774   }
2775   return v;
2776 }
2777 
2778 /* number of elliptic points of order 3 in X0(N) */
2779 static long
nu3(long N)2780 nu3(long N)
2781 {
2782   long i, l;
2783   GEN P;
2784   if (!odd(N) || (N%9) == 0) return 0;
2785   if ((N%3) == 0) N /= 3;
2786   P = gel(myfactoru(N), 1); l = lg(P);
2787   for (i = 1; i < l; i++) if ((P[i]%3) == 2) return 0;
2788   return 1L<<(l-1);
2789 }
2790 /* number of elliptic points of order 2 in X0(N) */
2791 static long
nu2(long N)2792 nu2(long N)
2793 {
2794   long i, l;
2795   GEN P;
2796   if ((N&3L) == 0) return 0;
2797   if (!odd(N)) N >>= 1;
2798   P = gel(myfactoru(N), 1); l = lg(P);
2799   for (i = 1; i < l; i++) if ((P[i]&3L) == 3) return 0;
2800   return 1L<<(l-1);
2801 }
2802 
2803 /* contribution of elliptic matrices of order 3 in dimension formula
2804  * Only depends on CHIP the primitive char attached to CHI */
2805 static GEN
A21(long N,long k,GEN CHI)2806 A21(long N, long k, GEN CHI)
2807 {
2808   GEN res, G, chi, o;
2809   long a21, i, limx, S;
2810   if ((N&1L) == 0) return gen_0;
2811   a21 = k%3 - 1;
2812   if (!a21) return gen_0;
2813   if (N <= 3) return sstoQ(a21, 3);
2814   if (!CHI) return sstoQ(nu3(N) * a21, 3);
2815   res = sqrtm3modN(N); limx = (N - 1) >> 1;
2816   G = gel(CHI,1); chi = gel(CHI,2);
2817   o = gmfcharorder(CHI);
2818   for (S = 0, i = 1; i < lg(res); i++)
2819   { /* (x,N) = 1; S += chi(x) + chi(x^2) */
2820     long x = res[i];
2821     if (x <= limx)
2822     { /* CHI(x)=e(c/o), 3rd-root of 1 */
2823       GEN c = znchareval(G, chi, utoi(x), o);
2824       if (!signe(c)) S += 2; else S--;
2825     }
2826   }
2827   return sstoQ(a21 * S, 3);
2828 }
2829 
2830 /* List of all square roots of -1 modulo N */
2831 static GEN
sqrtm1modN(long N)2832 sqrtm1modN(long N)
2833 {
2834   pari_sp av;
2835   GEN fa, P, E, B, mB, A, Q, T, R, v;
2836   long l, i, n, ct, fleven = 0;
2837   if ((N&3L) == 0) return cgetg(1,t_VECSMALL);
2838   if ((N&1L) == 0) { N >>= 1; fleven = 1; }
2839   fa = myfactoru(N); P = gel(fa,1); E = gel(fa,2);
2840   l = lg(P);
2841   for (i = 1; i < l; i++)
2842     if ((P[i]&3L) == 3) return cgetg(1,t_VECSMALL);
2843   A = cgetg(l, t_VECSMALL);
2844   B = cgetg(l, t_VECSMALL);
2845   mB= cgetg(l, t_VECSMALL);
2846   Q = cgetg(l, t_VECSMALL);
2847   for (i = 1; i < l; i++)
2848   {
2849     long p = P[i], e = E[i];
2850     Q[i] = upowuu(p,e);
2851     B[i] = itou( Zp_sqrt(gen_m1, utoipos(p), e) );
2852     mB[i]= Q[i] - B[i];
2853   }
2854   ct = 1 << (l-1);
2855   T = ZV_producttree(Q);
2856   R = ZV_chinesetree(Q,T);
2857   v = cgetg(ct+1, t_VECSMALL);
2858   av = avma;
2859   for (n = 1; n <= ct; n++)
2860   {
2861     long m = n-1, r;
2862     for (i = 1; i < l; i++)
2863     {
2864       A[i] = (m&1L)? mB[i]: B[i];
2865       m >>= 1;
2866     }
2867     r = itou( ZV_chinese_tree(A, Q, T, R) );
2868     if (fleven && !odd(r)) r += N;
2869     set_avma(av); v[n] = r;
2870   }
2871   return v;
2872 }
2873 
2874 /* contribution of elliptic matrices of order 4 in dimension formula.
2875  * Only depends on CHIP the primitive char attached to CHI */
2876 static GEN
A22(long N,long k,GEN CHI)2877 A22(long N, long k, GEN CHI)
2878 {
2879   GEN G, chi, o, res;
2880   long S, a22, i, limx, o2;
2881   if ((N&3L) == 0) return gen_0;
2882   a22 = (k & 3L) - 1; /* (k % 4) - 1 */
2883   if (!a22) return gen_0;
2884   if (N <= 2) return sstoQ(a22, 4);
2885   if (!CHI) return sstoQ(nu2(N)*a22, 4);
2886   if (mfcharparity(CHI) == -1) return gen_0;
2887   res = sqrtm1modN(N); limx = (N - 1) >> 1;
2888   G = gel(CHI,1); chi = gel(CHI,2);
2889   o = gmfcharorder(CHI);
2890   o2 = itou(o)>>1;
2891   for (S = 0, i = 1; i < lg(res); i++)
2892   { /* (x,N) = 1, S += real(chi(x)) */
2893     long x = res[i];
2894     if (x <= limx)
2895     { /* CHI(x)=e(c/o), 4th-root of 1 */
2896       long c = itou( znchareval(G, chi, utoi(x), o) );
2897       if (!c) S++; else if (c == o2) S--;
2898     }
2899   }
2900   return sstoQ(a22 * S, 2);
2901 }
2902 
2903 /* sumdiv(N,d,eulerphi(gcd(d,N/d))) */
2904 static long
nuinf(long N)2905 nuinf(long N)
2906 {
2907   GEN fa = myfactoru(N), P = gel(fa,1), E = gel(fa,2);
2908   long i, t = 1, l = lg(P);
2909   for (i=1; i<l; i++)
2910   {
2911     long p = P[i], e = E[i];
2912     if (odd(e))
2913       t *= upowuu(p,e>>1) << 1;
2914     else
2915       t *= upowuu(p,(e>>1)-1) * (p+1);
2916   }
2917   return t;
2918 }
2919 
2920 /* contribution of hyperbolic matrices in dimension formula */
2921 static GEN
A3(long N,long FC)2922 A3(long N, long FC)
2923 {
2924   long i, S, NF, l;
2925   GEN D;
2926   if (FC == 1) return sstoQ(nuinf(N),2);
2927   D = mydivisorsu(N); l = lg(D);
2928   S = 0; NF = N/FC;
2929   for (i = 1; i < l; i++)
2930   {
2931     long g = ugcd(D[i], D[l-i]);
2932     if (NF%g == 0) S += myeulerphiu(g);
2933   }
2934   return sstoQ(S, 2);
2935 }
2936 
2937 /* special contribution in weight 2 in dimension formula */
2938 static long
A4(long k,long FC)2939 A4(long k, long FC)
2940 { return (k==2 && FC==1)? 1: 0; }
2941 /* gcd(x,N) */
2942 static long
myugcd(GEN GCD,ulong x)2943 myugcd(GEN GCD, ulong x)
2944 {
2945   ulong N = lg(GCD)-1;
2946   if (x >= N) x %= N;
2947   return GCD[x+1];
2948 }
2949 /* 1_{gcd(x,N) = 1} * chi(x), return NULL if 0 */
2950 static GEN
mychicgcd(GEN GCD,GEN VCHI,long x)2951 mychicgcd(GEN GCD, GEN VCHI, long x)
2952 {
2953   long N = lg(GCD)-1;
2954   if (N == 1) return gen_1;
2955   x = umodsu(x, N);
2956   if (GCD[x+1] != 1) return NULL;
2957   x %= vchip_FC(VCHI); if (!x) return gen_1;
2958   return gel(gel(VCHI,1), x);
2959 }
2960 
2961 /* contribution of scalar matrices to trace formula */
2962 static GEN
TA1(long N,long k,GEN VCHI,GEN GCD,long n)2963 TA1(long N, long k, GEN VCHI, GEN GCD, long n)
2964 {
2965   GEN S;
2966   ulong m;
2967   if (!uissquareall(n, &m)) return gen_0;
2968   if (m == 1) return A1(N,k); /* common */
2969   S = mychicgcd(GCD, VCHI, m);
2970   return S? gmul(gmul(powuu(m, k-2), A1(N,k)), S): gen_0;
2971 }
2972 
2973 /* All square roots modulo 4N, x modulo 2N, precomputed to accelerate TA2 */
2974 static GEN
mksqr(long N)2975 mksqr(long N)
2976 {
2977   pari_sp av = avma;
2978   long x, N2 = N << 1, N4 = N << 2;
2979   GEN v = const_vec(N2, cgetg(1, t_VECSMALL));
2980   gel(v, N2) = mkvecsmall(0); /* x = 0 */
2981   for (x = 1; x <= N; x++)
2982   {
2983     long r = (((x*x - 1)%N4) >> 1) + 1;
2984     gel(v,r) = vecsmall_append(gel(v,r), x);
2985   }
2986   return gerepilecopy(av, v);
2987 }
2988 
2989 static GEN
mkgcd(long N)2990 mkgcd(long N)
2991 {
2992   GEN GCD, d;
2993   long i, N2;
2994   if (N == 1) return mkvecsmall(N);
2995   GCD = cgetg(N + 1, t_VECSMALL);
2996   d = GCD+1; /* GCD[i+1] = d[i] = gcd(i,N) = gcd(N-i,N), i = 0..N-1 */
2997   d[0] = N; d[1] = d[N-1] = 1; N2 = N>>1;
2998   for (i = 2; i <= N2; i++) d[i] = d[N-i] = ugcd(N, i);
2999   return GCD;
3000 }
3001 
3002 /* Table of \sum_{x^2-tx+n=0 mod Ng}chi(x) for all g dividing gcd(N,F),
3003  * F^2 largest such that (t^2-4n)/F^2=0 or 1 mod 4; t >= 0 */
3004 static GEN
mutglistall(long t,long N,long NF,GEN VCHI,long n,GEN MUP,GEN li,GEN GCD)3005 mutglistall(long t, long N, long NF, GEN VCHI, long n, GEN MUP, GEN li, GEN GCD)
3006 {
3007   long i, lx = lg(li);
3008   GEN DNF = mydivisorsu(NF), v = zerovec(NF);
3009   long j, g, lDNF = lg(DNF);
3010   for (i = 1; i < lx; i++)
3011   {
3012     long x = (li[i] + t) >> 1, y, lD;
3013     GEN D, c = mychicgcd(GCD, VCHI, x);
3014     if (li[i] && li[i] != N)
3015     {
3016       GEN c2 = mychicgcd(GCD, VCHI, t - x);
3017       if (c2) c = c? gadd(c, c2): c2;
3018     }
3019     if (!c) continue;
3020     y = (x*(x - t) + n) / N; /* exact division */
3021     D = mydivisorsu(ugcd(labs(y), NF)); lD = lg(D);
3022     for (j=1; j < lD; j++) { g = D[j]; gel(v,g) = gadd(gel(v,g), c); }
3023   }
3024   /* j = 1 corresponds to g = 1, and MUP[1] = 1 */
3025   for (j=2; j < lDNF; j++) { g = DNF[j]; gel(v,g) = gmulsg(MUP[g], gel(v,g)); }
3026   return v;
3027 }
3028 
3029 /* special case (N,F) = 1: easier */
3030 static GEN
mutg1(long t,long N,GEN VCHI,GEN li,GEN GCD)3031 mutg1(long t, long N, GEN VCHI, GEN li, GEN GCD)
3032 { /* (N,F) = 1 */
3033   GEN S = NULL;
3034   long i, lx = lg(li);
3035   for (i = 1; i < lx; i++)
3036   {
3037     long x = (li[i] + t) >> 1;
3038     GEN c = mychicgcd(GCD, VCHI, x);
3039     if (c) S = S? gadd(S, c): c;
3040     if (li[i] && li[i] != N)
3041     {
3042       c = mychicgcd(GCD, VCHI, t - x);
3043       if (c) S = S? gadd(S, c): c;
3044     }
3045     if (S && !signe(S)) S = NULL; /* strive hard to add gen_0 */
3046   }
3047   return S; /* single value */
3048 }
3049 
3050 /* Gegenbauer pol; n > 2, P = \sum_{0<=j<=n/2} (-1)^j (n-j)!/j!(n-2*j)! X^j */
3051 static GEN
mfrhopol(long n)3052 mfrhopol(long n)
3053 {
3054 #ifdef LONG_IS_64BIT
3055   const long M = 2642249;
3056 #else
3057   const long M = 1629;
3058 #endif
3059   long j, d = n >> 1; /* >= 1 */
3060   GEN P = cgetg(d + 3, t_POL);
3061 
3062   if (n > M) pari_err_IMPL("mfrhopol for large weight"); /* avoid overflow */
3063   P[1] = evalvarn(0)|evalsigne(1);
3064   gel(P,2) = gen_1;
3065   gel(P,3) = utoineg(n-1); /* j = 1 */
3066   if (d > 1) gel(P,4) = utoipos(((n-3)*(n-2)) >> 1); /* j = 2 */
3067   if (d > 2) gel(P,5) = utoineg(((n-5)*(n-4)*(n-3)) / 6); /* j = 3 */
3068   for (j = 4; j <= d; j++)
3069     gel(P,j+2) = divis(mulis(gel(P,j+1), (n-2*j+1)*(n-2*j+2)), (n-j+1)*(-j));
3070   return P;
3071 }
3072 
3073 /* polrecip(Q)(t2), assume Q(0) = 1 */
3074 static GEN
ZXrecip_u_eval(GEN Q,ulong t2)3075 ZXrecip_u_eval(GEN Q, ulong t2)
3076 {
3077   GEN T = addiu(gel(Q,3), t2);
3078   long l = lg(Q), j;
3079   for (j = 4; j < l; j++) T = addii(gel(Q,j), mului(t2, T));
3080   return T;
3081 }
3082 /* return sh * sqrt(n)^nu * G_nu(t/(2*sqrt(n))) for t != 0
3083  * else (sh/2) * sqrt(n)^nu * G_nu(0) [ implies nu is even ]
3084  * G_nu(z) = \sum_{0<=j<=nu/2} (-1)^j (nu-j)!/j!(nu-2*j)! * (2z)^(nu-2*j)) */
3085 static GEN
mfrhopowsimp(GEN Q,GEN sh,long nu,long t,long t2,long n)3086 mfrhopowsimp(GEN Q, GEN sh, long nu, long t, long t2, long n)
3087 {
3088   GEN T;
3089   switch (nu)
3090   {
3091     case 0: return t? sh: gmul2n(sh,-1);
3092     case 1: return gmulsg(t, sh);
3093     case 2: return t? gmulsg(t2 - n, sh): gmul(gmul2n(stoi(-n), -1), sh);
3094     case 3: return gmul(mulss(t, t2 - 2*n), sh);
3095     default:
3096       if (!t) return gmul(gmul2n(gel(Q, lg(Q) - 1), -1), sh);
3097       T = ZXrecip_u_eval(Q, t2); if (odd(nu)) T = mulsi(t, T);
3098       return gmul(T, sh);
3099   }
3100 }
3101 
3102 /* contribution of elliptic matrices to trace formula */
3103 static GEN
TA2(long N,long k,GEN VCHI,long n,GEN SQRTS,GEN MUP,GEN GCD)3104 TA2(long N, long k, GEN VCHI, long n, GEN SQRTS, GEN MUP, GEN GCD)
3105 {
3106   const long n4 = n << 2, N4 = N << 2, nu = k - 2;
3107   const long st = (!odd(N) && odd(n)) ? 2 : 1;
3108   long limt, t;
3109   GEN S, Q;
3110 
3111   limt = usqrt(n4);
3112   if (limt*limt == n4) limt--;
3113   Q = nu > 3 ? ZX_z_unscale(mfrhopol(nu), n) : NULL;
3114   S = gen_0;
3115   for (t = odd(k)? st: 0; t <= limt; t += st) /* t^2 < 4n */
3116   {
3117     pari_sp av = avma;
3118     long t2 = t*t, D = n4 - t2, F, D0, NF;
3119     GEN sh, li;
3120 
3121     li = gel(SQRTS, (umodsu(-D - 1, N4) >> 1) + 1);
3122     if (lg(li) == 1) continue;
3123     D0 = mycoredisc2neg(D, &F);
3124     NF = myugcd(GCD, F);
3125     if (NF == 1)
3126     { /* (N,F) = 1 => single value in mutglistall */
3127       GEN mut = mutg1(t, N, VCHI, li, GCD);
3128       if (!mut) { set_avma(av); continue; }
3129       sh = gmul(sstoQ(hclassno6u_i(D,D0,F),6), mut);
3130     }
3131     else
3132     {
3133       GEN v = mutglistall(t, N, NF, VCHI, n, MUP, li, GCD);
3134       GEN DF = mydivisorsu(F);
3135       long i, lDF = lg(DF);
3136       sh = gen_0;
3137       for (i = 1; i < lDF; i++)
3138       {
3139         long Ff, f = DF[i], g = myugcd(GCD, f);
3140         GEN mut = gel(v, g);
3141         if (gequal0(mut)) continue;
3142         Ff = DF[lDF-i]; /* F/f */
3143         if (Ff == 1) sh = gadd(sh, mut);
3144         else
3145         {
3146           GEN P = gel(myfactoru(Ff), 1);
3147           long j, lP = lg(P);
3148           for (j = 1; j < lP; j++) { long p = P[j]; Ff -= kross(D0, p)*Ff/p; }
3149           sh = gadd(sh, gmulsg(Ff, mut));
3150         }
3151       }
3152       if (gequal0(sh)) { set_avma(av); continue; }
3153       if (D0 == -3) sh = gdivgs(sh, 3);
3154       else if (D0 == -4) sh = gdivgs(sh, 2);
3155       else sh = gmulgs(sh, myh(D0));
3156     }
3157     S = gerepileupto(av, gadd(S, mfrhopowsimp(Q,sh,nu,t,t2,n)));
3158   }
3159   return S;
3160 }
3161 
3162 /* compute global auxiliary data for TA3 */
3163 static GEN
mkbez(long N,long FC)3164 mkbez(long N, long FC)
3165 {
3166   long ct, i, NF = N/FC;
3167   GEN w, D = mydivisorsu(N);
3168   long l = lg(D);
3169 
3170   w = cgetg(l, t_VEC);
3171   for (i = ct = 1; i < l; i++)
3172   {
3173     long u, v, h, c = D[i], Nc = D[l-i];
3174     if (c > Nc) break;
3175     h = cbezout(c, Nc, &u, &v);
3176     if (h == 1) /* shortcut */
3177       gel(w, ct++) = mkvecsmall4(1,u*c,1,i);
3178     else if (!(NF%h))
3179       gel(w, ct++) = mkvecsmall4(h,u*(c/h),myeulerphiu(h),i);
3180   }
3181   setlg(w,ct); stackdummy((pari_sp)(w+ct),(pari_sp)(w+l));
3182   return w;
3183 }
3184 
3185 /* contribution of hyperbolic matrices to trace formula, d * nd = n,
3186  * DN = divisorsu(N) */
3187 static GEN
auxsum(GEN VCHI,GEN GCD,long d,long nd,GEN DN,GEN BEZ)3188 auxsum(GEN VCHI, GEN GCD, long d, long nd, GEN DN, GEN BEZ)
3189 {
3190   GEN S = gen_0;
3191   long ct, g = nd - d, lDN = lg(DN), lBEZ = lg(BEZ);
3192   for (ct = 1; ct < lBEZ; ct++)
3193   {
3194     GEN y, B = gel(BEZ, ct);
3195     long ic, c, Nc, uch, h = B[1];
3196     if (g%h) continue;
3197     uch = B[2];
3198     ic  = B[4];
3199     c = DN[ic];
3200     Nc= DN[lDN - ic]; /* Nc = N/c */
3201     if (ugcd(Nc, nd) == 1)
3202       y = mychicgcd(GCD, VCHI, d + uch*g); /* 0 if (c,d) > 1 */
3203     else
3204       y = NULL;
3205     if (c != Nc && ugcd(Nc, d) == 1)
3206     {
3207       GEN y2 = mychicgcd(GCD, VCHI, nd - uch*g); /* 0 if (c,nd) > 1 */
3208       if (y2) y = y? gadd(y, y2): y2;
3209     }
3210     if (y) S = gadd(S, gmulsg(B[3], y));
3211   }
3212   return S;
3213 }
3214 
3215 static GEN
TA3(long N,long k,GEN VCHI,GEN GCD,GEN Dn,GEN BEZ)3216 TA3(long N, long k, GEN VCHI, GEN GCD, GEN Dn, GEN BEZ)
3217 {
3218   GEN S = gen_0, DN = mydivisorsu(N);
3219   long i, l = lg(Dn);
3220   for (i = 1; i < l; i++)
3221   {
3222     long d = Dn[i], nd = Dn[l-i]; /* = n/d */
3223     GEN t, u;
3224     if (d > nd) break;
3225     t = auxsum(VCHI, GCD, d, nd, DN, BEZ);
3226     if (isintzero(t)) continue;
3227     u = powuu(d,k-1); if (d == nd) u = gmul2n(u,-1);
3228     S = gadd(S, gmul(u,t));
3229   }
3230   return S;
3231 }
3232 
3233 /* special contribution in weight 2 in trace formula */
3234 static long
TA4(long k,GEN VCHIP,GEN Dn,GEN GCD)3235 TA4(long k, GEN VCHIP, GEN Dn, GEN GCD)
3236 {
3237   long i, l, S;
3238   if (k != 2 || vchip_FC(VCHIP) != 1) return 0;
3239   l = lg(Dn); S = 0;
3240   for (i = 1; i < l; i++)
3241   {
3242     long d = Dn[i]; /* gcd(N,n/d) == 1? */
3243     if (myugcd(GCD, Dn[l-i]) == 1) S += d;
3244   }
3245   return S;
3246 }
3247 
3248 /* precomputation of products occurring im mutg, again to accelerate TA2 */
3249 static GEN
mkmup(long N)3250 mkmup(long N)
3251 {
3252   GEN fa = myfactoru(N), P = gel(fa,1), D = divisorsu_fact(fa);
3253   long i, lP = lg(P), lD = lg(D);
3254   GEN MUP = zero_zv(N);
3255   MUP[1] = 1;
3256   for (i = 2; i < lD; i++)
3257   {
3258     long j, g = D[i], Ng = D[lD-i]; /*  N/g */
3259     for (j = 1; j < lP; j++) { long p = P[j]; if (Ng%p) g += g/p; }
3260     MUP[D[i]] = g;
3261   }
3262   return MUP;
3263 }
3264 
3265 /* quadratic nonresidues mod p; p odd prime, p^2 fits in a long */
3266 static GEN
non_residues(long p)3267 non_residues(long p)
3268 {
3269   long i, j, p2 = p >> 1;
3270   GEN v = cgetg(p2+1, t_VECSMALL), w = const_vecsmall(p-1, 1);
3271   for (i = 2; i <= p2; i++) w[(i*i) % p] = 0; /* no need to check 1 */
3272   for (i = 2, j = 1; i < p; i++) if (w[i]) v[j++] = i;
3273   return v;
3274 }
3275 
3276 /* CHIP primitive. Return t_VECSMALL v of length q such that
3277  * Tr^new_{N,CHIP}(n) = 0 whenever v[(n%q) + 1] is nonzero */
3278 static GEN
mfnewzerodata(long N,GEN CHIP)3279 mfnewzerodata(long N, GEN CHIP)
3280 {
3281   GEN V, M, L, faN = myfactoru(N), PN = gel(faN,1), EN = gel(faN,2);
3282   GEN G = gel(CHIP,1), chi = gel(CHIP,2);
3283   GEN fa = znstar_get_faN(G), P = ZV_to_zv(gel(fa,1)), E = gel(fa,2);
3284   long i, mod, j = 1, l = lg(PN);
3285 
3286   M = cgetg(l, t_VECSMALL); M[1] = 0;
3287   V = cgetg(l, t_VEC);
3288   /* Tr^new(n) = 0 if (n mod M[i]) in V[i]  */
3289   if ((N & 3) == 0)
3290   {
3291     long e = EN[1];
3292     long c = (lg(P) > 1 && P[1] == 2)? E[1]: 0; /* c = v_2(FC) */
3293     /* e >= 2 */
3294     if (c == e-1) return NULL; /* Tr^new = 0 */
3295     if (c == e)
3296     {
3297       if (e == 2)
3298       { /* sc: -4 */
3299         gel(V,1) = mkvecsmall(3);
3300         M[1] = 4;
3301       }
3302       else if (e == 3)
3303       { /* sc: -8 (CHI_2(-1)=-1<=>chi[1]=1) and 8 (CHI_2(-1)=1 <=> chi[1]=0) */
3304         long t = signe(gel(chi,1))? 7: 3;
3305         gel(V,1) = mkvecsmall2(5, t);
3306         M[1] = 8;
3307       }
3308     }
3309     else if (e == 5 && c == 3)
3310     { /* sc: -8 (CHI_2(-1)=-1<=>chi[1]=1) and 8 (CHI_2(-1)=1 <=> chi[1]=0) */
3311       long t = signe(gel(chi,1))? 7: 3;
3312       gel(V,1) = mkvecsmalln(6, 2L,4L,5L,6L,8L,t);
3313       M[1] = 8;
3314     }
3315     else if ((e == 4 && c == 2) || (e == 5 && c <= 2) || (e == 6 && c <= 2)
3316          || (e >= 7 && c == e - 3))
3317     { /* sc: 4 */
3318       gel(V,1) = mkvecsmall3(0,2,3);
3319       M[1] = 4;
3320     }
3321     else if ((e <= 4 && c == 0) || (e >= 5 && c == e - 2))
3322     { /* sc: 2 */
3323       gel(V,1) = mkvecsmall(0);
3324       M[1] = 2;
3325     }
3326     else if ((e == 6 && c == 3) || (e >= 7 && c <= e - 4))
3327     { /* sc: -2 */
3328       gel(V,1) = mkvecsmalln(7, 0L,2L,3L,4L,5L,6L,7L);
3329       M[1] = 8;
3330     }
3331   }
3332   j = M[1]? 2: 1;
3333   for (i = odd(N)? 1: 2; i < l; i++) /* skip p=2, done above */
3334   {
3335     long p = PN[i], e = EN[i];
3336     long z = zv_search(P, p), c = z? E[z]: 0; /* c = v_p(FC) */
3337     if ((e <= 2 && c == 1 && itos(gel(chi,z)) == (p>>1)) /* ord(CHI_p)=2 */
3338         || (e >= 3 && c <= e - 2))
3339     { /* sc: -p */
3340       GEN v = non_residues(p);
3341       if (e != 1) v = vecsmall_prepend(v, 0);
3342       gel(V,j) = v;
3343       M[j] = p; j++;
3344     }
3345     else if (e >= 2 && c < e)
3346     { /* sc: p */
3347       gel(V,j) = mkvecsmall(0);
3348       M[j] = p; j++;
3349     }
3350   }
3351   if (j == 1) return cgetg(1, t_VECSMALL);
3352   setlg(V,j); setlg(M,j); mod = zv_prod(M);
3353   L = zero_zv(mod);
3354   for (i = 1; i < j; i++)
3355   {
3356     GEN v = gel(V,i);
3357     long s, m = M[i], lv = lg(v);
3358     for (s = 1; s < lv; s++)
3359     {
3360       long a = v[s] + 1;
3361       do { L[a] = 1; a += m; } while (a <= mod);
3362     }
3363   }
3364   return L;
3365 }
3366 /* v=mfnewzerodata(N,CHI); returns TRUE if newtrace(n) must be zero,
3367  * (but newtrace(n) may still be zero if we return FALSE) */
3368 static long
mfnewchkzero(GEN v,long n)3369 mfnewchkzero(GEN v, long n) { long q = lg(v)-1; return q && v[(n%q) + 1]; }
3370 
3371 /* if (!VCHIP): from mftraceform_cusp;
3372  * else from initnewtrace and CHI is known to be primitive */
3373 static GEN
inittrace(long N,GEN CHI,GEN VCHIP)3374 inittrace(long N, GEN CHI, GEN VCHIP)
3375 {
3376   long FC;
3377   if (VCHIP)
3378     FC = mfcharmodulus(CHI);
3379   else
3380     VCHIP = mfcharinit(mfchartoprimitive(CHI, &FC));
3381   return mkvecn(5, mksqr(N), mkmup(N), mkgcd(N), VCHIP, mkbez(N, FC));
3382 }
3383 
3384 /* p > 2 prime; return a sorted t_VECSMALL of primes s.t Tr^new(p) = 0 for all
3385  * weights > 2 */
3386 static GEN
inittrconj(long N,long FC)3387 inittrconj(long N, long FC)
3388 {
3389   GEN fa, P, E, v;
3390   long i, k, l;
3391 
3392   if (FC != 1) return cgetg(1,t_VECSMALL);
3393 
3394   fa = myfactoru(N >> vals(N));
3395   P = gel(fa,1); l = lg(P);
3396   E = gel(fa,2);
3397   v = cgetg(l, t_VECSMALL);
3398   for (i = k = 1; i < l; i++)
3399   {
3400     long j, p = P[i]; /* > 2 */
3401     for (j = 1; j < l; j++)
3402       if (j != i && E[j] == 1 && kross(-p, P[j]) == 1) v[k++] = p;
3403   }
3404   setlg(v,k); return v;
3405 }
3406 
3407 /* assume CHIP primitive, f(CHIP) | N; NZ = mfnewzerodata(N,CHIP) */
3408 static GEN
initnewtrace_i(long N,GEN CHIP,GEN NZ)3409 initnewtrace_i(long N, GEN CHIP, GEN NZ)
3410 {
3411   GEN T = const_vec(N, cgetg(1,t_VEC)), D, VCHIP;
3412   long FC = mfcharmodulus(CHIP), N1, N2, i, l;
3413 
3414   if (!NZ) NZ = mkvecsmall(1); /*Tr^new = 0; initialize data nevertheless*/
3415   VCHIP = mfcharinit(CHIP);
3416   N1 = N/FC; newd_params(N1, &N2);
3417   D = mydivisorsu(N1/N2); l = lg(D);
3418   N2 *= FC;
3419   for (i = 1; i < l; i++)
3420   {
3421     long M = D[i]*N2;
3422     gel(T,M) = inittrace(M, CHIP, VCHIP);
3423   }
3424   gel(T,N) = shallowconcat(gel(T,N), mkvec2(NZ, inittrconj(N,FC)));
3425   return T;
3426 }
3427 /* don't initialize if Tr^new = 0, return NULL */
3428 static GEN
initnewtrace(long N,GEN CHI)3429 initnewtrace(long N, GEN CHI)
3430 {
3431   GEN CHIP = mfchartoprimitive(CHI, NULL), NZ = mfnewzerodata(N,CHIP);
3432   return NZ? initnewtrace_i(N, CHIP, NZ): NULL;
3433 }
3434 
3435 /* (-1)^k */
3436 static long
m1pk(long k)3437 m1pk(long k) { return odd(k)? -1 : 1; }
3438 static long
badchar(long N,long k,GEN CHI)3439 badchar(long N, long k, GEN CHI)
3440 { return mfcharparity(CHI) != m1pk(k) || (CHI && N % mfcharconductor(CHI)); }
3441 
3442 /* dimension of space of cusp forms S_k(\G_0(N),CHI)
3443  * Only depends on CHIP the primitive char attached to CHI */
3444 long
mfcuspdim(long N,long k,GEN CHI)3445 mfcuspdim(long N, long k, GEN CHI)
3446 {
3447   pari_sp av = avma;
3448   long FC;
3449   GEN s;
3450   if (k <= 0) return 0;
3451   if (k == 1) return mfwt1cuspdim(N, CHI);
3452   FC = CHI? mfcharconductor(CHI): 1;
3453   if (FC == 1) CHI = NULL;
3454   s = gsub(A1(N, k), gadd(A21(N, k, CHI), A22(N, k, CHI)));
3455   s = gadd(s, gsubsg(A4(k, FC), A3(N, FC)));
3456   return gc_long(av, itos(s));
3457 }
3458 
3459 /* dimension of whole space M_k(\G_0(N),CHI)
3460  * Only depends on CHIP the primitive char attached to CHI; assumes !badchar */
3461 long
mffulldim(long N,long k,GEN CHI)3462 mffulldim(long N, long k, GEN CHI)
3463 {
3464   pari_sp av = avma;
3465   long FC = CHI? mfcharconductor(CHI): 1;
3466   GEN s;
3467   if (k <= 0) return (k == 0 && FC == 1)? 1: 0;
3468   if (k == 1) return gc_long(av, itos(A3(N, FC)) + mfwt1cuspdim(N, CHI));
3469   if (FC == 1) CHI = NULL;
3470   s = gsub(A1(N, k), gadd(A21(N, k, CHI), A22(N, k, CHI)));
3471   s = gadd(s, A3(N, FC));
3472   return gc_long(av, itos(s));
3473 }
3474 
3475 /* Dimension of the space of Eisenstein series */
3476 long
mfeisensteindim(long N,long k,GEN CHI)3477 mfeisensteindim(long N, long k, GEN CHI)
3478 {
3479   pari_sp av = avma;
3480   long s, FC = CHI? mfcharconductor(CHI): 1;
3481   if (k <= 0) return (k == 0 && FC == 1)? 1: 0;
3482   s = itos(gmul2n(A3(N, FC), 1));
3483   if (k > 1) s -= A4(k, FC); else s >>= 1;
3484   return gc_long(av,s);
3485 }
3486 
3487 enum { _SQRTS = 1, _MUP, _GCD, _VCHIP, _BEZ, _NEWLZ, _TRCONJ };
3488 /* Trace of T(n) on space of cuspforms; only depends on CHIP the primitive char
3489  * attached to CHI */
3490 static GEN
mfcusptrace_i(long N,long k,long n,GEN Dn,GEN S)3491 mfcusptrace_i(long N, long k, long n, GEN Dn, GEN S)
3492 {
3493   pari_sp av = avma;
3494   GEN a, b, VCHIP, GCD;
3495   long t;
3496   if (!n) return gen_0;
3497   VCHIP = gel(S,_VCHIP);
3498   GCD = gel(S,_GCD);
3499   t = TA4(k, VCHIP, Dn, GCD);
3500   a = TA1(N, k, VCHIP, GCD, n); if (t) a = gaddgs(a,t);
3501   b = TA2(N, k, VCHIP, n, gel(S,_SQRTS), gel(S,_MUP), GCD);
3502   b = gadd(b, TA3(N, k, VCHIP, GCD, Dn, gel(S,_BEZ)));
3503   b = gsub(a,b);
3504   if (typ(b) != t_POL) return gerepileupto(av, b);
3505   return gerepilecopy(av, vchip_polmod(VCHIP, b));
3506 }
3507 
3508 static GEN
mfcusptracecache(long N,long k,long n,GEN Dn,GEN S,cachenew_t * cache)3509 mfcusptracecache(long N, long k, long n, GEN Dn, GEN S, cachenew_t *cache)
3510 {
3511   GEN C = NULL, T = gel(cache->vfull,N);
3512   long lcache = lg(T);
3513   if (n < lcache) C = gel(T, n);
3514   if (C) cache->cuspHIT++; else C = mfcusptrace_i(N, k, n, Dn, S);
3515   cache->cuspTOTAL++;
3516   if (n < lcache) gel(T,n) = C;
3517   return C;
3518 }
3519 
3520 /* return the divisors of n, known to be among the elements of D */
3521 static GEN
div_restrict(GEN D,ulong n)3522 div_restrict(GEN D, ulong n)
3523 {
3524   long i, j, l;
3525   GEN v, VDIV = caches[cache_DIV].cache;
3526   if (lg(VDIV) > n) return gel(VDIV,n);
3527   l = lg(D);
3528   v = cgetg(l, t_VECSMALL);
3529   for (i = j = 1; i < l; i++)
3530   {
3531     ulong d = D[i];
3532     if (n % d == 0) v[j++] = d;
3533   }
3534   setlg(v,j); return v;
3535 }
3536 
3537 /* for some prime divisors of N, Tr^new(p) = 0 */
3538 static int
trconj(GEN T,long N,long n)3539 trconj(GEN T, long N, long n)
3540 { return (lg(T) > 1 && N % n == 0 && zv_search(T, n)); }
3541 
3542 /* n > 0; trace formula on new space */
3543 static GEN
mfnewtrace_i(long N,long k,long n,cachenew_t * cache)3544 mfnewtrace_i(long N, long k, long n, cachenew_t *cache)
3545 {
3546   GEN VCHIP, s, Dn, DN1, SN, S = cache->DATA;
3547   long FC, N1, N2, N1N2, g, i, j, lDN1;
3548 
3549   if (!S) return gen_0;
3550   SN = gel(S,N);
3551   if (mfnewchkzero(gel(SN,_NEWLZ), n)) return gen_0;
3552   if (k > 2 && trconj(gel(SN,_TRCONJ), N, n)) return gen_0;
3553   VCHIP = gel(SN, _VCHIP); FC = vchip_FC(VCHIP);
3554   N1 = N/FC; newt_params(N1, n, FC, &g, &N2);
3555   N1N2 = N1/N2;
3556   DN1 = mydivisorsu(N1N2); lDN1 = lg(DN1);
3557   N2 *= FC;
3558   Dn = mydivisorsu(n); /* this one is probably out of cache */
3559   s = gmulsg(mubeta2(N1N2,n), mfcusptracecache(N2, k, n, Dn, gel(S,N2), cache));
3560   for (i = 2; i < lDN1; i++)
3561   { /* skip M1 = 1, done above */
3562     long M1 = DN1[i], N1M1 = DN1[lDN1-i];
3563     GEN Dg = mydivisorsu(ugcd(M1, g));
3564     M1 *= N2;
3565     s = gadd(s, gmulsg(mubeta2(N1M1,n),
3566                        mfcusptracecache(M1, k, n, Dn, gel(S,M1), cache)));
3567     for (j = 2; j < lg(Dg); j++) /* skip d = 1, done above */
3568     {
3569       long d = Dg[j], ndd = n/(d*d), M = M1/d;
3570       GEN z = mulsi(mubeta2(N1M1,ndd), powuu(d,k-1)), C = vchip_lift(VCHIP,d,z);
3571       GEN Dndd = div_restrict(Dn, ndd);
3572       s = gadd(s, gmul(C, mfcusptracecache(M, k, ndd, Dndd, gel(S,M), cache)));
3573     }
3574     s = vchip_mod(VCHIP, s);
3575   }
3576   return vchip_polmod(VCHIP, s);
3577 }
3578 
3579 /* mfcuspdim(N,k,CHI) - mfnewdim(N,k,CHI); CHIP primitive (for efficiency) */
3580 static long
mfolddim_i(long N,long k,GEN CHIP)3581 mfolddim_i(long N, long k, GEN CHIP)
3582 {
3583   long S, i, l, FC = mfcharmodulus(CHIP), N1 = N/FC, N2;
3584   GEN D;
3585   newd_params(N1, &N2); /* will ensure mubeta != 0 */
3586   D = mydivisorsu(N1/N2); l = lg(D);
3587   N2 *= FC; S = 0;
3588   for (i = 2; i < l; i++)
3589   {
3590     long M = D[l-i]*N2, d = mfcuspdim(M, k, CHIP);
3591     if (d) S -= mubeta(D[i]) * d;
3592   }
3593   return S;
3594 }
3595 long
mfolddim(long N,long k,GEN CHI)3596 mfolddim(long N, long k, GEN CHI)
3597 {
3598   pari_sp av = avma;
3599   GEN CHIP = mfchartoprimitive(CHI, NULL);
3600   return gc_long(av, mfolddim_i(N, k, CHIP));
3601 }
3602 /* Only depends on CHIP the primitive char attached to CHI; assumes !badchar */
3603 long
mfnewdim(long N,long k,GEN CHI)3604 mfnewdim(long N, long k, GEN CHI)
3605 {
3606   pari_sp av;
3607   long S;
3608   GEN CHIP = mfchartoprimitive(CHI, NULL);
3609   S = mfcuspdim(N, k, CHIP); if (!S) return 0;
3610   av = avma; return gc_long(av, S - mfolddim_i(N, k, CHIP));
3611 }
3612 
3613 /* trace form, given as closure */
3614 static GEN
mftraceform_new(long N,long k,GEN CHI)3615 mftraceform_new(long N, long k, GEN CHI)
3616 {
3617   GEN T;
3618   if (k == 1) return initwt1newtrace(mfinit_Nkchi(N, 1, CHI, mf_CUSP, 0));
3619   T = initnewtrace(N,CHI); if (!T) return mftrivial();
3620   return tag(t_MF_NEWTRACE, mkNK(N,k,CHI), T);
3621 }
3622 static GEN
mftraceform_cusp(long N,long k,GEN CHI)3623 mftraceform_cusp(long N, long k, GEN CHI)
3624 {
3625   if (k == 1) return initwt1trace(mfinit_Nkchi(N, 1, CHI, mf_CUSP, 0));
3626   return tag(t_MF_TRACE, mkNK(N,k,CHI), inittrace(N,CHI,NULL));
3627 }
3628 static GEN
mftraceform_i(GEN NK,long space)3629 mftraceform_i(GEN NK, long space)
3630 {
3631   GEN CHI;
3632   long N, k;
3633   checkNK(NK, &N, &k, &CHI, 0);
3634   if (!mfdim_Nkchi(N, k, CHI, space)) return mftrivial();
3635   switch(space)
3636   {
3637     case mf_NEW: return mftraceform_new(N, k, CHI);
3638     case mf_CUSP:return mftraceform_cusp(N, k, CHI);
3639   }
3640   pari_err_DOMAIN("mftraceform", "space", "=", utoi(space), NK);
3641   return NULL;/*LCOV_EXCL_LINE*/
3642 }
3643 GEN
mftraceform(GEN NK,long space)3644 mftraceform(GEN NK, long space)
3645 { pari_sp av = avma; return gerepilecopy(av, mftraceform_i(NK,space)); }
3646 
3647 static GEN
hecke_data(long N,long n)3648 hecke_data(long N, long n)
3649 { return mkvecsmall3(n, u_ppo(n, N), N); }
3650 /* 1/2-integral weight */
3651 static GEN
heckef2_data(long N,long n)3652 heckef2_data(long N, long n)
3653 {
3654   ulong f, fN, fN2;
3655   if (!uissquareall(n, &f)) return NULL;
3656   fN = u_ppo(f, N); fN2 = fN*fN;
3657   return mkvec2(myfactoru(fN), mkvecsmall4(n, N, fN2, n/fN2));
3658 }
3659 /* N = mf_get_N(F) or a multiple */
3660 static GEN
mfhecke_i(long n,long N,GEN F)3661 mfhecke_i(long n, long N, GEN F)
3662 {
3663   if (n == 1) return F;
3664   return tag2(t_MF_HECKE, mf_get_NK(F), hecke_data(N,n), F);
3665 }
3666 
3667 GEN
mfhecke(GEN mf,GEN F,long n)3668 mfhecke(GEN mf, GEN F, long n)
3669 {
3670   pari_sp av = avma;
3671   GEN NK, CHI, gk, DATA;
3672   long N, nk, dk;
3673   mf = checkMF(mf);
3674   if (!checkmf_i(F)) pari_err_TYPE("mfhecke",F);
3675   if (n <= 0) pari_err_TYPE("mfhecke [n <= 0]", stoi(n));
3676   if (n == 1) return gcopy(F);
3677   gk = mf_get_gk(F);
3678   Qtoss(gk,&nk,&dk);
3679   CHI = mf_get_CHI(F);
3680   N = MF_get_N(mf);
3681   if (dk == 2)
3682   {
3683     DATA = heckef2_data(N,n);
3684     if (!DATA) return mftrivial();
3685   }
3686   else
3687     DATA = hecke_data(N,n);
3688   NK = mkgNK(lcmii(stoi(N), mf_get_gN(F)), gk, CHI, mf_get_field(F));
3689   return gerepilecopy(av, tag2(t_MF_HECKE, NK, DATA, F));
3690 }
3691 
3692 /* form F given by closure, compute B(d)(F) as closure (q -> q^d) */
3693 static GEN
mfbd_i(GEN F,long d)3694 mfbd_i(GEN F, long d)
3695 {
3696   GEN D, NK, gk, CHI;
3697   if (d == 1) return F;
3698   if (d <= 0) pari_err_TYPE("mfbd [d <= 0]", stoi(d));
3699   if (mf_get_type(F) != t_MF_BD) D = utoi(d);
3700   else { D = mului(d, gel(F,3)); F = gel(F,2); }
3701   gk = mf_get_gk(F); CHI = mf_get_CHI(F);
3702   if (typ(gk) != t_INT) CHI = mfcharmul(CHI, get_mfchar(utoi(d << 2)));
3703   NK = mkgNK(muliu(mf_get_gN(F), d), gk, CHI, mf_get_field(F));
3704   return tag2(t_MF_BD, NK, F, D);
3705 }
3706 GEN
mfbd(GEN F,long d)3707 mfbd(GEN F, long d)
3708 {
3709   pari_sp av = avma;
3710   if (!checkmf_i(F)) pari_err_TYPE("mfbd",F);
3711   return gerepilecopy(av, mfbd_i(F, d));
3712 }
3713 
3714 /* A[i+1] = a(t*i^2) */
3715 static GEN
RgV_shimura(GEN A,long n,long t,long N,long r,GEN CHI)3716 RgV_shimura(GEN A, long n, long t, long N, long r, GEN CHI)
3717 {
3718   GEN R, a0, Pn = mfcharpol(CHI);
3719   long m, st, ord = mfcharorder(CHI), vt = varn(Pn), Nt = t == 1? N: ulcm(N,t);
3720 
3721   R = cgetg(n + 2, t_VEC);
3722   st = odd(r)? -t: t;
3723   a0 = gel(A, 1);
3724   if (!gequal0(a0))
3725   {
3726     long o = mfcharorder(CHI);
3727     if (st != 1 && odd(o)) o <<= 1;
3728     a0 = gmul(a0, charLFwtk(Nt, r, CHI, o, st));
3729   }
3730   gel(R, 1) = a0;
3731   for (m = 1; m <= n; m++)
3732   {
3733     GEN Dm = mydivisorsu(u_ppo(m, Nt)), S = gel(A, m*m + 1);
3734     long i, l = lg(Dm);
3735     for (i = 2; i < l; i++)
3736     { /* (e,Nt) = 1; skip i = 1: e = 1, done above */
3737       long e = Dm[i], me = m / e, a = mfcharevalord(CHI, e, ord);
3738       GEN c, C = powuu(e, r - 1);
3739       if (kross(st, e) == -1) C = negi(C);
3740       c = Qab_Czeta(a, ord, C, vt);
3741       S = gadd(S, gmul(c, gel(A, me*me + 1)));
3742     }
3743     gel(R, m+1) = S;
3744   }
3745   return degpol(Pn) > 1? gmodulo(R, Pn): R;
3746 }
3747 
3748 static long
mfisinkohnen(GEN mf,GEN F)3749 mfisinkohnen(GEN mf, GEN F)
3750 {
3751   GEN v, gk = MF_get_gk(mf), CHI = MF_get_CHI(mf);
3752   long i, eps, N4 = MF_get_N(mf) >> 2, sb = mfsturmNgk(N4 << 4, gk) + 1;
3753   eps = N4 % mfcharconductor(CHI)? -1 : 1;
3754   if (odd(MF_get_r(mf))) eps = -eps;
3755   v = mfcoefs(F, sb, 1);
3756   for (i = 2;     i <= sb; i+=4) if (!gequal0(gel(v,i+1))) return 0;
3757   for (i = 2+eps; i <= sb; i+=4) if (!gequal0(gel(v,i+1))) return 0;
3758   return 1;
3759 }
3760 
3761 static long
mfshimura_space_cusp(GEN mf)3762 mfshimura_space_cusp(GEN mf)
3763 {
3764   long N4;
3765   if (MF_get_r(mf) == 1 && (N4 = MF_get_N(mf) >> 2) >= 4)
3766   {
3767     GEN E = gel(myfactoru(N4), 2);
3768     long ma = vecsmall_max(E);
3769     if (ma > 2 || (ma == 2 && !mfcharistrivial(MF_get_CHI(mf)))) return 0;
3770   }
3771   return 1;
3772 }
3773 
3774 /* D is either a discriminant (not necessarily fundamental) with
3775    sign(D)=(-1)^{k-1/2}*eps, or a positive squarefree integer t, which is then
3776    transformed into a fundamental discriminant of the correct sign. */
3777 GEN
mfshimura(GEN mf,GEN F,long t)3778 mfshimura(GEN mf, GEN F, long t)
3779 {
3780   pari_sp av = avma;
3781   GEN G, res, mf2, CHI;
3782   long sb, M, r, N, space = mf_FULL;
3783 
3784   if (!checkmf_i(F)) pari_err_TYPE("mfshimura",F);
3785   mf = checkMF(mf);
3786   r = MF_get_r(mf);
3787   if (r <= 0) pari_err_DOMAIN("mfshimura", "weight", "<=", ghalf, mf_get_gk(F));
3788   if (t <= 0 || !uissquarefree(t)) pari_err_TYPE("mfshimura [t]", stoi(t));
3789   N = MF_get_N(mf); M = N >> 1;
3790   if (mfiscuspidal(mf,F))
3791   {
3792     if (mfshimura_space_cusp(mf)) space = mf_CUSP;
3793     if (mfisinkohnen(mf,F)) M = N >> 2;
3794   }
3795   CHI = MF_get_CHI(mf);
3796   mf2 = mfinit_Nkchi(M, r << 1, mfcharpow(CHI, gen_2), space, 0);
3797   sb = mfsturm(mf2);
3798   G = RgV_shimura(mfcoefs_i(F, sb*sb, t), sb, t, N, r, CHI);
3799   res = mftobasis_i(mf2, G);
3800   /* not mflinear(mf2,): we want lowest possible level */
3801   G = mflinear(MF_get_basis(mf2), res);
3802   return gerepilecopy(av, mkvec3(mf2, G, res));
3803 }
3804 
3805 /* W ZabM (ZM if n = 1), a t_INT or NULL, b t_INT, ZXQ mod P or NULL.
3806  * Write a/b = A/d with d t_INT and A Zab return [W,d,A,P] */
3807 static GEN
mkMinv(GEN W,GEN a,GEN b,GEN P)3808 mkMinv(GEN W, GEN a, GEN b, GEN P)
3809 {
3810   GEN A = (b && typ(b) == t_POL)? Q_remove_denom(QXQ_inv(b,P), &b): NULL;
3811   if (a && b)
3812   {
3813     a = Qdivii(a,b);
3814     if (typ(a) == t_INT) b = gen_1; else { b = gel(a,2); a = gel(a,1); }
3815     if (is_pm1(a)) a = NULL;
3816   }
3817   if (a) A = A? ZX_Z_mul(A,a): a; else if (!A) A = gen_1;
3818   if (!b) b = gen_1;
3819   if (!P) P = gen_0;
3820   return mkvec4(W,b,A,P);
3821 }
3822 /* M square invertible QabM, return [M',d], M*M' = d*Id */
3823 static GEN
QabM_Minv(GEN M,GEN P,long n)3824 QabM_Minv(GEN M, GEN P, long n)
3825 {
3826   GEN dW, W, dM;
3827   M = Q_remove_denom(M, &dM);
3828   W = P? ZabM_inv(liftpol_shallow(M), P, n, &dW): ZM_inv(M, &dW);
3829   return mkMinv(W, dM, dW, P);
3830 }
3831 /* Simplified form of mfclean, after a QabM_indexrank: M a ZabM with full
3832  * column rank and z = indexrank(M) is known */
3833 static GEN
mfclean2(GEN M,GEN z,GEN P,long n)3834 mfclean2(GEN M, GEN z, GEN P, long n)
3835 {
3836   GEN d, Minv, y = gel(z,1), W = rowpermute(M, y);
3837   W = P? ZabM_inv(liftpol_shallow(W), P, n, &d): ZM_inv(W, &d);
3838   M = rowslice(M, 1, y[lg(y)-1]);
3839   Minv = mkMinv(W, NULL, d, P);
3840   return mkvec3(y, Minv, M);
3841 }
3842 /* M QabM, lg(M)>1 and [y,z] its rank profile. Let Minv be the inverse of the
3843  * invertible square matrix in mkMinv format. Return [y,Minv, M[..y[#y],]]
3844  * P cyclotomic polynomial of order n > 2 or NULL */
3845 static GEN
mfclean(GEN M,GEN P,long n,int ratlift)3846 mfclean(GEN M, GEN P, long n, int ratlift)
3847 {
3848   GEN W, v, y, z, d, Minv, dM, MdM = Q_remove_denom(M, &dM);
3849   if (n <= 2)
3850     W = ZM_pseudoinv(MdM, &v, &d);
3851   else
3852     W = ZabM_pseudoinv_i(liftpol_shallow(MdM), P, n, &v, &d, ratlift);
3853   y = gel(v,1);
3854   z = gel(v,2);
3855   if (lg(z) != lg(MdM)) M = vecpermute(M,z);
3856   M = rowslice(M, 1, y[lg(y)-1]);
3857   Minv = mkMinv(W, dM, d, P);
3858   return mkvec3(y, Minv, M);
3859 }
3860 /* call mfclean using only CHI */
3861 static GEN
mfcleanCHI(GEN M,GEN CHI,int ratlift)3862 mfcleanCHI(GEN M, GEN CHI, int ratlift)
3863 {
3864   long n = mfcharorder(CHI);
3865   GEN P = (n <= 2)? NULL: mfcharpol(CHI);
3866   return mfclean(M, P, n, ratlift);
3867 }
3868 
3869 /* DATA component of a t_MF_NEWTRACE. Was it stripped to save memory ? */
3870 static int
newtrace_stripped(GEN DATA)3871 newtrace_stripped(GEN DATA)
3872 { return DATA && (lg(DATA) == 5 && typ(gel(DATA,3)) == t_INT); }
3873 /* f a t_MF_NEWTRACE */
3874 static GEN
newtrace_DATA(long N,GEN f)3875 newtrace_DATA(long N, GEN f)
3876 {
3877   GEN DATA = gel(f,2);
3878   return newtrace_stripped(DATA)? initnewtrace(N, DATA): DATA;
3879 }
3880 /* reset cachenew for new level incorporating new DATA, tf a t_MF_NEWTRACE
3881  * (+ possibly initialize 'full' for new allowed levels) */
3882 static void
reset_cachenew(cachenew_t * cache,long N,GEN tf)3883 reset_cachenew(cachenew_t *cache, long N, GEN tf)
3884 {
3885   long i, n, l;
3886   GEN v, DATA = newtrace_DATA(N,tf);
3887   cache->DATA = DATA;
3888   if (!DATA) return;
3889   n = cache->n;
3890   v = cache->vfull; l = N+1; /* = lg(DATA) */
3891   for (i = 1; i < l; i++)
3892     if (typ(gel(v,i)) == t_INT && lg(gel(DATA,i)) != 1)
3893       gel(v,i) = const_vec(n, NULL);
3894   cache->VCHIP = gel(gel(DATA,N),_VCHIP);
3895 }
3896 /* initialize a cache of newtrace / cusptrace up to index n and level | N;
3897  * DATA may be NULL (<=> Tr^new = 0). tf a t_MF_NEWTRACE */
3898 static void
init_cachenew(cachenew_t * cache,long n,long N,GEN tf)3899 init_cachenew(cachenew_t *cache, long n, long N, GEN tf)
3900 {
3901   long i, l = N+1; /* = lg(tf.DATA) when DATA != NULL */
3902   GEN v;
3903   cache->n = n;
3904   cache->vnew = v = cgetg(l, t_VEC);
3905   for (i = 1; i < l; i++) gel(v,i) = (N % i)? gen_0: const_vec(n, NULL);
3906   cache->newHIT = cache->newTOTAL = cache->cuspHIT = cache->cuspTOTAL = 0;
3907   cache->vfull = v = zerovec(N);
3908   reset_cachenew(cache, N, tf);
3909 }
3910 static void
dbg_cachenew(cachenew_t * C)3911 dbg_cachenew(cachenew_t *C)
3912 {
3913   if (DEBUGLEVEL >= 2 && C)
3914     err_printf("newtrace cache hits: new = %ld/%ld, cusp = %ld/%ld\n",
3915                     C->newHIT, C->newTOTAL, C->cuspHIT, C->cuspTOTAL);
3916 }
3917 
3918 /* newtrace_{N,k}(d*i), i = n0, ..., n */
3919 static GEN
colnewtrace(long n0,long n,long d,long N,long k,cachenew_t * cache)3920 colnewtrace(long n0, long n, long d, long N, long k, cachenew_t *cache)
3921 {
3922   GEN v = cgetg(n-n0+2, t_COL);
3923   long i;
3924   for (i = n0; i <= n; i++) gel(v, i-n0+1) = mfnewtracecache(N, k, i*d, cache);
3925   return v;
3926 }
3927 /* T_n(l*m0, l*(m0+1), ..., l*m) F, F = t_MF_NEWTRACE [N,k],DATA, cache
3928  * contains DATA != NULL as well as cached values of F */
3929 static GEN
heckenewtrace(long m0,long m,long l,long N,long NBIG,long k,long n,cachenew_t * cache)3930 heckenewtrace(long m0, long m, long l, long N, long NBIG, long k, long n, cachenew_t *cache)
3931 {
3932   long lD, a, k1, nl = n*l;
3933   GEN D, V, v = colnewtrace(m0, m, nl, N, k, cache); /* d=1 */
3934   GEN VCHIP;
3935   if (n == 1) return v;
3936   VCHIP = cache->VCHIP;
3937   D = mydivisorsu(u_ppo(n, NBIG)); lD = lg(D);
3938   k1 = k - 1;
3939   for (a = 2; a < lD; a++)
3940   { /* d > 1, (d,NBIG) = 1 */
3941     long i, j, d = D[a], c = ugcd(l, d), dl = d/c, m0d = ceildiv(m0, dl);
3942     GEN C = vchip_lift(VCHIP, d, powuu(d, k1));
3943     /* m0=0: i = 1 => skip F(0) = 0 */
3944     if (!m0) { i = 1; j = dl; } else { i = 0; j = m0d*dl; }
3945     V = colnewtrace(m0d, m/dl, nl/(d*c), N, k, cache);
3946     /* C = chi(d) d^(k-1) */
3947     for (; j <= m; i++, j += dl)
3948       gel(v,j-m0+1) = gadd(gel(v,j-m0+1), vchip_mod(VCHIP, gmul(C,gel(V,i+1))));
3949   }
3950   return v;
3951 }
3952 
3953 /* Given v = an[i], return an[d*i] */
3954 static GEN
anextract(GEN v,long n,long d)3955 anextract(GEN v, long n, long d)
3956 {
3957   GEN w = cgetg(n+2, t_VEC);
3958   long i;
3959   for (i = 0; i <= n; i++) gel(w, i+1) = gel(v, i*d+1);
3960   return w;
3961 }
3962 /* T_n(F)(0, l, ..., l*m) */
3963 static GEN
hecke_i(long m,long l,GEN V,GEN F,GEN DATA)3964 hecke_i(long m, long l, GEN V, GEN F, GEN DATA)
3965 {
3966   long k, n, nNBIG, NBIG, lD, M, a, t, nl;
3967   GEN D, v, CHI;
3968   if (typ(DATA) == t_VEC)
3969   { /* 1/2-integral k */
3970     if (!V) { GEN S = gel(DATA,2); V = mfcoefs_i(F, m*l*S[3], S[4]); }
3971     return RgV_heckef2(m, l, V, F, DATA);
3972   }
3973   k = mf_get_k(F);
3974   n = DATA[1]; nl = n*l;
3975   nNBIG = DATA[2];
3976   NBIG = DATA[3];
3977   if (nNBIG == 1) return V? V: mfcoefs_i(F,m,nl);
3978   if (!V && mf_get_type(F) == t_MF_NEWTRACE)
3979   { /* inline F to allow cache, T_n at level NBIG acting on Tr^new(N,k,CHI) */
3980     cachenew_t cache;
3981     long N = mf_get_N(F);
3982     init_cachenew(&cache, m*nl, N, F);
3983     v = heckenewtrace(0, m, l, N, NBIG, k, n, &cache);
3984     dbg_cachenew(&cache);
3985     settyp(v, t_VEC); return v;
3986   }
3987   CHI = mf_get_CHI(F);
3988   D = mydivisorsu(nNBIG); lD = lg(D);
3989   M = m + 1;
3990   t = nNBIG * ugcd(nNBIG, l);
3991   if (!V) V = mfcoefs_i(F, m * t, nl / t); /* usually nl = t */
3992   v = anextract(V, m, t); /* mfcoefs(F, m, nl); d = 1 */
3993   for (a = 2; a < lD; a++)
3994   { /* d > 1, (d, NBIG) = 1 */
3995     long d = D[a], c = ugcd(l, d), dl = d/c, i, idl;
3996     GEN C = gmul(mfchareval(CHI, d), powuu(d, k-1));
3997     GEN w = anextract(V, m/dl, t/(d*c)); /* mfcoefs(F, m/dl, nl/(d*c)) */
3998     for (i = idl = 1; idl <= M; i++, idl += dl)
3999       gel(v,idl) = gadd(gel(v,idl), gmul(C, gel(w,i)));
4000   }
4001   return v;
4002 }
4003 
4004 static GEN
mkmf(GEN x1,GEN x2,GEN x3,GEN x4,GEN x5)4005 mkmf(GEN x1, GEN x2, GEN x3, GEN x4, GEN x5)
4006 {
4007   GEN MF = obj_init(5, MF_SPLITN);
4008   gel(MF,1) = x1;
4009   gel(MF,2) = x2;
4010   gel(MF,3) = x3;
4011   gel(MF,4) = x4;
4012   gel(MF,5) = x5; return MF;
4013 }
4014 
4015 /* return an integer b such that p | b => T_p^k Tr^new = 0, for all k > 0 */
4016 static long
get_badj(long N,long FC)4017 get_badj(long N, long FC)
4018 {
4019   GEN fa = myfactoru(N), P = gel(fa,1), E = gel(fa,2);
4020   long i, b = 1, l = lg(P);
4021   for (i = 1; i < l; i++)
4022     if (E[i] > 1 && u_lval(FC, P[i]) < E[i]) b *= P[i];
4023   return b;
4024 }
4025 /* in place, assume perm strictly increasing */
4026 static void
vecpermute_inplace(GEN v,GEN perm)4027 vecpermute_inplace(GEN v, GEN perm)
4028 {
4029   long i, l = lg(perm);
4030   for (i = 1; i < l; i++) gel(v,i) = gel(v,perm[i]);
4031 }
4032 
4033 /* Find basis of newspace using closures; assume k >= 2 and !badchar.
4034  * Return NULL if space is empty, else
4035  * [mf1, list of closures T(j)traceform, list of corresponding j, matrix] */
4036 static GEN
mfnewinit(long N,long k,GEN CHI,cachenew_t * cache,long init)4037 mfnewinit(long N, long k, GEN CHI, cachenew_t *cache, long init)
4038 {
4039   GEN S, vj, M, CHIP, mf1, listj, P, tf;
4040   long j, ct, ctlj, dim, jin, SB, sb, two, ord, FC, badj;
4041 
4042   dim = mfnewdim(N, k, CHI);
4043   if (!dim && !init) return NULL;
4044   sb = mfsturmNk(N, k);
4045   CHIP = mfchartoprimitive(CHI, &FC);
4046   /* remove newtrace data from S to save space in output: negligible slowdown */
4047   tf = tag(t_MF_NEWTRACE, mkNK(N,k,CHIP), CHIP);
4048   badj = get_badj(N, FC);
4049   /* try sbsmall first: Sturm bound not sharp for new space */
4050   SB = ceilA1(N, k);
4051   listj = cgetg(2*sb + 3, t_VECSMALL);
4052   for (j = ctlj = 1; ctlj < 2*sb + 3; j++)
4053     if (ugcd(j, badj) == 1) listj[ctlj++] = j;
4054   if (init)
4055   {
4056     init_cachenew(cache, (SB+1)*listj[dim+1], N, tf);
4057     if (init == -1 || !dim) return NULL; /* old space or dim = 0 */
4058   }
4059   else
4060     reset_cachenew(cache, N, tf);
4061   /* cache.DATA is not NULL */
4062   ord = mfcharorder(CHIP);
4063   P = ord <= 2? NULL: mfcharpol(CHIP);
4064   vj = cgetg(dim+1, t_VECSMALL);
4065   M = cgetg(dim+1, t_MAT);
4066   for (two = 1, ct = 0, jin = 1; two <= 2; two++)
4067   {
4068     long a, jlim = jin + sb;
4069     for (a = jin; a <= jlim; a++)
4070     {
4071       GEN z, vecz;
4072       ct++; vj[ct] = listj[a];
4073       gel(M, ct) = heckenewtrace(0, SB, 1, N, N, k, vj[ct], cache);
4074       if (ct < dim) continue;
4075 
4076       z = QabM_indexrank(M, P, ord);
4077       vecz = gel(z, 2); ct = lg(vecz) - 1;
4078       if (ct == dim) { M = mkvec3(z, gen_0, M); break; } /*maximal rank, done*/
4079       vecpermute_inplace(M, vecz);
4080       vecpermute_inplace(vj, vecz);
4081     }
4082     if (a <= jlim) break;
4083     /* sbsmall was not sufficient, use Sturm bound: must extend M */
4084     for (j = 1; j <= ct; j++)
4085     {
4086       GEN t = heckenewtrace(SB + 1, sb, 1, N, N, k, vj[j], cache);
4087       gel(M,j) = shallowconcat(gel(M, j), t);
4088     }
4089     jin = jlim + 1; SB = sb;
4090   }
4091   S = cgetg(dim + 1, t_VEC);
4092   for (j = 1; j <= dim; j++) gel(S, j) = mfhecke_i(vj[j], N, tf);
4093   dbg_cachenew(cache);
4094   mf1 = mkvec4(utoipos(N), utoipos(k), CHI, utoi(mf_NEW));
4095   return mkmf(mf1, cgetg(1,t_VEC), S, vj, M);
4096 }
4097 /* k > 1 integral, mf space is mf_CUSP or mf_FULL */
4098 static GEN
mfinittonew(GEN mf)4099 mfinittonew(GEN mf)
4100 {
4101   GEN CHI = MF_get_CHI(mf), S = MF_get_S(mf), vMjd = MFcusp_get_vMjd(mf);
4102   GEN M = MF_get_M(mf), vj, mf1;
4103   long i, j, l, l0 = lg(S), N0 = MF_get_N(mf);
4104   for (i = l0-1; i > 0; i--)
4105   {
4106     long N = gel(vMjd,i)[1];
4107     if (N != N0) break;
4108   }
4109   if (i == l0-1) return NULL;
4110   S = vecslice(S, i+1, l0-1); /* forms of conductor N0 */
4111   l = lg(S); vj = cgetg(l, t_VECSMALL);
4112   for (j = 1; j < l; j++) vj[j] = gel(vMjd,j+i)[2];
4113   M = vecslice(M, lg(M)-lg(S)+1, lg(M)-1); /* their coefficients */
4114   M = mfcleanCHI(M, CHI, 0);
4115   mf1 = mkvec4(utoipos(N0), MF_get_gk(mf), CHI, utoi(mf_NEW));
4116   return mkmf(mf1, cgetg(1,t_VEC), S, vj, M);
4117 }
4118 
4119 /* Bd(f)[m0..m], v = f[ceil(m0/d)..floor(m/d)], m0d = ceil(m0/d) */
4120 static GEN
RgC_Bd_expand(long m0,long m,GEN v,long d,long m0d)4121 RgC_Bd_expand(long m0, long m, GEN v, long d, long m0d)
4122 {
4123   long i, j;
4124   GEN w;
4125   if (d == 1) return v;
4126   w = zerocol(m-m0+1);
4127   if (!m0) { i = 1; j = d; } else { i = 0; j = m0d*d; }
4128   for (; j <= m; i++, j += d) gel(w,j-m0+1) = gel(v,i+1);
4129   return w;
4130 }
4131 /* S a nonempty vector of t_MF_BD(t_MF_HECKE(t_MF_NEWTRACE)); M the matrix
4132  * of their coefficients r*0, r*1, ..., r*m0 (~ mfvectomat) or NULL (empty),
4133  * extend it to coeffs up to m > m0. The forms B_d(T_j(tf_N))in S should be
4134  * sorted by level N, then j, then increasing d. No reordering here. */
4135 static GEN
bhnmat_extend(GEN M,long m,long r,GEN S,cachenew_t * cache)4136 bhnmat_extend(GEN M, long m, long r, GEN S, cachenew_t *cache)
4137 {
4138   long i, mr, m0, m0r, Nold = 0, jold = 0, l = lg(S);
4139   GEN MAT = cgetg(l, t_MAT), v = NULL;
4140   if (M) { m0 = nbrows(M); m0r = m0 * r; } else m0 = m0r = 0;
4141   mr = m*r;
4142   for (i = 1; i < l; i++)
4143   {
4144     long d, j, md, N;
4145     GEN c, f = bhn_parse(gel(S,i), &d,&j); /* t_MF_NEWTRACE */
4146     N = mf_get_N(f);
4147     md = ceildiv(m0r,d);
4148     if (N != Nold) { reset_cachenew(cache, N, f); Nold = N; jold = 0; }
4149     if (!cache->DATA) { gel(MAT,i) = zerocol(m+1); continue; }
4150     if (j != jold || md)
4151     { v = heckenewtrace(md, mr/d, 1, N, N, mf_get_k(f), j,cache); jold=j; }
4152     c = RgC_Bd_expand(m0r, mr, v, d, md);
4153     if (r > 1) c = c_deflate(m-m0, r, c);
4154     if (M) c = shallowconcat(gel(M,i), c);
4155     gel(MAT,i) = c;
4156   }
4157   return MAT;
4158 }
4159 
4160 static GEN
mfinitcusp(long N,long k,GEN CHI,cachenew_t * cache,long space)4161 mfinitcusp(long N, long k, GEN CHI, cachenew_t *cache, long space)
4162 {
4163   long L, l, lDN1, FC, N1, d1, i, init;
4164   GEN vS, vMjd, DN1, vmf, CHIP = mfchartoprimitive(CHI, &FC);
4165 
4166   d1 = (space == mf_OLD)? mfolddim_i(N, k, CHIP): mfcuspdim(N, k, CHIP);
4167   if (!d1) return NULL;
4168   N1 = N/FC; DN1 = mydivisorsu(N1); lDN1 = lg(DN1);
4169   init = (space == mf_OLD)? -1: 1;
4170   vmf = cgetg(lDN1, t_VEC);
4171   for (i = lDN1 - 1, l = 1; i; i--)
4172   { /* by decreasing level to allow cache */
4173     GEN mf = mfnewinit(FC*DN1[i], k, CHIP, cache, init);
4174     if (mf) gel(vmf, l++) = mf;
4175     init = 0;
4176   }
4177   setlg(vmf,l); vmf = vecreverse(vmf); /* reorder by increasing level */
4178 
4179   L = mfsturmNk(N, k)+1;
4180   vS = vectrunc_init(L);
4181   vMjd = vectrunc_init(L);
4182   for (i = 1; i < l; i++)
4183   {
4184     GEN DNM, mf = gel(vmf,i), S = MF_get_S(mf), vj = MFnew_get_vj(mf);
4185     long a, lDNM, lS = lg(S), M = MF_get_N(mf);
4186     DNM = mydivisorsu(N / M); lDNM = lg(DNM);
4187     for (a = 1; a < lS; a++)
4188     {
4189       GEN tf = gel(S,a);
4190       long b, j = vj[a];
4191       for (b = 1; b < lDNM; b++)
4192       {
4193         long d = DNM[b];
4194         vectrunc_append(vS, mfbd_i(tf, d));
4195         vectrunc_append(vMjd, mkvecsmall3(M, j, d));
4196       }
4197     }
4198   }
4199   return mkmf(NULL, cgetg(1, t_VEC), vS, vMjd, NULL);
4200 }
4201 
4202 long
mfsturm_mf(GEN mf)4203 mfsturm_mf(GEN mf)
4204 {
4205   GEN Mindex = MF_get_Mindex(mf);
4206   long n = lg(Mindex)-1;
4207   return n? Mindex[n]-1: 0;
4208 }
4209 
4210 long
mfsturm(GEN T)4211 mfsturm(GEN T)
4212 {
4213   long N, nk, dk;
4214   GEN CHI, mf = checkMF_i(T);
4215   if (mf) return mfsturm_mf(mf);
4216   checkNK2(T, &N, &nk, &dk, &CHI, 0);
4217   return dk == 1 ? mfsturmNk(N, nk) : mfsturmNk(N, (nk + 1) >> 1);
4218 }
4219 long
mfisequal(GEN F,GEN G,long lim)4220 mfisequal(GEN F, GEN G, long lim)
4221 {
4222   pari_sp av = avma;
4223   long b;
4224   if (!checkmf_i(F)) pari_err_TYPE("mfisequal",F);
4225   if (!checkmf_i(G)) pari_err_TYPE("mfisequal",G);
4226   b = lim? lim: maxss(mfsturmmf(F), mfsturmmf(G));
4227   return gc_long(av, gequal(mfcoefs_i(F, b, 1), mfcoefs_i(G, b, 1)));
4228 }
4229 
4230 GEN
mffields(GEN mf)4231 mffields(GEN mf)
4232 {
4233   if (checkmf_i(mf)) return gcopy(mf_get_field(mf));
4234   mf = checkMF(mf); return gcopy(MF_get_fields(mf));
4235 }
4236 
4237 GEN
mfeigenbasis(GEN mf)4238 mfeigenbasis(GEN mf)
4239 {
4240   pari_sp ltop = avma;
4241   GEN F, S, v, vP;
4242   long i, l, k, dS;
4243 
4244   mf = checkMF(mf);
4245   k = MF_get_k(mf);
4246   S = MF_get_S(mf); dS = lg(S)-1;
4247   if (!dS) return cgetg(1, t_VEC);
4248   F = MF_get_newforms(mf);
4249   vP = MF_get_fields(mf);
4250   if (k == 1)
4251   {
4252     if (MF_get_space(mf) == mf_FULL)
4253     {
4254       long dE = lg(MF_get_E(mf)) - 1;
4255       if (dE) F = rowslice(F, dE+1, dE+dS);
4256     }
4257     v = vecmflineardiv_linear(S, F);
4258     l = lg(v);
4259   }
4260   else
4261   {
4262     GEN (*L)(GEN, GEN) = (MF_get_space(mf) == mf_FULL)? mflinear: mflinear_bhn;
4263     l = lg(F); v = cgetg(l, t_VEC);
4264     for (i = 1; i < l; i++) gel(v,i) = L(mf, gel(F,i));
4265   }
4266   for (i = 1; i < l; i++) mf_setfield(gel(v,i), gel(vP,i));
4267   return gerepilecopy(ltop, v);
4268 }
4269 
4270 /* Minv = [M, d, A], v a t_COL; A a Zab, d a t_INT; return (A/d) * M*v */
4271 static GEN
Minv_RgC_mul(GEN Minv,GEN v)4272 Minv_RgC_mul(GEN Minv, GEN v)
4273 {
4274   GEN M = gel(Minv,1), d = gel(Minv,2), A = gel(Minv,3);
4275   v = RgM_RgC_mul(M, v);
4276   if (!equali1(A))
4277   {
4278     if (typ(A) == t_POL && degpol(A) > 0) A = mkpolmod(A, gel(Minv,4));
4279     v = RgC_Rg_mul(v, A);
4280   }
4281   if (!equali1(d)) v = RgC_Rg_div(v, d);
4282   return v;
4283 }
4284 static GEN
Minv_RgM_mul(GEN Minv,GEN B)4285 Minv_RgM_mul(GEN Minv, GEN B)
4286 {
4287   long j, l = lg(B);
4288   GEN M = cgetg(l, t_MAT);
4289   for (j = 1; j < l; j++) gel(M,j) = Minv_RgC_mul(Minv, gel(B,j));
4290   return M;
4291 }
4292 /* B * Minv; allow B = NULL for Id */
4293 static GEN
RgM_Minv_mul(GEN B,GEN Minv)4294 RgM_Minv_mul(GEN B, GEN Minv)
4295 {
4296   GEN M = gel(Minv,1), d = gel(Minv,2), A = gel(Minv,3);
4297   if (B) M = RgM_mul(B, M);
4298   if (!equali1(A))
4299   {
4300     if (typ(A) == t_POL) A = mkpolmod(A, gel(Minv,4));
4301     M = RgM_Rg_mul(M, A);
4302   }
4303   if (!equali1(d)) M = RgM_Rg_div(M,d);
4304   return M;
4305 }
4306 
4307 /* perm vector of strictly increasing indices, v a vector or arbitrary length;
4308  * the last r entries of perm fall beyond v.
4309  * Return v o perm[1..(-r)], discarding the last r entries of v */
4310 static GEN
vecpermute_partial(GEN v,GEN perm,long * r)4311 vecpermute_partial(GEN v, GEN perm, long *r)
4312 {
4313   long i, n = lg(v)-1, l = lg(perm);
4314   GEN w;
4315   if (perm[l-1] <= n) { *r = 0; return vecpermute(v,perm); }
4316   for (i = 1; i < l; i++)
4317     if (perm[i] > n) break;
4318   *r = l - i; l = i;
4319   w = cgetg(l, typ(v));
4320   for (i = 1; i < l; i++) gel(w,i) = gel(v,perm[i]);
4321   return w;
4322 }
4323 
4324 /* given form F, find coeffs of F on mfbasis(mf). If power series, not
4325  * guaranteed correct if precision less than Sturm bound */
4326 static GEN
mftobasis_i(GEN mf,GEN F)4327 mftobasis_i(GEN mf, GEN F)
4328 {
4329   GEN v, Mindex, Minv;
4330   if (!MF_get_dim(mf)) return cgetg(1, t_COL);
4331   Mindex = MF_get_Mindex(mf);
4332   Minv = MF_get_Minv(mf);
4333   if (checkmf_i(F))
4334   {
4335     long n = Mindex[lg(Mindex)-1];
4336     v = vecpermute(mfcoefs_i(F, n, 1), Mindex);
4337     return Minv_RgC_mul(Minv, v);
4338   }
4339   else
4340   {
4341     GEN A = gel(Minv,1), d = gel(Minv,2);
4342     long r;
4343     v = F;
4344     switch(typ(F))
4345     {
4346       case t_SER: v = sertocol(v);
4347       case t_VEC: case t_COL: break;
4348       default: pari_err_TYPE("mftobasis", F);
4349     }
4350     if (lg(v) == 1) pari_err_TYPE("mftobasis",v);
4351     v = vecpermute_partial(v, Mindex, &r);
4352     if (!r) return Minv_RgC_mul(Minv, v); /* single solution */
4353     /* affine space of dimension r */
4354     v = RgM_RgC_mul(vecslice(A, 1, lg(v)-1), v);
4355     if (!equali1(d)) v = RgC_Rg_div(v,d);
4356     return mkvec2(v, vecslice(A, lg(A)-r, lg(A)-1));
4357   }
4358 }
4359 
4360 static GEN
const_mat(long n,GEN x)4361 const_mat(long n, GEN x)
4362 {
4363   long j, l = n+1;
4364   GEN A = cgetg(l,t_MAT);
4365   for (j = 1; j < l; j++) gel(A,j) = const_col(n, x);
4366   return A;
4367 }
4368 
4369 /* L is the mftobasis of a form on CUSP space. We allow mf_FULL or mf_CUSP */
4370 static GEN
mftonew_i(GEN mf,GEN L,long * plevel)4371 mftonew_i(GEN mf, GEN L, long *plevel)
4372 {
4373   GEN S, listMjd, CHI, res, Aclos, Acoef, D, perm;
4374   long N1, LC, lD, i, l, t, level, N = MF_get_N(mf);
4375 
4376   if (MF_get_k(mf) == 1) pari_err_IMPL("mftonew in weight 1");
4377   listMjd = MFcusp_get_vMjd(mf);
4378   CHI = MF_get_CHI(mf); LC = mfcharconductor(CHI);
4379   S = MF_get_S(mf);
4380 
4381   N1 = N/LC;
4382   D = mydivisorsu(N1); lD = lg(D);
4383   perm = cgetg(N1+1, t_VECSMALL);
4384   for (i = 1; i < lD; i++) perm[D[i]] = i;
4385   Aclos = const_mat(lD-1, cgetg(1,t_VEC));
4386   Acoef = const_mat(lD-1, cgetg(1,t_VEC));
4387   l = lg(listMjd);
4388   for (i = 1; i < l; i++)
4389   {
4390     long M, d;
4391     GEN v;
4392     if (gequal0(gel(L,i))) continue;
4393     v = gel(listMjd, i);
4394     M = perm[ v[1]/LC ];
4395     d = perm[ v[3] ];
4396     gcoeff(Aclos,M,d) = vec_append(gcoeff(Aclos,M,d), gel(S,i));
4397     gcoeff(Acoef,M,d) = shallowconcat(gcoeff(Acoef,M,d), gel(L,i));
4398   }
4399   res = cgetg(l, t_VEC); level = 1;
4400   for (i = t = 1; i < lD; i++)
4401   {
4402     long j, M = D[i]*LC;
4403     GEN gM = utoipos(M);
4404     for (j = 1; j < lD; j++)
4405     {
4406       GEN f = gcoeff(Aclos,i,j), C, NK;
4407       long d;
4408       if (lg(f) == 1) continue;
4409       NK = mf_get_NK(gel(f,1));
4410       d = D[j];
4411       C = gcoeff(Acoef,i,j);
4412       level = ulcm(level, M*d);
4413       gel(res,t++) = mkvec3(gM, utoipos(d), mflinear_i(NK,f,C));
4414     }
4415   }
4416   if (plevel) *plevel = level;
4417   setlg(res, t); return res;
4418 }
4419 GEN
mftonew(GEN mf,GEN F)4420 mftonew(GEN mf, GEN F)
4421 {
4422   pari_sp av = avma;
4423   GEN ES;
4424   long s;
4425   mf = checkMF(mf);
4426   s = MF_get_space(mf);
4427   if (s != mf_FULL && s != mf_CUSP)
4428     pari_err_TYPE("mftonew [not a full or cuspidal space]", mf);
4429   ES = mftobasisES(mf,F);
4430   if (!gequal0(gel(ES,1)))
4431     pari_err_TYPE("mftonew [not a cuspidal form]", F);
4432   F = gel(ES,2);
4433   return gerepilecopy(av, mftonew_i(mf,F, NULL));
4434 }
4435 
4436 static GEN mfeisenstein_i(long k, GEN CHI1, GEN CHI2);
4437 
4438 /* mfinit(F * Theta) */
4439 static GEN
mf2init(GEN mf)4440 mf2init(GEN mf)
4441 {
4442   GEN CHI = MF_get_CHI(mf), gk = gadd(MF_get_gk(mf), ghalf);
4443   long N = MF_get_N(mf);
4444   return mfinit_Nkchi(N, itou(gk), mfchiadjust(CHI, gk, N), mf_FULL, 0);
4445 }
4446 
4447 static long
mfvec_first_cusp(GEN v)4448 mfvec_first_cusp(GEN v)
4449 {
4450   long i, l = lg(v);
4451   for (i = 1; i < l; i++)
4452   {
4453     GEN F = gel(v,i);
4454     long t = mf_get_type(F);
4455     if (t == t_MF_BD) { F = gel(F,2); t = mf_get_type(F); }
4456     if (t == t_MF_HECKE) { F = gel(F,3); t = mf_get_type(F); }
4457     if (t == t_MF_NEWTRACE) break;
4458   }
4459   return i;
4460 }
4461 /* vF a vector of mf F of type DIV(LINEAR(BAS,L), f) in (lcm) level N,
4462  * F[2]=LINEAR(BAS,L), F[2][2]=BAS=fixed basis (Eisenstein or bhn type),
4463  * F[2][3]=L, F[3]=f; mfvectomat(vF, n) */
4464 static GEN
mflineardivtomat(long N,GEN vF,long n)4465 mflineardivtomat(long N, GEN vF, long n)
4466 {
4467   GEN F, M, f, fc, ME, dB, B, a0, V = NULL;
4468   long lM, lF = lg(vF), j;
4469 
4470   if (lF == 1) return cgetg(1,t_MAT);
4471   F = gel(vF,1);
4472   if (lg(F) == 5)
4473   { /* chicompat */
4474     V = gmael(F,4,4);
4475     if (typ(V) == t_INT) V = NULL;
4476   }
4477   M = gmael(F,2,2); /* BAS */
4478   lM = lg(M);
4479   j = mfvec_first_cusp(M);
4480   if (j == 1) ME = NULL;
4481   else
4482   { /* BAS starts by Eisenstein */
4483     ME = mfvectomat(vecslice(M,1,j-1), n, 1);
4484     M = vecslice(M, j,lM-1);
4485   }
4486   M = bhnmat_extend_nocache(NULL, N, n, 1, M);
4487   if (ME) M = shallowconcat(ME,M);
4488   /* M = mfcoefs of BAS */
4489   B = cgetg(lF, t_MAT);
4490   dB= cgetg(lF, t_VEC);
4491   for (j = 1; j < lF; j++)
4492   {
4493     GEN g = gel(vF, j); /* t_MF_DIV */
4494     gel(B,j) = RgM_RgC_mul(M, gmael(g,2,3));
4495     gel(dB,j)= gmael(g,2,4);
4496   }
4497   f = mfcoefsser(gel(F,3),n);
4498   a0 = polcoef_i(f, 0, -1);
4499   if (gequal0(a0) || gequal1(a0))
4500     a0 = NULL;
4501   else
4502     f = gdiv(ser_unscale(f, a0), a0);
4503   fc = ginv(f);
4504   for (j = 1; j < lF; j++)
4505   {
4506     pari_sp av = avma;
4507     GEN LISer = RgV_to_ser_full(gel(B,j)), f;
4508     if (a0) LISer = gdiv(ser_unscale(LISer, a0), a0);
4509     f = gmul(LISer, fc);
4510     if (a0) f = ser_unscale(f, ginv(a0));
4511     f = sertocol(f); setlg(f, n+2);
4512     if (!gequal1(gel(dB,j))) f = RgC_Rg_div(f, gel(dB,j));
4513     gel(B,j) = gerepileupto(av,f);
4514   }
4515   if (V) B = gmodulo(QabM_tracerel(V, 0, B), gel(V,1));
4516   return B;
4517 }
4518 
4519 static GEN
mfheckemat_mfcoefs(GEN mf,GEN B,GEN DATA)4520 mfheckemat_mfcoefs(GEN mf, GEN B, GEN DATA)
4521 {
4522   GEN Mindex = MF_get_Mindex(mf), Minv = MF_get_Minv(mf);
4523   long j, l = lg(B), sb = mfsturm_mf(mf);
4524   GEN b = MF_get_basis(mf), Q = cgetg(l, t_VEC);
4525   for (j = 1; j < l; j++)
4526   {
4527     GEN v = hecke_i(sb, 1, gel(B,j), gel(b,j), DATA); /* Tn b[j] */
4528     settyp(v,t_COL); gel(Q,j) = vecpermute(v, Mindex);
4529   }
4530   return Minv_RgM_mul(Minv,Q);
4531 }
4532 /* T_p^2, p prime, 1/2-integral weight; B = mfcoefs(mf,sb*p^2,1) or (mf,sb,p^2)
4533  * if p|N */
4534 static GEN
mfheckemat_mfcoefs_p2(GEN mf,long p,GEN B)4535 mfheckemat_mfcoefs_p2(GEN mf, long p, GEN B)
4536 {
4537   pari_sp av = avma;
4538   GEN DATA = heckef2_data(MF_get_N(mf), p*p);
4539   return gerepileupto(av, mfheckemat_mfcoefs(mf, B, DATA));
4540 }
4541 /* convert Mindex from row-index to mfcoef indexation: a(n) is stored in
4542  * mfcoefs()[n+1], so subtract 1 from all indices */
4543 static GEN
Mindex_as_coef(GEN mf)4544 Mindex_as_coef(GEN mf)
4545 {
4546   GEN v, Mindex = MF_get_Mindex(mf);
4547   long i, l = lg(Mindex);
4548   v = cgetg(l, t_VECSMALL);
4549   for (i = 1; i < l; i++) v[i] = Mindex[i]-1;
4550   return v;
4551 }
4552 /* T_p, p prime; B = mfcoefs(mf,sb*p,1) or (mf,sb,p) if p|N; integral weight */
4553 static GEN
mfheckemat_mfcoefs_p(GEN mf,long p,GEN B)4554 mfheckemat_mfcoefs_p(GEN mf, long p, GEN B)
4555 {
4556   pari_sp av = avma;
4557   GEN vm, Q, C, Minv = MF_get_Minv(mf);
4558   long lm, k, i, j, l = lg(B), N = MF_get_N(mf);
4559 
4560   if (N % p == 0) return Minv_RgM_mul(Minv, rowpermute(B, MF_get_Mindex(mf)));
4561   k = MF_get_k(mf);
4562   C = gmul(mfchareval(MF_get_CHI(mf), p), powuu(p, k-1));
4563   vm = Mindex_as_coef(mf); lm = lg(vm);
4564   Q = cgetg(l, t_MAT);
4565   for (j = 1; j < l; j++) gel(Q,j) = cgetg(lm, t_COL);
4566   for (i = 1; i < lm; i++)
4567   {
4568     long m = vm[i], mp = m*p;
4569     GEN Cm = (m % p) == 0? C : NULL;
4570     for (j = 1; j < l; j++)
4571     {
4572       GEN S = gel(B,j), s = gel(S, mp + 1);
4573       if (Cm) s = gadd(s, gmul(C, gel(S, m/p + 1)));
4574       gcoeff(Q, i, j) = s;
4575     }
4576   }
4577   return gerepileupto(av, Minv_RgM_mul(Minv,Q));
4578 }
4579 /* Matrix of T(p), p prime, dim(mf) > 0 and integral weight */
4580 static GEN
mfheckemat_p(GEN mf,long p)4581 mfheckemat_p(GEN mf, long p)
4582 {
4583   pari_sp av = avma;
4584   long N = MF_get_N(mf), sb = mfsturm_mf(mf);
4585   GEN B = (N % p)? mfcoefs_mf(mf, sb * p, 1): mfcoefs_mf(mf, sb, p);
4586   return gerepileupto(av, mfheckemat_mfcoefs(mf, B, hecke_data(N,p)));
4587 }
4588 
4589 /* mf_NEW != (0), weight > 1, p prime. Use
4590  * T(p) T(j) = T(j*p) + p^{k-1} \chi(p) 1_{p | j, p \nmid N} T(j/p) */
4591 static GEN
mfnewmathecke_p(GEN mf,long p)4592 mfnewmathecke_p(GEN mf, long p)
4593 {
4594   pari_sp av = avma;
4595   GEN tf, vj = MFnew_get_vj(mf), CHI = MF_get_CHI(mf);
4596   GEN Mindex = MF_get_Mindex(mf), Minv = MF_get_Minv(mf);
4597   long N = MF_get_N(mf), k = MF_get_k(mf);
4598   long i, j, lvj = lg(vj), lim = vj[lvj-1] * p;
4599   GEN M, perm, V, need = zero_zv(lim);
4600   GEN C = (N % p)? gmul(mfchareval(CHI,p), powuu(p,k-1)): NULL;
4601   tf = mftraceform_new(N, k, CHI);
4602   for (i = 1; i < lvj; i++)
4603   {
4604     j = vj[i]; need[j*p] = 1;
4605     if (N % p && j % p == 0) need[j/p] = 1;
4606   }
4607   perm = zero_zv(lim);
4608   V = cgetg(lim+1, t_VEC);
4609   for (i = j = 1; i <= lim; i++)
4610     if (need[i]) { gel(V,j) = mfhecke_i(i, N, tf); perm[i] = j; j++; }
4611   setlg(V, j);
4612   V = bhnmat_extend_nocache(NULL, N, mfsturm_mf(mf), 1, V);
4613   V = rowpermute(V, Mindex); /* V[perm[i]] = coeffs(T_i newtrace) */
4614   M = cgetg(lvj, t_MAT);
4615   for (i = 1; i < lvj; i++)
4616   {
4617     GEN t;
4618     j = vj[i]; t = gel(V, perm[j*p]);
4619     if (C && j % p == 0) t = RgC_add(t, RgC_Rg_mul(gel(V, perm[j/p]),C));
4620     gel(M,i) = t;
4621   }
4622   return gerepileupto(av, Minv_RgM_mul(Minv, M));
4623 }
4624 
4625 GEN
mfheckemat(GEN mf,GEN vn)4626 mfheckemat(GEN mf, GEN vn)
4627 {
4628   pari_sp av = avma;
4629   long lv, lvP, i, N, dim, nk, dk, p, sb, flint = (typ(vn)==t_INT);
4630   GEN CHI, res, vT, FA, B, vP;
4631 
4632   mf = checkMF(mf);
4633   if (typ(vn) != t_VECSMALL) vn = gtovecsmall(vn);
4634   N = MF_get_N(mf); CHI = MF_get_CHI(mf); Qtoss(MF_get_gk(mf), &nk, &dk);
4635   dim = MF_get_dim(mf);
4636   lv = lg(vn);
4637   res = cgetg(lv, t_VEC);
4638   FA = cgetg(lv, t_VEC);
4639   vP = cgetg(lv, t_VEC);
4640   vT = const_vec(vecsmall_max(vn), NULL);
4641   for (i = 1; i < lv; i++)
4642   {
4643     ulong n = (ulong)labs(vn[i]);
4644     GEN fa;
4645     if (!n) pari_err_TYPE("mfheckemat", vn);
4646     if (dk == 1 || uissquareall(n, &n)) fa = myfactoru(n);
4647     else { n = 0; fa = myfactoru(1); } /* dummy: T_{vn[i]} = 0 */
4648     vn[i] = n;
4649     gel(FA,i) = fa;
4650     gel(vP,i) = gel(fa,1);
4651   }
4652   vP = shallowconcat1(vP); vecsmall_sort(vP);
4653   vP = vecsmall_uniq_sorted(vP); /* all primes occurring in vn */
4654   lvP = lg(vP); if (lvP == 1) goto END;
4655   p = vP[lvP-1];
4656   sb = mfsturm_mf(mf);
4657   if (dk == 1 && nk != 1 && MF_get_space(mf) == mf_NEW)
4658     B = NULL; /* special purpose mfnewmathecke_p is faster */
4659   else if (lvP == 2 && N % p == 0)
4660     B = mfcoefs_mf(mf, sb, dk==2? p*p: p); /* single prime | N, can optimize */
4661   else
4662     B = mfcoefs_mf(mf, sb * (dk==2? p*p: p), 1); /* general initialization */
4663   for (i = 1; i < lvP; i++)
4664   {
4665     long j, l, q, e = 1;
4666     GEN C, Tp, u1, u0;
4667     p = vP[i];
4668     for (j = 1; j < lv; j++) e = maxss(e, z_lval(vn[j], p));
4669     if (!B)
4670       Tp = mfnewmathecke_p(mf, p);
4671     else if (dk == 2)
4672       Tp = mfheckemat_mfcoefs_p2(mf,p, (lvP==2||N%p)? B: matdeflate(sb,p*p,B));
4673     else
4674       Tp = mfheckemat_mfcoefs_p(mf, p, (lvP==2||N%p)? B: matdeflate(sb,p,B));
4675     gel(vT, p) = Tp;
4676     if (e == 1) continue;
4677     u0 = gen_1;
4678     if (dk == 2)
4679     {
4680       C = N % p? gmul(mfchareval(CHI,p*p), powuu(p, nk-2)): NULL;
4681       if (e == 2) u0 = sstoQ(p+1,p); /* special case T_{p^4} */
4682     }
4683     else
4684       C = N % p? gmul(mfchareval(CHI,p),   powuu(p, nk-1)): NULL;
4685     for (u1=Tp, q=p, l=2; l <= e; l++)
4686     { /* u0 = T_{p^{l-2}}, u1 = T_{p^{l-1}} for l > 2 */
4687       GEN v = gmul(Tp, u1);
4688       if (C) v = gsub(v, gmul(C, u0));
4689       /* q = p^l, vT[q] = T_q for k integer else T_{q^2} */
4690       q *= p; u0 = u1; gel(vT, q) = u1 = v;
4691     }
4692   }
4693 END:
4694   /* vT[p^e] = T_{p^e} for all p^e occurring below */
4695   for (i = 1; i < lv; i++)
4696   {
4697     long n = vn[i], j, lP;
4698     GEN fa, P, E, M;
4699     if (n == 0) { gel(res,i) = zeromat(dim,dim); continue; }
4700     if (n == 1) { gel(res,i) = matid(dim); continue; }
4701     fa = gel(FA,i);
4702     P = gel(fa,1); lP = lg(P);
4703     E = gel(fa,2); M = gel(vT, upowuu(P[1], E[1]));
4704     for (j = 2; j < lP; j++) M = RgM_mul(M, gel(vT, upowuu(P[j], E[j])));
4705     gel(res,i) = M;
4706   }
4707   if (flint) res = gel(res,1);
4708   return gerepilecopy(av, res);
4709 }
4710 
4711 /* f = \sum_i v[i] T_listj[i] (Trace Form) attached to v; replace by f/a_1(f) */
4712 static GEN
mf_normalize(GEN mf,GEN v)4713 mf_normalize(GEN mf, GEN v)
4714 {
4715   GEN c, dc = NULL, M = MF_get_M(mf), Mindex = MF_get_Mindex(mf);
4716   v = Q_primpart(v);
4717   c = RgMrow_RgC_mul(M, v, 2); /* a_1(f) */
4718   if (gequal1(c)) return v;
4719   if (typ(c) == t_POL) c = gmodulo(c, mfcharpol(MF_get_CHI(mf)));
4720   if (typ(c) == t_POLMOD && varn(gel(c,1)) == 1 && degpol(gel(c,1)) >= 40
4721                          && Mindex[1] == 2
4722                          && mfcharorder(MF_get_CHI(mf)) <= 2)
4723   { /* normalize using expansion at infinity (small coefficients) */
4724     GEN w, P = gel(c,1), a1 = gel(c,2);
4725     long i, l = lg(Mindex);
4726     w = cgetg(l, t_COL);
4727     gel(w,1) = gen_1;
4728     for (i = 2; i < l; i++)
4729     {
4730       c = liftpol_shallow(RgMrow_RgC_mul(M, v, Mindex[i]));
4731       gel(w,i) = QXQ_div(c, a1, P);
4732     }
4733     /* w = expansion at oo of normalized form */
4734     v = Minv_RgC_mul(MF_get_Minv(mf), Q_remove_denom(w, &dc));
4735     v = gmodulo(v, P); /* back to mfbasis coefficients */
4736   }
4737   else
4738   {
4739     c = ginv(c);
4740     if (typ(c) == t_POLMOD) c = Q_remove_denom(c, &dc);
4741     v = RgC_Rg_mul(v, c);
4742   }
4743   if (dc) v = RgC_Rg_div(v, dc);
4744   return v;
4745 }
4746 static void
pol_red(GEN NF,GEN * pP,GEN * pa,long flag)4747 pol_red(GEN NF, GEN *pP, GEN *pa, long flag)
4748 {
4749   GEN dP, a, P = *pP;
4750   long d = degpol(P);
4751 
4752   *pa = a = pol_x(varn(P));
4753   if (d > 30) return;
4754 
4755   dP = RgX_disc(P);
4756   if (typ(dP) != t_INT)
4757   { dP = gnorm(dP); if (typ(dP) != t_INT) pari_err_BUG("mfnewsplit"); }
4758   if (d == 2 || expi(dP) < 62)
4759   {
4760     if (expi(dP) < 31)
4761       P = NF? rnfpolredabs(NF, P,flag): polredabs0(P,flag);
4762     else
4763       P = NF? rnfpolredbest(NF,P,flag): polredbest(P,flag);
4764     if (flag)
4765     {
4766       a = gel(P,2); if (typ(a) == t_POLMOD) a = gel(a,2);
4767       P = gel(P,1);
4768     }
4769   }
4770   *pP = P;
4771   *pa = a;
4772 }
4773 
4774 /* Diagonalize and normalize. See mfsplit for meaning of flag. */
4775 static GEN
mfspclean(GEN mf,GEN mf0,GEN NF,long ord,GEN simplesp,long flag)4776 mfspclean(GEN mf, GEN mf0, GEN NF, long ord, GEN simplesp, long flag)
4777 {
4778   const long vz = 1;
4779   long i, l = lg(simplesp), dim = MF_get_dim(mf);
4780   GEN res = cgetg(l, t_MAT), pols = cgetg(l, t_VEC);
4781   GEN zeros = (mf == mf0)? NULL: zerocol(dim - MF_get_dim(mf0));
4782   for (i = 1; i < l; i++)
4783   {
4784     GEN ATP = gel(simplesp, i), A = gel(ATP,1), P = gel(ATP,3);
4785     long d = degpol(P);
4786     GEN a, v = (flag && d > flag)? NULL: gel(A,1);
4787     if (d == 1) P = pol_x(vz);
4788     else
4789     {
4790       pol_red(NF, &P, &a, !!v);
4791       if (v)
4792       { /* Mod(a,P) root of charpoly(T), K*gpowers(a) = eigenvector of T */
4793         GEN K, den, M = cgetg(d+1, t_MAT), T = gel(ATP,2);
4794         long j;
4795         T = shallowtrans(T);
4796         gel(M,1) = vec_ei(d,1); /* basis of cyclic vectors */
4797         for (j = 2; j <= d; j++) gel(M,j) = RgM_RgC_mul(T, gel(M,j-1));
4798         M = Q_primpart(M);
4799         K = NF? ZabM_inv(liftpol_shallow(M), nf_get_pol(NF), ord, &den)
4800               : ZM_inv(M,&den);
4801         K = shallowtrans(K);
4802         v = gequalX(a)? pol_x_powers(d, vz): RgXQ_powers(a, d-1, P);
4803         v = gmodulo(RgM_RgC_mul(A, RgM_RgC_mul(K,v)), P);
4804       }
4805     }
4806     if (v)
4807     {
4808       v = mf_normalize(mf0, v); if (zeros) v = shallowconcat(zeros,v);
4809       gel(res,i) = v; if (flag) setlg(res,i+1);
4810     }
4811     else
4812       gel(res,i) = zerocol(dim);
4813     gel(pols,i) = P;
4814   }
4815   return mkvec2(res, pols);
4816 }
4817 
4818 /* return v = v_{X-r}(P), and set Z = P / (X-r)^v */
4819 static long
RgX_valrem_root(GEN P,GEN r,GEN * Z)4820 RgX_valrem_root(GEN P, GEN r, GEN *Z)
4821 {
4822   long v;
4823   for (v = 0; degpol(P); v++)
4824   {
4825     GEN t, Q = RgX_div_by_X_x(P, r, &t);
4826     if (!gequal0(t)) break;
4827     P = Q;
4828   }
4829   *Z = P; return v;
4830 }
4831 static GEN
mynffactor(GEN NF,GEN P,long dimlim)4832 mynffactor(GEN NF, GEN P, long dimlim)
4833 {
4834   long i, l, v;
4835   GEN R, E;
4836   if (dimlim != 1)
4837   {
4838     R = NF? nffactor(NF, P): QX_factor(P);
4839     if (!dimlim) return R;
4840     E = gel(R,2);
4841     R = gel(R,1); l = lg(R);
4842     for (i = 1; i < l; i++)
4843       if (degpol(gel(R,i)) > dimlim) break;
4844     if (i == 1) return NULL;
4845     setlg(E,i);
4846     setlg(R,i); return mkmat2(R, E);
4847   }
4848   /* dimlim = 1 */
4849   R = nfroots(NF, P); l = lg(R);
4850   if (l == 1) return NULL;
4851   v = varn(P);
4852   settyp(R, t_COL);
4853   if (degpol(P) == l-1)
4854     E = const_col(l-1, gen_1);
4855   else
4856   {
4857     E = cgetg(l, t_COL);
4858     for (i = 1; i < l; i++) gel(E,i) = utoi(RgX_valrem_root(P, gel(R,i), &P));
4859   }
4860   R = deg1_from_roots(R, v);
4861   return mkmat2(R, E);
4862 }
4863 
4864 /* Let K be a number field attached to NF (Q if NF = NULL). A K-vector
4865  * space of dimension d > 0 is given by a t_MAT A (n x d, full column rank)
4866  * giving a K-basis, X a section (d x n: left pseudo-inverse of A). Return a
4867  * pair (T, fa), where T is an element of the Hecke algebra (a sum of Tp taken
4868  * from vector vTp) acting on A (a d x d t_MAT) and fa is the factorization of
4869  * its characteristic polynomial, limited to factors of degree <= dimlim if
4870  * dimlim != 0 (return NULL if there are no factors of degree <= dimlim) */
4871 static GEN
findbestsplit(GEN NF,GEN vTp,GEN A,GEN X,long dimlim,long vz)4872 findbestsplit(GEN NF, GEN vTp, GEN A, GEN X, long dimlim, long vz)
4873 {
4874   GEN T = NULL, Tkeep = NULL, fakeep = NULL;
4875   long lmax = 0, i, lT = lg(vTp);
4876   for (i = 1; i < lT; i++)
4877   {
4878     GEN D, P, E, fa, TpA = gel(vTp,i);
4879     long l;
4880     if (typ(TpA) == t_INT) break;
4881     if (lg(TpA) > lg(A)) TpA = RgM_mul(X, RgM_mul(TpA, A)); /* Tp | A */
4882     T = T ? RgM_add(T, TpA) : TpA;
4883     if (!NF) { P = QM_charpoly_ZX(T); setvarn(P, vz); }
4884     else
4885     {
4886       P = charpoly(Q_remove_denom(T, &D), vz);
4887       if (D) P = gdiv(RgX_unscale(P, D), powiu(D, degpol(P)));
4888     }
4889     fa = mynffactor(NF, P, dimlim);
4890     if (!fa) return NULL;
4891     E = gel(fa, 2);
4892     /* characteristic polynomial is separable ? */
4893     if (isint1(vecmax(E))) { Tkeep = T; fakeep = fa; break; }
4894     l = lg(E);
4895     /* characteristic polynomial has more factors than before ? */
4896     if (l > lmax) { lmax = l; Tkeep = T; fakeep = fa; }
4897   }
4898   return mkvec2(Tkeep, fakeep);
4899 }
4900 
4901 static GEN
nfcontent(GEN nf,GEN v)4902 nfcontent(GEN nf, GEN v)
4903 {
4904   long i, l = lg(v);
4905   GEN c = gel(v,1);
4906   for (i = 2; i < l; i++) c = idealadd(nf, c, gel(v,i));
4907   if (typ(c) == t_MAT && gequal1(gcoeff(c,1,1))) c = gen_1;
4908   return c;
4909 }
4910 static GEN
nf_primpart(GEN nf,GEN B)4911 nf_primpart(GEN nf, GEN B)
4912 {
4913   switch(typ(B))
4914   {
4915     case t_COL:
4916     {
4917       GEN A = matalgtobasis(nf, B), c = nfcontent(nf, A);
4918       if (typ(c) == t_INT) return B;
4919       c = idealred_elt(nf,c);
4920       A = Q_primpart( nfC_nf_mul(nf, A, Q_primpart(nfinv(nf,c))) );
4921       A = liftpol_shallow( matbasistoalg(nf, A) );
4922       if (gexpo(A) > gexpo(B)) A = B;
4923       return A;
4924     }
4925     case t_MAT:
4926     {
4927       long i, l;
4928       GEN A = cgetg_copy(B, &l);
4929       for (i = 1; i < l; i++) gel(A,i) = nf_primpart(nf, gel(B,i));
4930       return A;
4931     }
4932     default:
4933       pari_err_TYPE("nf_primpart", B);
4934       return NULL; /*LCOV_EXCL_LINE*/
4935   }
4936 }
4937 
4938 /* rotate entries of v to accomodate new entry 'x' (push out oldest entry) */
4939 static void
vecpush(GEN v,GEN x)4940 vecpush(GEN v, GEN x)
4941 {
4942   long i;
4943   for (i = lg(v)-1; i > 1; i--) gel(v,i) = gel(v,i-1);
4944   gel(v,1) = x;
4945 }
4946 
4947 /* sort t_VEC of vector spaces by increasing dimension */
4948 static GEN
sort_by_dim(GEN v)4949 sort_by_dim(GEN v)
4950 {
4951   long i, l = lg(v);
4952   GEN D = cgetg(l, t_VECSMALL);
4953   for (i = 1; i < l; i++) D[i] = lg(gmael(v,i,2));
4954   return vecpermute(v , vecsmall_indexsort(D));
4955 }
4956 static GEN
split_starting_space(GEN mf)4957 split_starting_space(GEN mf)
4958 {
4959   long d = MF_get_dim(mf), d2;
4960   GEN id = matid(d);
4961   switch(MF_get_space(mf))
4962   {
4963     case mf_NEW:
4964     case mf_CUSP: return mkvec2(id, id);
4965   }
4966   d2 = lg(MF_get_S(mf))-1;
4967   return mkvec2(vecslice(id, d-d2+1,d),
4968                 shallowconcat(zeromat(d2,d-d2),matid(d2)));
4969 }
4970 /* If dimlim > 0, keep only the dimension <= dimlim eigenspaces.
4971  * See mfsplit for the meaning of flag. */
4972 static GEN
split_ii(GEN mf,long dimlim,long flag,long * pnewd)4973 split_ii(GEN mf, long dimlim, long flag, long *pnewd)
4974 {
4975   forprime_t iter;
4976   GEN CHI = MF_get_CHI(mf), empty = cgetg(1, t_VEC), mf0 = mf;
4977   GEN NF, POLCYC, todosp, Tpbigvec, simplesp;
4978   long N = MF_get_N(mf), k = MF_get_k(mf);
4979   long ord, FC, NEWT, dimsimple = 0, newd = -1;
4980   const long NBH = 5, vz = 1;
4981   ulong p;
4982 
4983   switch(MF_get_space(mf))
4984   {
4985     case mf_NEW: break;
4986     case mf_CUSP:
4987     case mf_FULL:
4988       if (k > 1) { mf0 = mfinittonew(mf); break; }
4989       newd = lg(MF_get_S(mf))-1 - mfolddim(N, k, CHI);
4990       break;
4991     default: pari_err_TYPE("mfsplit [space does not contain newspace]", mf);
4992       return NULL; /*LCOV_EXCL_LINE*/
4993   }
4994   if (newd < 0) newd = mf0? MF_get_dim(mf0): 0;
4995   *pnewd = newd;
4996   if (!newd) return mkvec2(cgetg(1, t_MAT), empty);
4997 
4998   NEWT = (k > 1 && MF_get_space(mf0) == mf_NEW);
4999   todosp = mkvec( split_starting_space(mf0) );
5000   simplesp = empty;
5001   FC = mfcharconductor(CHI);
5002   ord = mfcharorder(CHI);
5003   if (ord <= 2) NF = POLCYC = NULL;
5004   else
5005   {
5006     POLCYC = mfcharpol(CHI);
5007     NF = nfinit(POLCYC,DEFAULTPREC);
5008   }
5009   Tpbigvec = zerovec(NBH);
5010   u_forprime_init(&iter, 2, ULONG_MAX);
5011   while (dimsimple < newd && (p = u_forprime_next(&iter)))
5012   {
5013     GEN nextsp;
5014     long ind;
5015     if (N % (p*p) == 0 && N/p % FC == 0) continue; /* T_p = 0 in this case */
5016     vecpush(Tpbigvec, NEWT? mfnewmathecke_p(mf0,p): mfheckemat_p(mf0,p));
5017     nextsp = empty;
5018     for (ind = 1; ind < lg(todosp); ind++)
5019     {
5020       GEN tmp = gel(todosp, ind), fa, P, E, D, Tp, DTp;
5021       GEN A = gel(tmp, 1);
5022       GEN X = gel(tmp, 2);
5023       long lP, i;
5024       tmp = findbestsplit(NF, Tpbigvec, A, X, dimlim, vz);
5025       if (!tmp) continue; /* nothing there */
5026       Tp = gel(tmp, 1);
5027       fa = gel(tmp, 2);
5028       P = gel(fa, 1);
5029       E = gel(fa, 2); lP = lg(P);
5030       /* lP > 1 */
5031       if (DEBUGLEVEL) err_printf("Exponents = %Ps\n", E);
5032       if (lP == 2)
5033       {
5034         GEN P1 = gel(P,1);
5035         long e1 = itos(gel(E,1)), d1 = degpol(P1);
5036         if (e1 * d1 == lg(Tp)-1)
5037         {
5038           if (e1 > 1) nextsp = vec_append(nextsp, mkvec2(A,X));
5039           else
5040           { /* simple module */
5041             simplesp = vec_append(simplesp, mkvec3(A,Tp,P1));
5042             dimsimple += d1;
5043           }
5044           continue;
5045         }
5046       }
5047       /* Found splitting */
5048       DTp = Q_remove_denom(Tp, &D);
5049       for (i = 1; i < lP; i++)
5050       {
5051         GEN Ai, Xi, dXi, AAi, v, y, Pi = gel(P,i);
5052         Ai = RgX_RgM_eval(D? RgX_rescale(Pi,D): Pi, DTp);
5053         Ai = QabM_ker(Ai, POLCYC, ord);
5054         if (NF) Ai = nf_primpart(NF, Ai);
5055 
5056         AAi = RgM_mul(A, Ai);
5057         /* gives section, works on nonsquare matrices */
5058         Xi = QabM_pseudoinv(Ai, POLCYC, ord, &v, &dXi);
5059         Xi = RgM_Rg_div(Xi, dXi);
5060         y = gel(v,1);
5061         if (isint1(gel(E,i)))
5062         {
5063           GEN Tpi = RgM_mul(Xi, RgM_mul(rowpermute(Tp,y), Ai));
5064           simplesp = vec_append(simplesp, mkvec3(AAi, Tpi, Pi));
5065           dimsimple += degpol(Pi);
5066         }
5067         else
5068         {
5069           Xi = RgM_mul(Xi, rowpermute(X,y));
5070           nextsp = vec_append(nextsp, mkvec2(AAi, Xi));
5071         }
5072       }
5073     }
5074     todosp = nextsp; if (lg(todosp) == 1) break;
5075   }
5076   if (DEBUGLEVEL) err_printf("end split, need to clean\n");
5077   return mfspclean(mf, mf0, NF, ord, sort_by_dim(simplesp), flag);
5078 }
5079 static GEN
dim_filter(GEN v,long dim)5080 dim_filter(GEN v, long dim)
5081 {
5082   GEN P = gel(v,2);
5083   long j, l = lg(P);
5084   for (j = 1; j < l; j++)
5085     if (degpol(gel(P,j)) > dim)
5086     {
5087       v = mkvec2(vecslice(gel(v,1),1,j-1), vecslice(P,1,j-1));
5088       break;
5089     }
5090   return v;
5091 }
5092 static long
dim_sum(GEN v)5093 dim_sum(GEN v)
5094 {
5095   GEN P = gel(v,2);
5096   long j, l = lg(P), d = 0;
5097   for (j = 1; j < l; j++) d += degpol(gel(P,j));
5098   return d;
5099 }
5100 static GEN
split_i(GEN mf,long dimlim,long flag)5101 split_i(GEN mf, long dimlim, long flag)
5102 { long junk; return split_ii(mf, dimlim, flag, &junk); }
5103 /* mf is either already split or output by mfinit. Splitting is done only for
5104  * newspace except in weight 1. If flag = 0 (default) split completely.
5105  * If flag = d > 0, only give the Galois polynomials in degree > d
5106  * Flag is ignored if dimlim = 1. */
5107 GEN
mfsplit(GEN mf0,long dimlim,long flag)5108 mfsplit(GEN mf0, long dimlim, long flag)
5109 {
5110   pari_sp av = avma;
5111   GEN v, mf = checkMF_i(mf0);
5112   if (!mf) pari_err_TYPE("mfsplit", mf0);
5113   if ((v = obj_check(mf, MF_SPLIT)))
5114   { if (dimlim) v = dim_filter(v, dimlim); }
5115   else if (dimlim && (v = obj_check(mf, MF_SPLITN)))
5116   { v = (itos(gel(v,1)) >= dimlim)? dim_filter(gel(v,2), dimlim): NULL; }
5117   if (!v)
5118   {
5119     long newd;
5120     v = split_ii(mf, dimlim, flag, &newd);
5121     if (lg(v) == 1) obj_insert(mf, MF_SPLITN, mkvec2(utoi(dimlim), v));
5122     else if (!flag)
5123     {
5124       if (dim_sum(v) == newd) obj_insert(mf, MF_SPLIT,v);
5125       else obj_insert(mf, MF_SPLITN, mkvec2(utoi(dimlim), v));
5126     }
5127   }
5128   return gerepilecopy(av, v);
5129 }
5130 static GEN
split(GEN mf)5131 split(GEN mf) { return split_i(mf,0,0); }
5132 GEN
MF_get_newforms(GEN mf)5133 MF_get_newforms(GEN mf) { return gel(obj_checkbuild(mf,MF_SPLIT,&split),1); }
5134 GEN
MF_get_fields(GEN mf)5135 MF_get_fields(GEN mf) { return gel(obj_checkbuild(mf,MF_SPLIT,&split),2); }
5136 
5137 /*************************************************************************/
5138 /*                     Modular forms of Weight 1                         */
5139 /*************************************************************************/
5140 /* S_1(G_0(N)), small N. Return 1 if definitely empty; return 0 if maybe
5141  * nonempty  */
5142 static int
wt1empty(long N)5143 wt1empty(long N)
5144 {
5145   if (N <= 100) switch (N)
5146   { /* nonempty [32/100] */
5147     case 23: case 31: case 39: case 44: case 46:
5148     case 47: case 52: case 55: case 56: case 57:
5149     case 59: case 62: case 63: case 68: case 69:
5150     case 71: case 72: case 76: case 77: case 78:
5151     case 79: case 80: case 83: case 84: case 87:
5152     case 88: case 92: case 93: case 94: case 95:
5153     case 99: case 100: return 0;
5154     default: return 1;
5155   }
5156   if (N <= 600) switch(N)
5157   { /* empty [111/500] */
5158     case 101: case 102: case 105: case 106: case 109:
5159     case 113: case 121: case 122: case 123: case 125:
5160     case 130: case 134: case 137: case 146: case 149:
5161     case 150: case 153: case 157: case 162: case 163:
5162     case 169: case 170: case 173: case 178: case 181:
5163     case 182: case 185: case 187: case 193: case 194:
5164     case 197: case 202: case 205: case 210: case 218:
5165     case 221: case 226: case 233: case 241: case 242:
5166     case 245: case 246: case 250: case 257: case 265:
5167     case 267: case 269: case 274: case 277: case 281:
5168     case 289: case 293: case 298: case 305: case 306:
5169     case 313: case 314: case 317: case 326: case 337:
5170     case 338: case 346: case 349: case 353: case 361:
5171     case 362: case 365: case 369: case 370: case 373:
5172     case 374: case 377: case 386: case 389: case 394:
5173     case 397: case 401: case 409: case 410: case 421:
5174     case 425: case 427: case 433: case 442: case 449:
5175     case 457: case 461: case 466: case 481: case 482:
5176     case 485: case 490: case 493: case 509: case 514:
5177     case 521: case 530: case 533: case 534: case 538:
5178     case 541: case 545: case 554: case 557: case 562:
5179     case 565: case 569: case 577: case 578: case 586:
5180     case 593: return 1;
5181     default: return 0;
5182   }
5183   return 0;
5184 }
5185 
5186 static GEN
initwt1trace(GEN mf)5187 initwt1trace(GEN mf)
5188 {
5189   GEN S = MF_get_S(mf), v, H;
5190   long l, i;
5191   if (lg(S) == 1) return mftrivial();
5192   H = mfheckemat(mf, Mindex_as_coef(mf));
5193   l = lg(H); v = cgetg(l, t_VEC);
5194   for (i = 1; i < l; i++) gel(v,i) = gtrace(gel(H,i));
5195   v = Minv_RgC_mul(MF_get_Minv(mf), v);
5196   return mflineardiv_linear(S, v, 1);
5197 }
5198 static GEN
initwt1newtrace(GEN mf)5199 initwt1newtrace(GEN mf)
5200 {
5201   GEN v, D, S, Mindex, CHI = MF_get_CHI(mf);
5202   long FC, lD, i, sb, N1, N2, lM, N = MF_get_N(mf);
5203   CHI = mfchartoprimitive(CHI, &FC);
5204   if (N % FC || mfcharparity(CHI) == 1) return mftrivial();
5205   D = mydivisorsu(N/FC); lD = lg(D);
5206   S = MF_get_S(mf);
5207   if (lg(S) == 1) return mftrivial();
5208   N2 = newd_params2(N);
5209   N1 = N / N2;
5210   Mindex = MF_get_Mindex(mf);
5211   lM = lg(Mindex);
5212   sb = Mindex[lM-1];
5213   v = zerovec(sb+1);
5214   for (i = 1; i < lD; i++)
5215   {
5216     long M = FC*D[i], j;
5217     GEN tf = initwt1trace(M == N? mf: mfinit_Nkchi(M, 1, CHI, mf_CUSP, 0));
5218     GEN listd, w;
5219     if (mf_get_type(tf) == t_MF_CONST) continue;
5220     w = mfcoefs_i(tf, sb, 1);
5221     if (M == N) { v = gadd(v, w); continue; }
5222     listd = mydivisorsu(u_ppo(ugcd(N/M, N1), FC));
5223     for (j = 1; j < lg(listd); j++)
5224     {
5225       long d = listd[j], d2 = d*d; /* coprime to FC */
5226       GEN dk = mfchareval(CHI, d);
5227       long NMd = N/(M*d), m;
5228       for (m = 1; m <= sb/d2; m++)
5229       {
5230         long be = mubeta2(NMd, m);
5231         if (be)
5232         {
5233           GEN c = gmul(dk, gmulsg(be, gel(w, m+1)));
5234           long n = m*d2;
5235           gel(v, n+1) = gadd(gel(v, n+1), c);
5236         }
5237       }
5238     }
5239   }
5240   if (gequal0(gel(v,2))) return mftrivial();
5241   v = vecpermute(v,Mindex);
5242   v = Minv_RgC_mul(MF_get_Minv(mf), v);
5243   return mflineardiv_linear(S, v, 1);
5244 }
5245 
5246 /* Matrix of T(p), p \nmid N */
5247 static GEN
Tpmat(long p,long lim,GEN CHI)5248 Tpmat(long p, long lim, GEN CHI)
5249 {
5250   GEN M = zeromatcopy(lim, p*lim), chip = mfchareval(CHI, p); /* != 0 */
5251   long i, j, pi, pj;
5252   gcoeff(M, 1, 1) = gaddsg(1, chip);
5253   for (i = 1, pi = p; i < lim; i++,  pi += p) gcoeff(M, i+1, pi+1) = gen_1;
5254   for (j = 1, pj = p; pj < lim; j++, pj += p) gcoeff(M, pj+1, j+1) = chip;
5255   return M;
5256 }
5257 
5258 /* assume !wt1empty(N), in particular N>25 */
5259 /* Returns [[lim,p], mf (weight 2), p*lim x dim matrix] */
5260 static GEN
mfwt1_pre(long N)5261 mfwt1_pre(long N)
5262 {
5263   GEN M, mf = mfinit_Nkchi(N, 2, mfchartrivial(), mf_CUSP, 0);
5264   /*not empty for N>25*/
5265   long p, lim;
5266   if (uisprime(N))
5267   {
5268     p = 2; /*N>25 is not 2 */
5269     lim = ceilA1(N, 3);
5270   }
5271   else
5272   {
5273     forprime_t S;
5274     u_forprime_init(&S, 2, N);
5275     while ((p = u_forprime_next(&S)))
5276       if (N % p) break;
5277     lim = mfsturm_mf(mf) + 1;
5278   }
5279   /* p = smalllest prime not dividing N */
5280   M = bhnmat_extend_nocache(MF_get_M(mf), N, p*lim-1, 1, MF_get_S(mf));
5281   return mkvec3(mkvecsmall2(lim, p), mf, M);
5282 }
5283 
5284 /* lg(A) > 1, E a t_POL */
5285 static GEN
mfmatsermul(GEN A,GEN E)5286 mfmatsermul(GEN A, GEN E)
5287 {
5288   long j, l = lg(A), r = nbrows(A);
5289   GEN M = cgetg(l, t_MAT);
5290   E = RgXn_red_shallow(E, r+1);
5291   for (j = 1; j < l; j++)
5292   {
5293     GEN c = RgV_to_RgX(gel(A,j), 0);
5294     gel(M, j) = RgX_to_RgC(RgXn_mul(c, E, r+1), r);
5295   }
5296   return M;
5297 }
5298 /* lg(Ap) > 1, Ep an Flxn */
5299 static GEN
mfmatsermul_Fl(GEN Ap,GEN Ep,ulong p)5300 mfmatsermul_Fl(GEN Ap, GEN Ep, ulong p)
5301 {
5302   long j, l = lg(Ap), r = nbrows(Ap);
5303   GEN M = cgetg(l, t_MAT);
5304   for (j = 1; j < l; j++)
5305   {
5306     GEN c = Flv_to_Flx(gel(Ap,j), 0);
5307     gel(M,j) = Flx_to_Flv(Flxn_mul(c, Ep, r+1, p), r);
5308   }
5309   return M;
5310 }
5311 
5312 /* CHI mod F | N, return mfchar of modulus N.
5313  * FIXME: wasteful, G should be precomputed  */
5314 static GEN
mfcharinduce(GEN CHI,long N)5315 mfcharinduce(GEN CHI, long N)
5316 {
5317   GEN G, chi;
5318   if (mfcharmodulus(CHI) == N) return CHI;
5319   G = znstar0(utoipos(N), 1);
5320   chi = zncharinduce(gel(CHI,1), gel(CHI,2), G);
5321   CHI = leafcopy(CHI);
5322   gel(CHI,1) = G;
5323   gel(CHI,2) = chi; return CHI;
5324 }
5325 
5326 static GEN
gmfcharno(GEN CHI)5327 gmfcharno(GEN CHI)
5328 {
5329   GEN G = gel(CHI,1), chi = gel(CHI,2);
5330   return mkintmod(znconreyexp(G, chi), znstar_get_N(G));
5331 }
5332 static long
mfcharno(GEN CHI)5333 mfcharno(GEN CHI)
5334 {
5335   GEN n = znconreyexp(gel(CHI,1), gel(CHI,2));
5336   return itou(n);
5337 }
5338 
5339 /* return k such that minimal mfcharacter in Galois orbit of CHI is CHI^k */
5340 static long
mfconreyminimize(GEN CHI)5341 mfconreyminimize(GEN CHI)
5342 {
5343   GEN G = gel(CHI,1), cyc, chi;
5344   cyc = ZV_to_zv(znstar_get_cyc(G));
5345   chi = ZV_to_zv(znconreychar(G, gel(CHI,2)));
5346   return zv_cyc_minimize(cyc, chi, coprimes_zv(mfcharorder(CHI)));
5347 }
5348 
5349 /* find scalar c such that first nonzero entry of c*v is 1; return c*v
5350  * (set c = NULL for 1) */
5351 static GEN
RgV_normalize(GEN v,GEN * pc)5352 RgV_normalize(GEN v, GEN *pc)
5353 {
5354   long i, l = lg(v);
5355   *pc = NULL;
5356   for (i = 1; i < l; i++)
5357   {
5358     GEN c = gel(v,i);
5359     if (!gequal0(c))
5360     {
5361       if (gequal1(c)) { *pc = gen_1; return v; }
5362       *pc = ginv(c); return RgV_Rg_mul(v, *pc);
5363     }
5364   }
5365   return v;
5366 }
5367 static GEN
mftreatdihedral(GEN DIH,GEN POLCYC,long ordchi,long biglim,GEN * pS)5368 mftreatdihedral(GEN DIH, GEN POLCYC, long ordchi, long biglim, GEN *pS)
5369 {
5370   GEN M, Minv, C;
5371   long l, i;
5372   l = lg(DIH); if (l == 1) return NULL;
5373   if (!pS) return DIH;
5374   C = cgetg(l, t_VEC);
5375   M = cgetg(l, t_MAT);
5376   for (i = 1; i < l; i++)
5377   {
5378     GEN c, v = mfcoefs_i(gel(DIH,i), biglim, 1);
5379     gel(M,i) = RgV_normalize(v, &c);
5380     gel(C,i) = Rg_col_ei(c, l-1, i);
5381   }
5382   Minv = gel(mfclean(M,POLCYC,ordchi,0),2);
5383   M = RgM_Minv_mul(M, Minv);
5384   C = RgM_Minv_mul(C, Minv);
5385   *pS = vecmflinear(DIH, C);
5386   return M;
5387 }
5388 
5389 static GEN
mfstabiter(GEN * pVC,GEN M,GEN A2,GEN E1inv,long lim,GEN P,long ordchi)5390 mfstabiter(GEN *pVC, GEN M, GEN A2, GEN E1inv, long lim, GEN P, long ordchi)
5391 {
5392   GEN A, VC, con;
5393   E1inv = primitive_part(E1inv, &con);
5394   VC = con? ginv(con): gen_1;
5395   A = mfmatsermul(A2, E1inv);
5396   for(;;)
5397   {
5398     GEN R = shallowconcat(RgM_mul(M,A), rowslice(A,1,lim));
5399     GEN B = QabM_ker(R, P, ordchi);
5400     long lA = lg(A), lB = lg(B);
5401     if (lB == 1) return NULL;
5402     if (lB == lA) { *pVC = gmul(*pVC, VC); return A; }
5403     B = rowslice(B, 1, lA-1);
5404     if (ordchi > 2) B = gmodulo(B, P);
5405     A = Q_primitive_part(RgM_mul(A,B), &con);
5406     VC = gmul(VC,B); /* first VC is a scalar, then a RgM */
5407     if (con) VC = RgM_Rg_div(VC, con);
5408   }
5409 }
5410 static long
mfstabitermodp(GEN Mp,GEN Ap,long p,long lim)5411 mfstabitermodp(GEN Mp, GEN Ap, long p, long lim)
5412 {
5413   GEN VC = NULL;
5414   while (1)
5415   {
5416     GEN Rp = shallowconcat(Flm_mul(Mp,Ap,p), rowslice(Ap,1,lim));
5417     GEN Bp = Flm_ker(Rp, p);
5418     long lA = lg(Ap), lB = lg(Bp);
5419     if (lB == 1) return 0;
5420     if (lB == lA) return lA-1;
5421     Bp = rowslice(Bp, 1, lA-1);
5422     Ap = Flm_mul(Ap, Bp, p);
5423     VC = VC? Flm_mul(VC, Bp, p): Bp;
5424   }
5425 }
5426 
5427 static GEN
mfintereis(GEN * pVC,GEN A,GEN M2,GEN y,GEN den,GEN E2,GEN P,long ordchi)5428 mfintereis(GEN *pVC, GEN A, GEN M2, GEN y, GEN den, GEN E2, GEN P, long ordchi)
5429 {
5430   GEN z, M1 = mfmatsermul(A,E2), M1den = isint1(den)? M1: RgM_Rg_mul(M1,den);
5431   M2 = RgM_mul(M2, rowpermute(M1, y));
5432   z = QabM_ker(RgM_sub(M2,M1den), P, ordchi);
5433   if (lg(z) == 1) return NULL;
5434   if (ordchi > 2) z = gmodulo(z, P);
5435   *pVC = typ(*pVC) == t_INT? z: RgM_mul(*pVC, z);
5436   return RgM_mul(A,z);
5437 }
5438 static GEN
mfintereismodp(GEN * pVC,GEN A,GEN M2,GEN E2,long dih,ulong p)5439 mfintereismodp(GEN *pVC, GEN A, GEN M2, GEN E2, long dih, ulong p)
5440 {
5441   GEN M1 = mfmatsermul_Fl(A, E2, p), z;
5442   long j, lx = lg(A);
5443   z = Flm_ker(shallowconcat(M1, M2), p);
5444   j = lg(z) - 1; if (j == dih) return NULL;
5445   for (; j; j--) setlg(z[j], lx);
5446   *pVC = *pVC? Flm_mul(*pVC, z, p): z;
5447   return Flm_mul(A,z,p);
5448 }
5449 
5450 static GEN
mfcharinv_i(GEN CHI)5451 mfcharinv_i(GEN CHI)
5452 {
5453   GEN G = gel(CHI,1);
5454   CHI = leafcopy(CHI); gel(CHI,2) =  zncharconj(G, gel(CHI,2)); return CHI;
5455 }
5456 
5457 /* upper bound dim S_1(Gamma_0(N),chi) performing the linear algebra mod p */
5458 static long
mfwt1dimmodp(GEN A,GEN ES,GEN M,long ordchi,long dih,long lim)5459 mfwt1dimmodp(GEN A, GEN ES, GEN M, long ordchi, long dih, long lim)
5460 {
5461   GEN Ap, ES1p, VC;
5462   ulong p, r = QabM_init(ordchi, &p);
5463 
5464   Ap = QabM_to_Flm(A, r, p);
5465   VC = NULL;
5466   ES1p = QabX_to_Flx(gel(ES,1), r, p);
5467   if (lg(ES) >= 3)
5468   {
5469     GEN M2 = mfmatsermul_Fl(Ap, ES1p, p);
5470     pari_sp av = avma;
5471     long i;
5472     for (i = 2; i < lg(ES); i++)
5473     {
5474       GEN ESip = QabX_to_Flx(gel(ES,i), r, p);
5475       Ap = mfintereismodp(&VC, Ap, M2, ESip, dih, p);
5476       if (!Ap) return dih;
5477       gerepileall(av, 2, &Ap,&VC);
5478     }
5479   }
5480   /* intersection of Eisenstein series quotients non empty: use Schaeffer */
5481   Ap = mfmatsermul_Fl(Ap, Flxn_inv(ES1p,nbrows(Ap),p), p);
5482   return mfstabitermodp(QabM_to_Flm(M,r,p), Ap, p, lim);
5483 }
5484 
5485 /* Compute the full S_1(\G_0(N),\chi). If pS is NULL, only the dimension
5486  * dim, in the form of a vector having dim components. Otherwise output
5487  * a basis: ptvf contains a pointer to the vector of forms, and the
5488  * program returns the corresponding matrix of Fourier expansions.
5489  * ptdimdih gives the dimension of the subspace generated by dihedral forms;
5490  * TMP is from mfwt1_pre or NULL. */
5491 static GEN
mfwt1basis(long N,GEN CHI,GEN TMP,GEN * pS,long * ptdimdih)5492 mfwt1basis(long N, GEN CHI, GEN TMP, GEN *pS, long *ptdimdih)
5493 {
5494   GEN ES, E, mf, A, M, Tp, den, VC, C, POLCYC, ES1, ES1INV, DIH, a0, a0i;
5495   long plim, lim, biglim, i, p, dA, dimp, ordchi, dih;
5496 
5497   if (ptdimdih) *ptdimdih = 0;
5498   if (pS) *pS = NULL;
5499   if (wt1empty(N) || mfcharparity(CHI) != -1) return NULL;
5500   ordchi = mfcharorder(CHI);
5501   if (uisprime(N) && ordchi > 4) return NULL;
5502   if (!pS)
5503   {
5504     dih = mfdihedralcuspdim(N, CHI);
5505     DIH = zerovec(dih);
5506   }
5507   else
5508   {
5509     DIH = mfdihedralcusp(N, CHI);
5510     dih = lg(DIH) - 1;
5511   }
5512   POLCYC = (ordchi <= 2)? NULL: mfcharpol(CHI);
5513   if (ptdimdih) *ptdimdih = dih;
5514   biglim = mfsturmNk(N, 2);
5515   if (N <= 600) switch(N)
5516   {
5517     long m;
5518     case 219: case 273: case 283: case 331: case 333: case 344: case 416:
5519     case 438: case 468: case 491: case 504: case 546: case 553: case 563:
5520     case 566: case 581: case 592:
5521       break; /* one chi with both exotic and dihedral forms */
5522     default: /* only dihedral forms */
5523       if (!dih) return NULL;
5524       /* fall through */
5525     case 124: case 133: case 148: case 171: case 201: case 209: case 224:
5526     case 229: case 248: case 261: case 266: case 288: case 296: case 301:
5527     case 309: case 325: case 342: case 371: case 372: case 380: case 399:
5528     case 402: case 403: case 404: case 408: case 418: case 432: case 444:
5529     case 448: case 451: case 453: case 458: case 496: case 497: case 513:
5530     case 522: case 527: case 532: case 576: case 579:
5531       /* no chi with both exotic and dihedral; one chi with exotic forms */
5532       if (dih) return mftreatdihedral(DIH, POLCYC, ordchi, biglim, pS);
5533       m = mfcharno(mfcharinduce(CHI,N));
5534       if (N == 124 && (m != 67 && m != 87)) return NULL;
5535       if (N == 133 && (m != 83 && m !=125)) return NULL;
5536       if (N == 148 && (m !=105 && m !=117)) return NULL;
5537       if (N == 171 && (m != 94 && m !=151)) return NULL;
5538       if (N == 201 && (m != 29 && m !=104)) return NULL;
5539       if (N == 209 && (m != 87 && m !=197)) return NULL;
5540       if (N == 224 && (m != 95 && m !=191)) return NULL;
5541       if (N == 229 && (m !=107 && m !=122)) return NULL;
5542       if (N == 248 && (m != 87 && m !=191)) return NULL;
5543       if (N == 261 && (m != 46 && m !=244)) return NULL;
5544       if (N == 266 && (m != 83 && m !=125)) return NULL;
5545       if (N == 288 && (m != 31 && m !=223)) return NULL;
5546       if (N == 296 && (m !=105 && m !=265)) return NULL;
5547   }
5548   if (!TMP) TMP = mfwt1_pre(N);
5549   lim = gel(TMP,1)[1]; p = gel(TMP,1)[2]; plim = p*lim;
5550   mf  = gel(TMP,2);
5551   A   = gel(TMP,3); /* p*lim x dim matrix */
5552   E = mfeisensteinbasis(N, 1, mfcharinv_i(CHI));
5553   ES = RgM_to_RgXV(mfvectomat(E, plim+1, 1), 0);
5554   Tp = Tpmat(p, lim, CHI);
5555   dimp = mfwt1dimmodp(A, ES, Tp, ordchi, dih, lim);
5556   if (!dimp) return NULL;
5557   if (dimp == dih) return mftreatdihedral(DIH, POLCYC, ordchi, biglim, pS);
5558   VC = gen_1; ES1 = gel(ES,1); /* does not vanish at oo */
5559   if (lg(ES) > 2)
5560   {
5561     pari_sp btop;
5562     GEN Ar = rowslice(A, 1, (3*lim)/2 + 1), M2 = mfmatsermul(Ar, ES1);
5563     GEN v, y, M2M2I, M2I;
5564     M2I = QabM_pseudoinv(M2, POLCYC, ordchi, &v, &den);
5565     M2M2I = RgM_mul(M2,M2I);
5566     y = gel(v,1); btop = avma;
5567     for (i = 2; i < lg(ES); i++)
5568     {
5569       Ar = mfintereis(&VC, Ar, M2M2I, y, den, gel(ES,i), POLCYC,ordchi);
5570       if (!Ar) return NULL;
5571       if (gc_needed(btop, 1))
5572       {
5573         if (DEBUGMEM > 1) pari_warn(warnmem,"mfwt1basis i = %ld", i);
5574         gerepileall(btop, 2, &Ar, &VC);
5575       }
5576     }
5577     A = RgM_mul(A, vecslice(VC,1, lg(Ar)-1));
5578   }
5579   a0 = gel(ES1,2); /* nonzero */
5580   if (gequal1(a0)) a0 = a0i = NULL;
5581   else
5582   {
5583     a0i = ginv(a0);
5584     ES1 = RgX_Rg_mul(RgX_unscale(ES1,a0), a0i);
5585   }
5586   ES1INV = RgXn_inv(ES1, plim-1);
5587   if (a0) ES1INV = RgX_Rg_mul(RgX_unscale(ES1INV, a0i), a0i);
5588   A = mfstabiter(&VC, Tp, A, ES1INV, lim, POLCYC, ordchi);
5589   if (!A) return NULL;
5590   dA = lg(A);
5591   C = cgetg(dA, t_VEC);
5592   M = cgetg(dA, t_MAT);
5593   for (i = 1; i < dA; i++)
5594   {
5595     GEN c, v = gel(A,i);
5596     gel(M,i) = RgV_normalize(v, &c);
5597     gel(C,i) = RgC_Rg_mul(gel(VC,i), c);
5598   }
5599   if (pS)
5600   {
5601     GEN Minv = gel(mfclean(M, POLCYC, ordchi, 0), 2);
5602     M = RgM_Minv_mul(M, Minv);
5603     C = RgM_Minv_mul(C, Minv);
5604     *pS = vecmflineardiv0(MF_get_S(mf), C, gel(E,1));
5605   }
5606   return M;
5607 }
5608 
5609 static void
MF_set_space(GEN mf,long x)5610 MF_set_space(GEN mf, long x) { gmael(mf,1,4) = utoi(x); }
5611 static GEN
mfwt1_cusptonew(GEN mf)5612 mfwt1_cusptonew(GEN mf)
5613 {
5614   const long vy = 1;
5615   GEN vP, F, S, Snew, vF, v = split(mf);
5616   long i, lP, dSnew, ct;
5617 
5618   F = gel(v,1);
5619   vP= gel(v,2); lP = lg(vP);
5620   if (lP == 1) { obj_insert(mf, MF_SPLIT, v); return NULL; }
5621   MF_set_space(mf, mf_NEW);
5622   S = MF_get_S(mf);
5623   dSnew = dim_sum(v);
5624   Snew = cgetg(dSnew + 1, t_VEC); ct = 0;
5625   vF = cgetg(lP, t_MAT);
5626   for (i = 1; i < lP; i++)
5627   {
5628     GEN V, P = gel(vP,i), f = liftpol_shallow(gel(F,i));
5629     long j, d = degpol(P);
5630     gel(vF,i) = V = zerocol(dSnew);
5631     if (d == 1)
5632     {
5633       gel(Snew, ct+1) = mflineardiv_linear(S, f, 0);
5634       gel(V, ct+1) = gen_1;
5635     }
5636     else
5637     {
5638       f = RgXV_to_RgM(f,d);
5639       for (j = 1; j <= d; j++)
5640       {
5641         gel(Snew, ct+j) = mflineardiv_linear(S, row(f,j), 0);
5642         gel(V, ct+j) = mkpolmod(pol_xn(j-1,vy), P);
5643       }
5644     }
5645     ct += d;
5646   }
5647   obj_insert(mf, MF_SPLIT, mkvec2(vF, vP));
5648   gel(mf,3) = Snew; return mf;
5649 }
5650 static GEN
mfwt1init(long N,GEN CHI,GEN TMP,long space,long flraw)5651 mfwt1init(long N, GEN CHI, GEN TMP, long space, long flraw)
5652 {
5653   GEN mf, mf1, S, M = mfwt1basis(N, CHI, TMP, &S, NULL);
5654   if (!M) return NULL;
5655   mf1 = mkvec4(stoi(N), gen_1, CHI, utoi(mf_CUSP));
5656   mf = mkmf(mf1, cgetg(1,t_VEC), S, gen_0, NULL);
5657   if (space == mf_NEW)
5658   {
5659     gel(mf,5) = mfcleanCHI(M,CHI, 0);
5660     mf = mfwt1_cusptonew(mf); if (!mf) return NULL;
5661     if (!flraw) M = mfcoefs_mf(mf, mfsturmNk(N,1)+1, 1);
5662   }
5663   gel(mf,5) = flraw? zerovec(3): mfcleanCHI(M, CHI, 0);
5664   return mf;
5665 }
5666 
5667 static GEN
mfEMPTY(GEN mf1)5668 mfEMPTY(GEN mf1)
5669 {
5670   GEN Minv = mkMinv(cgetg(1,t_MAT), NULL,NULL,NULL);
5671   GEN M = mkvec3(cgetg(1,t_VECSMALL), Minv, cgetg(1,t_MAT));
5672   return mkmf(mf1, cgetg(1,t_VEC), cgetg(1,t_VEC), cgetg(1,t_VEC), M);
5673 }
5674 static GEN
mfEMPTYall(long N,GEN gk,GEN vCHI,long space)5675 mfEMPTYall(long N, GEN gk, GEN vCHI, long space)
5676 {
5677   long i, l;
5678   GEN v, gN, gs;
5679   if (!vCHI) return cgetg(1, t_VEC);
5680   gN = utoipos(N); gs = utoi(space);
5681   l = lg(vCHI); v = cgetg(l, t_VEC);
5682   for (i = 1; i < l; i++) gel(v,i) = mfEMPTY(mkvec4(gN,gk,gel(vCHI,i),gs));
5683   return v;
5684 }
5685 
5686 static GEN
fmt_dim(GEN CHI,long d,long dih)5687 fmt_dim(GEN CHI, long d, long dih)
5688 { return mkvec4(gmfcharorder(CHI), gmfcharno(CHI), utoi(d), stoi(dih)); }
5689 /* merge two vector of fmt_dim's for the same vector of characters. If CHI
5690  * is not NULL, remove dim-0 spaces and add character from CHI */
5691 static GEN
merge_dims(GEN V,GEN W,GEN CHI)5692 merge_dims(GEN V, GEN W, GEN CHI)
5693 {
5694   long i, j, id, l = lg(V);
5695   GEN A = cgetg(l, t_VEC);
5696   if (l == 1) return A;
5697   id = CHI? 1: 3;
5698   for (i = j = 1; i < l; i++)
5699   {
5700     GEN v = gel(V,i), w = gel(W,i);
5701     long dv = itou(gel(v,id)), dvh = itou(gel(v,id+1)), d;
5702     long dw = itou(gel(w,id)), dwh = itou(gel(w,id+1));
5703     d = dv + dw;
5704     if (d || CHI)
5705       gel(A,j++) = CHI? fmt_dim(gel(CHI,i),d, dvh+dwh)
5706                       : mkvec2s(d,dvh+dwh);
5707   }
5708   setlg(A, j); return A;
5709 }
5710 static GEN
mfdim0all(GEN w)5711 mfdim0all(GEN w)
5712 {
5713   if (w) retconst_vec(lg(w)-1, zerovec(2));
5714   return cgetg(1,t_VEC);
5715 }
5716 static long
mfwt1cuspdim_i(long N,GEN CHI,GEN TMP,long * dih)5717 mfwt1cuspdim_i(long N, GEN CHI, GEN TMP, long *dih)
5718 {
5719   pari_sp av = avma;
5720   GEN b = mfwt1basis(N, CHI, TMP, NULL, dih);
5721   return gc_long(av, b? lg(b)-1: 0);
5722 }
5723 static long
mfwt1cuspdim(long N,GEN CHI)5724 mfwt1cuspdim(long N, GEN CHI) { return mfwt1cuspdim_i(N, CHI, NULL, NULL); }
5725 static GEN
mfwt1cuspdimall(long N,GEN vCHI)5726 mfwt1cuspdimall(long N, GEN vCHI)
5727 {
5728   GEN z, TMP, w;
5729   long i, j, l;
5730   if (wt1empty(N)) return mfdim0all(vCHI);
5731   w = mfwt1chars(N,vCHI);
5732   l = lg(w); if (l == 1) return cgetg(1,t_VEC);
5733   z = cgetg(l, t_VEC);
5734   TMP = mfwt1_pre(N);
5735   for (i = j = 1; i < l; i++)
5736   {
5737     GEN CHI = gel(w,i);
5738     long dih, d = mfwt1cuspdim_i(N, CHI, TMP, &dih);
5739     if (vCHI)
5740       gel(z,j++) = mkvec2s(d, dih);
5741     else if (d)
5742       gel(z,j++) = fmt_dim(CHI, d, dih);
5743   }
5744   setlg(z,j); return z;
5745 }
5746 
5747 /* dimension of S_1(Gamma_1(N)) */
5748 static long
mfwt1cuspdimsum(long N)5749 mfwt1cuspdimsum(long N)
5750 {
5751   pari_sp av = avma;
5752   GEN v = mfwt1cuspdimall(N, NULL);
5753   long i, ct = 0, l = lg(v);
5754   for (i = 1; i < l; i++)
5755   {
5756     GEN w = gel(v,i); /* [ord(CHI),*,dim,*] */
5757     ct += itou(gel(w,3))*myeulerphiu(itou(gel(w,1)));
5758   }
5759   return gc_long(av,ct);
5760 }
5761 
5762 static GEN
mfwt1newdimall(long N,GEN vCHI)5763 mfwt1newdimall(long N, GEN vCHI)
5764 {
5765   GEN z, w, vTMP, fa, P, E;
5766   long i, c, l, lw, P1;
5767   if (wt1empty(N)) return mfdim0all(vCHI);
5768   w = mfwt1chars(N,vCHI);
5769   lw = lg(w); if (lw == 1) return cgetg(1,t_VEC);
5770   vTMP = const_vec(N, NULL);
5771   gel(vTMP,N) = mfwt1_pre(N);
5772   /* if p || N and p \nmid F(CHI), S_1^new(G0(N),chi) = 0 */
5773   fa = znstar_get_faN(gmael(w,1,1));
5774   P = gel(fa,1); l = lg(P);
5775   E = gel(fa,2);
5776   for (i = P1 = 1; i < l; i++)
5777     if (E[i] == 1) P1 *= itou(gel(P,i));
5778   /* P1 = \prod_{v_p(N) = 1} p */
5779   z = cgetg(lw, t_VEC);
5780   for (i = c = 1; i < lw; i++)
5781   {
5782     long S, j, l, F, dihnew;
5783     GEN D, CHI = gel(w,i), CHIP = mfchartoprimitive(CHI,&F);
5784 
5785     S = F % P1? 0: mfwt1cuspdim_i(N, CHI, gel(vTMP,N), &dihnew);
5786     if (!S)
5787     {
5788       if (vCHI) gel(z, c++) = zerovec(2);
5789       continue;
5790     }
5791     D = mydivisorsu(N/F); l = lg(D);
5792     for (j = l-2; j > 0; j--) /* skip last M = N */
5793     {
5794       long M = D[j]*F, m, s, dih;
5795       GEN TMP = gel(vTMP,M);
5796       if (wt1empty(M) || !(m = mubeta(D[l-j]))) continue; /*m = mubeta(N/M)*/
5797       if (!TMP) gel(vTMP,M) = TMP = mfwt1_pre(M);
5798       s = mfwt1cuspdim_i(M, CHIP, TMP, &dih);
5799       if (s) { S += m * s; dihnew += m * dih; }
5800     }
5801     if (vCHI)
5802       gel(z,c++) = mkvec2s(S, dihnew);
5803     else if (S)
5804       gel(z, c++) = fmt_dim(CHI, S, dihnew);
5805   }
5806   setlg(z,c); return z;
5807 }
5808 
5809 static GEN
mfwt1olddimall(long N,GEN vCHI)5810 mfwt1olddimall(long N, GEN vCHI)
5811 {
5812   long i, j, l;
5813   GEN z, w;
5814   if (wt1empty(N)) return mfdim0all(vCHI);
5815   w = mfwt1chars(N,vCHI);
5816   l = lg(w); z = cgetg(l, t_VEC);
5817   for (i = j = 1; i < l; i++)
5818   {
5819     GEN CHI = gel(w,i);
5820     long d = mfolddim(N, 1, CHI);
5821     if (vCHI)
5822       gel(z,j++) = mkvec2s(d,d?-1:0);
5823     else if (d)
5824       gel(z, j++) = fmt_dim(CHI, d, -1);
5825   }
5826   setlg(z,j); return z;
5827 }
5828 
5829 static long
mfwt1olddimsum(long N)5830 mfwt1olddimsum(long N)
5831 {
5832   GEN D;
5833   long N2, i, l, S = 0;
5834   newd_params(N, &N2); /* will ensure mubeta != 0 */
5835   D = mydivisorsu(N/N2); l = lg(D);
5836   for (i = 2; i < l; i++)
5837   {
5838     long M = D[l-i]*N2, d = mfwt1cuspdimsum(M);
5839     if (d) S -= mubeta(D[i]) * d;
5840   }
5841   return S;
5842 }
5843 static long
mfwt1newdimsum(long N)5844 mfwt1newdimsum(long N)
5845 {
5846   long S = mfwt1cuspdimsum(N);
5847   return S? S - mfwt1olddimsum(N): 0;
5848 }
5849 
5850 /* return the automorphism of a degree-2 nf */
5851 static GEN
nf2_get_conj(GEN nf)5852 nf2_get_conj(GEN nf)
5853 {
5854   GEN pol = nf_get_pol(nf);
5855   return deg1pol_shallow(gen_m1, negi(gel(pol,3)), varn(pol));
5856 }
5857 static int
foo_stable(GEN foo)5858 foo_stable(GEN foo)
5859 { return lg(foo) != 3 || equalii(gel(foo,1), gel(foo,2)); }
5860 
5861 static long
mfisdihedral(GEN vF,GEN DIH)5862 mfisdihedral(GEN vF, GEN DIH)
5863 {
5864   GEN vG = gel(DIH,1), M = gel(DIH,2), v, G, bnr, w, gen, D, f, nf, tau;
5865   GEN bnr0 = NULL, f0, f0b, xin, foo;
5866   long i, l, e, j, L, n;
5867   if (lg(M) == 1) return 0;
5868   v = RgM_RgC_invimage(M, vF);
5869   if (!v) return 0;
5870   l = lg(v);
5871   for (i = 1; i < l; i++)
5872     if (!gequal0(gel(v,i))) break;
5873   if (i == l) return 0;
5874   G = gel(vG,i);
5875   bnr = gel(G,2); D = cyc_get_expo(bnr_get_cyc(bnr));
5876   w = gel(G,3);
5877   f = bnr_get_mod(bnr);
5878   nf = bnr_get_nf(bnr);
5879   tau = nf2_get_conj(nf);
5880   f0 = gel(f,1); foo = gel(f,2);
5881   f0b = galoisapply(nf, tau, f0);
5882   xin = zv_to_ZV(gel(w,2)); /* xi(bnr.gen[i]) = e(xin[i] / D) */
5883   if (!foo_stable(foo)) { foo = mkvec2(gen_1, gen_1); bnr0 = bnr; }
5884   if (!gequal(f0, f0b))
5885   {
5886     f0 = idealmul(nf, f0, idealdivexact(nf, f0b, idealadd(nf, f0, f0b)));
5887     bnr0 = bnr;
5888   }
5889   if (bnr0)
5890   { /* conductor not ambiguous */
5891     GEN S;
5892     bnr = Buchray(bnr_get_bnf(bnr), mkvec2(f0, foo), nf_INIT | nf_GEN);
5893     S = bnrsurjection(bnr, bnr0);
5894     xin = FpV_red(RgV_RgM_mul(xin, gel(S,1)), D);
5895     /* still xi(gen[i]) = e(xin[i] / D), for the new generators; D stays
5896      * the same, not exponent(bnr.cyc) ! */
5897   }
5898   gen = bnr_get_gen(bnr); L = lg(gen);
5899   for (j = 1, e = itou(D); j < L; j++)
5900   {
5901     GEN Ng = idealnorm(nf, gel(gen,j));
5902     GEN a = shifti(gel(xin,j), 1); /* xi(g_j^2) = e(a/D) */
5903     GEN b = FpV_dotproduct(xin, isprincipalray(bnr,Ng), D);
5904     GEN m = Fp_sub(a, b, D); /* xi(g_j/g_j^\tau) = e(m/D) */
5905     e = ugcd(e, itou(m)); if (e == 1) break;
5906   }
5907   n = itou(D) / e;
5908   return n == 1? 4: 2*n;
5909 }
5910 
5911 static ulong
myradicalu(ulong n)5912 myradicalu(ulong n) { return zv_prod(gel(myfactoru(n),1)); }
5913 
5914 /* list of fundamental discriminants unramified outside N, with sign s
5915  * [s = 0 => no sign condition] */
5916 static GEN
mfunram(long N,long s)5917 mfunram(long N, long s)
5918 {
5919   long cN = myradicalu(N >> vals(N)), p = 1, m = 1, l, c, i;
5920   GEN D = mydivisorsu(cN), res;
5921   l = lg(D);
5922   if (s == 1) m = 0; else if (s == -1) p = 0;
5923   res = cgetg(6*l - 5, t_VECSMALL);
5924   c = 1;
5925   if (!odd(N))
5926   { /* d = 1 */
5927     if (p) res[c++] = 8;
5928     if (m) { res[c++] =-8; res[c++] =-4; }
5929   }
5930   for (i = 2; i < l; i++)
5931   { /* skip d = 1, done above */
5932     long d = D[i], d4 = d & 3L; /* d odd, squarefree, d4 = 1 or 3 */
5933     if (d4 == 1) { if (p) res[c++] = d; }
5934     else         { if (m) res[c++] =-d; }
5935     if (!odd(N))
5936     {
5937       if (p) { res[c++] = 8*d; if (d4 == 3) res[c++] = 4*d; }
5938       if (m) { res[c++] =-8*d; if (d4 == 1) res[c++] =-4*d; }
5939     }
5940   }
5941   setlg(res, c); return res;
5942 }
5943 
5944 /* Return 1 if F is definitely not S4 type; return 0 on failure. */
5945 static long
mfisnotS4(long N,GEN w)5946 mfisnotS4(long N, GEN w)
5947 {
5948   GEN D = mfunram(N, 0);
5949   long i, lD = lg(D), lw = lg(w);
5950   for (i = 1; i < lD; i++)
5951   {
5952     long p, d = D[i], ok = 0;
5953     for (p = 2; p < lw; p++)
5954       if (w[p] && kross(d,p) == -1) { ok = 1; break; }
5955     if (!ok) return 0;
5956   }
5957   return 1;
5958 }
5959 
5960 /* Return 1 if Q(sqrt(5)) \not\subset Q(F), i.e. F is definitely not A5 type;
5961  * return 0 on failure. */
5962 static long
mfisnotA5(GEN F)5963 mfisnotA5(GEN F)
5964 {
5965   GEN CHI = mf_get_CHI(F), P = mfcharpol(CHI), T, Q;
5966 
5967   if (mfcharorder(CHI) % 5 == 0) return 0;
5968   T = mf_get_field(F); if (degpol(T) == 1) return 1;
5969   if (degpol(P) > 1) T = rnfequation(P,T);
5970   Q = gsubgs(pol_xn(2,varn(T)), 5);
5971   return (typ(nfisincl(Q, T)) == t_INT);
5972 }
5973 
5974 /* v[p+1]^2 / chi(p) - 2 = z + 1/z with z primitive root of unity of order n,
5975  * return n */
5976 static long
mffindrootof1(GEN v,long p,GEN CHI)5977 mffindrootof1(GEN v, long p, GEN CHI)
5978 {
5979   GEN ap = gel(v,p+1), u0, u1, u1k, u2;
5980   long c = 1;
5981   if (gequal0(ap)) return 2;
5982   u0 = gen_2; u1k = u1 = gsubgs(gdiv(gsqr(ap), mfchareval(CHI, p)), 2);
5983   while (!gequalsg(2, liftpol_shallow(u1))) /* u1 = z^c + z^-c */
5984   {
5985     u2 = gsub(gmul(u1k, u1), u0);
5986     u0 = u1; u1 = u2; c++;
5987   }
5988   return c;
5989 }
5990 
5991 /* we known that F is not dihedral */
5992 static long
mfgaloistype_i(long N,GEN CHI,GEN F,GEN v)5993 mfgaloistype_i(long N, GEN CHI, GEN F, GEN v)
5994 {
5995   forprime_t iter;
5996   long lim = lg(v)-2;
5997   GEN w = zero_zv(lim);
5998   pari_sp av;
5999   ulong p;
6000   u_forprime_init(&iter, 2, lim);
6001   av = avma;
6002   while((p = u_forprime_next(&iter))) if (N%p) switch(mffindrootof1(v, p, CHI))
6003   {
6004     case 1: case 2: continue;
6005     case 3: w[p] = 1; break;
6006     case 4: return -24; /* S4 */
6007     case 5: return -60; /* A5 */
6008     default: pari_err_DOMAIN("mfgaloistype", "form", "not a",
6009                              strtoGENstr("cuspidal eigenform"), F);
6010     set_avma(av);
6011   }
6012   if (mfisnotS4(N,w) && mfisnotA5(F)) return -12; /* A4 */
6013   return 0; /* FAILURE */
6014 }
6015 
6016 static GEN
mfgaloistype0(long N,GEN CHI,GEN F,GEN DIH,long lim)6017 mfgaloistype0(long N, GEN CHI, GEN F, GEN DIH, long lim)
6018 {
6019   pari_sp av = avma;
6020   GEN vF = mftocol(F, lim, 1);
6021   long t = mfisdihedral(vF, DIH), bound;
6022   if (t) { set_avma(av); return stoi(t); }
6023   bound = maxss(200, 5*expu(N)*expu(N));
6024   for(;;)
6025   {
6026     t = mfgaloistype_i(N, CHI, F, vF);
6027     set_avma(av); if (t) return stoi(t);
6028     if (lim > bound) return gen_0;
6029     lim += lim >> 1;
6030     vF = mfcoefs_i(F,lim,1);
6031   }
6032 }
6033 
6034 /* If f is NULL, give all the galoistypes, otherwise just for f */
6035 /* May return 0 as a type if failed to determine; in this case the type is
6036  * either -12 or -60, most likely -12. FIXME using the Galois representation. */
6037 GEN
mfgaloistype(GEN NK,GEN f)6038 mfgaloistype(GEN NK, GEN f)
6039 {
6040   pari_sp av = avma;
6041   GEN CHI, T, F, DIH, mf = checkMF_i(NK);
6042   long N, k, lL, i, lim, SB;
6043 
6044   if (f && !checkmf_i(f)) pari_err_TYPE("mfgaloistype", f);
6045   if (mf)
6046   {
6047     N = MF_get_N(mf);
6048     k = MF_get_k(mf);
6049     CHI = MF_get_CHI(mf);
6050   }
6051   else
6052   {
6053     checkNK(NK, &N, &k, &CHI, 0);
6054     mf = f? NULL: mfinit_i(NK, mf_NEW);
6055   }
6056   if (k != 1) pari_err_DOMAIN("mfgaloistype", "k", "!=", gen_1, stoi(k));
6057   SB = mf? mfsturm_mf(mf): mfsturmNk(N,1);
6058   DIH = mfdihedralnew(N,CHI);
6059   lim = lg(DIH) == 1? 200: SB;
6060   DIH = mkvec2(DIH, mfvectomat(DIH,SB,1));
6061   if (f) return gerepileuptoint(av, mfgaloistype0(N,CHI, f, DIH, lim));
6062   F = mfeigenbasis(mf); lL = lg(F);
6063   T = cgetg(lL, t_VEC);
6064   for (i=1; i < lL; i++) gel(T,i) = mfgaloistype0(N, CHI, gel(F,i), DIH, lim);
6065   return gerepileupto(av, T);
6066 }
6067 
6068 /******************************************************************/
6069 /*                   Find all dihedral forms.                     */
6070 /******************************************************************/
6071 /* lim >= 2 */
6072 static void
consttabdihedral(long lim)6073 consttabdihedral(long lim)
6074 { cache_set(cache_DIH, mfdihedralall(mkvecsmall2(1,lim))); }
6075 
6076 /* a ideal coprime to bnr modulus */
6077 static long
mfdiheval(GEN bnr,GEN w,GEN a)6078 mfdiheval(GEN bnr, GEN w, GEN a)
6079 {
6080   GEN L, cycn = gel(w,1), chin = gel(w,2);
6081   long ordmax = cycn[1];
6082   L = ZV_to_Flv(isprincipalray(bnr,a), ordmax);
6083   return Flv_dotproduct(chin, L, ordmax);
6084 }
6085 
6086 /* A(x^k) mod T */
6087 static GEN
Galois(GEN A,long k,GEN T)6088 Galois(GEN A, long k, GEN T)
6089 {
6090   if (typ(A) != t_POL) return A;
6091   return gmod(RgX_inflate(A, k), T);
6092 }
6093 static GEN
vecGalois(GEN v,long k,GEN T)6094 vecGalois(GEN v, long k, GEN T)
6095 {
6096   long i, l;
6097   GEN w = cgetg_copy(v,&l);
6098   for (i = 1; i < l; i++) gel(w,i) = Galois(gel(v,i), k, T);
6099   return w;
6100 }
6101 
6102 static GEN
fix_pol(GEN S,GEN Pn,int * trace)6103 fix_pol(GEN S, GEN Pn, int *trace)
6104 {
6105   if (typ(S) != t_POL) return S;
6106   S = RgX_rem(S, Pn);
6107   if (typ(S) == t_POL)
6108   {
6109     switch(lg(S))
6110     {
6111       case 2: return gen_0;
6112       case 3: return gel(S,2);
6113     }
6114     *trace = 1;
6115   }
6116   return S;
6117 }
6118 
6119 static GEN
dihan(GEN bnr,GEN w,GEN k0j,ulong lim)6120 dihan(GEN bnr, GEN w, GEN k0j, ulong lim)
6121 {
6122   GEN nf = bnr_get_nf(bnr), f = bid_get_ideal(bnr_get_bid(bnr));
6123   GEN v = zerovec(lim+1), cycn = gel(w,1), Tinit = gel(w,3);
6124   GEN Pn = gel(Tinit,lg(Tinit)==4? 2: 1);
6125   long j, ordmax = cycn[1], k0 = k0j[1], jdeg = k0j[2];
6126   long D = itos(nf_get_disc(nf)), vt = varn(Pn);
6127   int trace = 0;
6128   ulong p, n;
6129   forprime_t T;
6130 
6131   if (!lim) return v;
6132   gel(v,2) = gen_1;
6133   u_forprime_init(&T, 2, lim);
6134   /* fill in prime powers first */
6135   while ((p = u_forprime_next(&T)))
6136   {
6137     GEN vP, vchiP, S;
6138     long k, lP;
6139     ulong q, qk;
6140     if (kross(D,p) >= 0) q = p;
6141     else if (!(q = umuluu_le(p,p,lim))) continue;
6142     /* q = Norm P */
6143     vP = idealprimedec(nf, utoipos(p));
6144     lP = lg(vP);
6145     vchiP = cgetg(lP, t_VECSMALL);
6146     for (j = k = 1; j < lP; j++)
6147     {
6148       GEN P = gel(vP,j);
6149       if (!idealval(nf, f, P)) vchiP[k++] = mfdiheval(bnr,w,P);
6150     }
6151     if (k == 1) continue;
6152     setlg(vchiP, k); lP = k;
6153     if (lP == 2)
6154     { /* one prime above p not dividing f */
6155       long s, s0 = vchiP[1];
6156       for (qk=q, s = s0;; s = Fl_add(s,s0,ordmax))
6157       {
6158         S = Qab_zeta(s, ordmax, vt);
6159         gel(v, qk+1) = fix_pol(S, Pn, &trace);
6160         if (!(qk = umuluu_le(qk,q,lim))) break;
6161       }
6162     }
6163     else /* two primes above p not dividing f */
6164     {
6165       long s, s0 = vchiP[1], s1 = vchiP[2];
6166       for (qk=q, k = 1;; k++)
6167       { /* sum over a,b s.t. Norm( P1^a P2^b ) = q^k, i.e. a+b = k */
6168         long a;
6169         GEN S = gen_0;
6170         for (a = 0; a <= k; a++)
6171         {
6172           s = Fl_add(Fl_mul(a, s0, ordmax), Fl_mul(k-a, s1, ordmax), ordmax);
6173           S = gadd(S, Qab_zeta(s, ordmax, vt));
6174         }
6175         gel(v, qk+1) = fix_pol(S, Pn, &trace);
6176         if (!(qk = umuluu_le(qk,q,lim))) break;
6177       }
6178     }
6179   }
6180   /* complete with nonprime powers */
6181   for (n = 2; n <= lim; n++)
6182   {
6183     GEN S, fa = myfactoru(n), P = gel(fa, 1), E = gel(fa, 2);
6184     long q;
6185     if (lg(P) == 2) continue;
6186     /* not a prime power */
6187     q = upowuu(P[1],E[1]);
6188     S = gmul(gel(v, q + 1), gel(v, n/q + 1));
6189     gel(v, n+1) = fix_pol(S, Pn, &trace);
6190   }
6191   if (trace)
6192   {
6193     v = QabV_tracerel(Tinit, jdeg, v);
6194     /* Apply Galois Mod(k0, ordw) */
6195     if (k0 > 1) { GEN Pm = gel(Tinit,1); v = vecGalois(v, k0, Pm); }
6196   }
6197   return v;
6198 }
6199 
6200 /* as cyc_normalize for t_VECSMALL cyc */
6201 static GEN
cyc_normalize_zv(GEN cyc)6202 cyc_normalize_zv(GEN cyc)
6203 {
6204   long i, o = cyc[1], l = lg(cyc); /* > 1 */
6205   GEN D = cgetg(l, t_VECSMALL);
6206   D[1] = o; for (i = 2; i < l; i++) D[i] = o / cyc[i];
6207   return D;
6208 }
6209 /* as char_normalize for t_VECSMALLs */
6210 static GEN
char_normalize_zv(GEN chi,GEN ncyc)6211 char_normalize_zv(GEN chi, GEN ncyc)
6212 {
6213   long i, l = lg(chi);
6214   GEN c = cgetg(l, t_VECSMALL);
6215   if (l > 1) {
6216     c[1] = chi[1];
6217     for (i = 2; i < l; i++) c[i] = chi[i] * ncyc[i];
6218   }
6219   return c;
6220 }
6221 
6222 static GEN
dihan_bnf(long D)6223 dihan_bnf(long D)
6224 {
6225   GEN c = getrand(), bnf;
6226   setrand(gen_1);
6227   bnf = Buchall(quadpoly(stoi(D)), 0, LOWDEFAULTPREC);
6228   setrand(c);
6229   return bnf;
6230 }
6231 static GEN
dihan_bnr(GEN bnf,GEN A)6232 dihan_bnr(GEN bnf, GEN A)
6233 {
6234   GEN c = getrand(), bnr;
6235   setrand(gen_1);
6236   bnr = Buchray(bnf, A, nf_INIT|nf_GEN);
6237   setrand(c);
6238   return bnr;
6239 }
6240 /* Hecke xi * (D/.) = Dirichlet chi, return v in Q^r st chi(g_i) = e(v[i]).
6241  * cycn = cyc_normalize_zv(bnr.cyc), chin = char_normalize_zv(chi,cyc) */
6242 static GEN
bnrchartwist2conrey(GEN chin,GEN cycn,GEN bnrconreyN,GEN kroconreyN)6243 bnrchartwist2conrey(GEN chin, GEN cycn, GEN bnrconreyN, GEN kroconreyN)
6244 {
6245   long l = lg(bnrconreyN), c1 = cycn[1], i;
6246   GEN v = cgetg(l, t_COL);
6247   for (i = 1; i < l; i++)
6248   {
6249     GEN d = sstoQ(zv_dotproduct(chin, gel(bnrconreyN,i)), c1);
6250     if (kroconreyN[i] < 0) d = gadd(d, ghalf);
6251     gel(v,i) = d;
6252   }
6253   return v;
6254 }
6255 
6256 /* chi(g_i) = e(v[i]) denormalize wrt Conrey generators orders */
6257 static GEN
conreydenormalize(GEN znN,GEN v)6258 conreydenormalize(GEN znN, GEN v)
6259 {
6260   GEN gcyc = znstar_get_conreycyc(znN), w;
6261   long l = lg(v), i;
6262   w = cgetg(l, t_COL);
6263   for (i = 1; i < l; i++)
6264     gel(w,i) = modii(gmul(gel(v,i), gel(gcyc,i)), gel(gcyc,i));
6265   return w;
6266 }
6267 
6268 static long
Miyake(GEN vchi,GEN gb,GEN cycn)6269 Miyake(GEN vchi, GEN gb, GEN cycn)
6270 {
6271   long i, e = cycn[1], lb = lg(gb);
6272   GEN v = char_normalize_zv(vchi, cycn);
6273   for (i = 1; i < lb; i++)
6274     if ((zv_dotproduct(v, gel(gb,i)) -  v[i]) % e) return 1;
6275   return 0;
6276 }
6277 
6278 /* list of Hecke characters not induced by a Dirichlet character up to Galois
6279  * conjugation, whose conductor is bnr.cond; cycn = cyc_normalize(bnr.cyc)*/
6280 static GEN
mklvchi(GEN bnr,GEN cycn,GEN gb)6281 mklvchi(GEN bnr, GEN cycn, GEN gb)
6282 {
6283   GEN cyc = bnr_get_cyc(bnr), cycsmall = ZV_to_zv(cyc);
6284   GEN vchi = cyc2elts(cycsmall);
6285   long ordmax = cycsmall[1], c, i, l;
6286   l = lg(vchi);
6287   for (i = c = 1; i < l; i++)
6288   {
6289     GEN chi = gel(vchi,i);
6290     if (!gb || Miyake(chi, gb, cycn)) gel(vchi, c++) = Flv_to_ZV(chi);
6291   }
6292   setlg(vchi, c); l = c;
6293   for (i = 1; i < l; i++)
6294   {
6295     GEN chi = gel(vchi,i);
6296     long n;
6297     if (!chi) continue;
6298     for (n = 2; n < ordmax; n++)
6299       if (ugcd(n, ordmax) == 1)
6300       {
6301         GEN tmp = vecmodii(gmulsg(n, chi), cyc);
6302         long j;
6303         for (j = i+1; j < l; j++)
6304           if (gel(vchi,j) && gequal(gel(vchi,j), tmp)) gel(vchi,j) = NULL;
6305       }
6306   }
6307   for (i = c = 1; i < l; i++)
6308   {
6309     GEN chi = gel(vchi,i);
6310     if (chi && bnrisconductor(bnr, chi)) gel(vchi, c++) = chi;
6311   }
6312   setlg(vchi, c); return vchi;
6313 }
6314 
6315 static GEN
get_gb(GEN bnr,GEN con)6316 get_gb(GEN bnr, GEN con)
6317 {
6318   GEN gb, g = bnr_get_gen(bnr), nf = bnr_get_nf(bnr);
6319   long i, l = lg(g);
6320   gb = cgetg(l, t_VEC);
6321   for (i = 1; i < l; i++)
6322     gel(gb,i) = ZV_to_zv(isprincipalray(bnr, galoisapply(nf, con, gel(g,i))));
6323   return gb;
6324 }
6325 static GEN
get_bnrconreyN(GEN bnr,GEN znN)6326 get_bnrconreyN(GEN bnr, GEN znN)
6327 {
6328   GEN z, g = znstar_get_conreygen(znN);
6329   long i, l = lg(g);
6330   z = cgetg(l, t_VEC);
6331   for (i = 1; i < l; i++) gel(z,i) = ZV_to_zv(isprincipalray(bnr,gel(g,i)));
6332   return z;
6333 }
6334 /* con = NULL if D > 0 or if D < 0 and id != idcon. */
6335 static GEN
mfdihedralcommon(GEN bnf,GEN id,GEN znN,GEN kroconreyN,long N,long D,GEN con)6336 mfdihedralcommon(GEN bnf, GEN id, GEN znN, GEN kroconreyN, long N, long D, GEN con)
6337 {
6338   GEN bnr = dihan_bnr(bnf, id), cyc = ZV_to_zv( bnr_get_cyc(bnr) );
6339   GEN bnrconreyN, cycn, cycN, Lvchi, res, P, vT;
6340   long j, ordmax, l, lc, deghecke, degrel, vt;
6341 
6342   lc = lg(cyc); if (lc == 1) return NULL;
6343   cycn = cyc_normalize_zv(cyc);
6344   Lvchi = mklvchi(bnr, cycn, con? get_gb(bnr, con): NULL);
6345   l = lg(Lvchi);
6346   if (l == 1) return NULL;
6347 
6348   bnrconreyN = get_bnrconreyN(bnr, znN);
6349   cycN = ZV_to_zv(znstar_get_cyc(znN));
6350   ordmax = cyc[1];
6351   vT = const_vec(odd(ordmax)? ordmax << 1: ordmax, NULL);
6352   vt = fetch_user_var("t");
6353   P = polcyclo(ordmax, vt);
6354   gel(vT,ordmax) = Qab_trace_init(ordmax, ordmax, P, P);
6355   deghecke = myeulerphiu(ordmax);
6356   res = cgetg(l, t_VEC);
6357   for (j = 1; j < l; j++)
6358   {
6359     GEN T, v, vchi = ZV_to_zv(gel(Lvchi,j));
6360     GEN chi, chin = char_normalize_zv(vchi, cycn);
6361     long o, vnum, k0;
6362     v = bnrchartwist2conrey(chin, cycn, bnrconreyN, kroconreyN);
6363     o = itou(Q_denom(v));
6364     T = gel(vT, o);
6365     if (!T) gel(vT,o) = T = Qab_trace_init(ordmax, o, P, polcyclo(o,vt));
6366     chi = conreydenormalize(znN, v);
6367     vnum = itou(znconreyexp(znN, chi));
6368     chi = ZV_to_zv(znconreychar(znN,chi));
6369     degrel = deghecke / degpol(gel(T,1));
6370     k0 = zv_cyc_minimize(cycN, chi, coprimes_zv(o));
6371     vnum = Fl_powu(vnum, k0, N);
6372     /* encodes degrel forms: jdeg = 0..degrel-1 */
6373     gel(res,j) = mkvec3(mkvecsmalln(5, N, k0, vnum, D, degrel),
6374                         id, mkvec3(cycn,chin,T));
6375   }
6376   return res;
6377 }
6378 
6379 static long
not_cond(long D,long n)6380 not_cond(long D, long n)
6381 {
6382   if (D > 0) return n == 4 && (D&7L) != 1;
6383   return n == 2 || n == 3 || (n == 4 && (D&7L)==1);
6384 }
6385 /* Append to v all dihedral weight 1 forms coming from D, if fundamental.
6386  * level in [l1, l2] */
6387 static void
append_dihedral(GEN v,long D,long l1,long l2)6388 append_dihedral(GEN v, long D, long l1, long l2)
6389 {
6390   long Da = labs(D), no, i, numi, ct, min, max;
6391   GEN bnf, con, LI, resall, arch1, arch2;
6392   pari_sp av;
6393 
6394   /* min <= Nf <= max */
6395   max = l2 / Da;
6396   if (l1 == l2)
6397   { /* assume Da | l2 */
6398     min = max;
6399     if (D > 0 && min < 3) return;
6400   }
6401   else /* assume l1 < l2 */
6402     min = (l1 + Da-1)/Da;
6403   if (!sisfundamental(D)) return;
6404 
6405   av = avma;
6406   bnf = dihan_bnf(D);
6407   con = nf2_get_conj(bnf_get_nf(bnf));
6408   LI = ideallist(bnf, max);
6409   numi = 0; for (i = min; i <= max; i++) numi += lg(gel(LI, i)) - 1;
6410   if (D > 0)
6411   {
6412     numi <<= 1;
6413     arch1 = mkvec2(gen_1,gen_0);
6414     arch2 = mkvec2(gen_0,gen_1);
6415   }
6416   else
6417     arch1 = arch2 = NULL;
6418   resall = cgetg(numi+1, t_VEC); ct = 1;
6419   for (no = min; no <= max; no++) if (!not_cond(D, no))
6420   {
6421     long N = Da*no, lgc, lglis;
6422     GEN LIs = gel(LI, no), znN = znstar0(utoipos(N), 1), conreyN, kroconreyN;
6423 
6424     conreyN = znstar_get_conreygen(znN); lgc = lg(conreyN);
6425     kroconreyN = cgetg(lgc, t_VECSMALL);
6426     for (i = 1; i < lgc; i++) kroconreyN[i] = krosi(D, gel(conreyN, i));
6427     lglis = lg(LIs);
6428     for (i = 1; i < lglis; i++)
6429     {
6430       GEN id = gel(LIs, i), idcon, z;
6431       long j;
6432       if (typ(id) == t_INT) continue;
6433       idcon = galoisapply(bnf, con, id);
6434       for (j = i; j < lglis; j++)
6435         if (gequal(idcon, gel(LIs, j))) { gel(LIs, j) = gen_0; break; }
6436       if (D < 0)
6437       {
6438         GEN conk = i == j ? con : NULL;
6439         z = mfdihedralcommon(bnf, id, znN, kroconreyN, N, D, conk);
6440         if (z) gel(resall, ct++) = z;
6441       }
6442       else
6443       {
6444         GEN ide;
6445         ide = mkvec2(id, arch1);
6446         z = mfdihedralcommon(bnf, ide, znN, kroconreyN, N, D, NULL);
6447         if (z) gel(resall, ct++) = z;
6448         if (gequal(idcon,id)) continue;
6449         ide = mkvec2(id, arch2);
6450         z = mfdihedralcommon(bnf, ide, znN, kroconreyN, N, D, NULL);
6451         if (z) gel(resall, ct++) = z;
6452       }
6453     }
6454   }
6455   if (ct == 1) set_avma(av);
6456   else
6457   {
6458     setlg(resall, ct);
6459     vectrunc_append(v, gerepilecopy(av, shallowconcat1(resall)));
6460   }
6461 }
6462 
6463 static long
di_N(GEN a)6464 di_N(GEN a) { return gel(a,1)[1]; }
6465 /* All primitive dihedral wt1 forms: LIM a t_VECSMALL with a single component
6466  * (only level LIM) or 2 components [m,M], m < M (between m and M) */
6467 static GEN
mfdihedralall(GEN LIM)6468 mfdihedralall(GEN LIM)
6469 {
6470   GEN res, z;
6471   long limD, ct, i, l1, l2;
6472 
6473   if (lg(LIM) == 2) l1 = l2 = LIM[1]; else { l1 = LIM[1]; l2 = LIM[2]; }
6474   limD = l2;
6475   res = vectrunc_init(2*limD);
6476   if (l1 == l2)
6477   {
6478     GEN D = mydivisorsu(l1);
6479     long l = lg(D), j;
6480     for (j = 2; j < l; j++)
6481     { /* skip d = 1 */
6482       long d = D[j];
6483       if (d == 2) continue;
6484       append_dihedral(res, -d, l1,l2);
6485       if (d >= 5 && D[l-j] >= 3) append_dihedral(res, d, l1,l2); /* Nf >= 3 */
6486     }
6487   }
6488   else
6489   {
6490     long D;
6491     for (D = -3; D >= -limD; D--) append_dihedral(res, D, l1,l2);
6492     limD /= 3; /* Nf >= 3 (GTM 193, prop 3.3.18) */
6493     for (D = 5; D <= limD;   D++) append_dihedral(res, D, l1,l2);
6494   }
6495   ct = lg(res);
6496   if (ct > 1) res = shallowconcat1(res);
6497   if (l1 == l2) return res; /* single level */
6498   if (ct > 1)
6499   { /* sort wrt N */
6500     res = vecpermute(res, indexvecsort(res, mkvecsmall(1)));
6501     ct = lg(res);
6502   }
6503   z = const_vec(l2-l1+1, cgetg(1,t_VEC));
6504   for (i = 1; i < ct;)
6505   { /* regroup result sharing the same N */
6506     long n = di_N(gel(res,i)), j = i+1, k;
6507     GEN v;
6508     while (j < ct && di_N(gel(res,j)) == n) j++;
6509     n -= l1-1;
6510     gel(z, n) = v = cgetg(j-i+1, t_VEC);
6511     for (k = 1; i < j; k++,i++) gel(v,k) = gel(res,i);
6512   }
6513   return z;
6514 }
6515 
6516 /* return [vF, index], where vecpermute(vF,index) generates dihedral forms
6517  * for character CHI */
6518 static GEN
mfdihedralnew_i(long N,GEN CHI)6519 mfdihedralnew_i(long N, GEN CHI)
6520 {
6521   GEN bnf, Tinit, Pm, vf, M, V, NK, SP;
6522   long Dold, d, ordw, i, SB, c, l, k0, k1, chino, chinoorig, lv;
6523 
6524   SP = cache_get(cache_DIH, N);
6525   if (!SP) SP = mfdihedralall(mkvecsmall(N));
6526   lv = lg(SP); if (lv == 1) return NULL;
6527   CHI = mfcharinduce(CHI,N);
6528   ordw = mfcharorder(CHI);
6529   chinoorig = mfcharno(CHI);
6530   k0 = mfconreyminimize(CHI);
6531   chino = Fl_powu(chinoorig, k0, N);
6532   k1 = Fl_inv(k0 % ordw, ordw);
6533   V = cgetg(lv, t_VEC);
6534   d = 0;
6535   for (i = l = 1; i < lv; i++)
6536   {
6537     GEN sp = gel(SP,i), T = gel(sp,1);
6538     if (T[3] != chino) continue;
6539     d += T[5];
6540     if (k1 != 1)
6541     {
6542       GEN t = leafcopy(T);
6543       t[3] = chinoorig;
6544       t[2] = (t[2]*k1) % ordw;
6545       sp = mkvec4(t, gel(sp,2), gel(sp,3), gel(sp,4));
6546     }
6547     gel(V, l++) = sp;
6548   }
6549   setlg(V, l); /* dihedral forms of level N and character CHI */
6550   if (l == 1) return NULL;
6551 
6552   SB = myeulerphiu(ordw) * mfsturmNk(N,1) + 1;
6553   M = cgetg(d+1, t_MAT);
6554   vf = cgetg(d+1, t_VEC);
6555   NK = mkNK(N, 1, CHI);
6556   bnf = NULL; Dold = 0;
6557   for (i = c = 1; i < l; i++)
6558   { /* T = [N, k0, conreyno, D, degrel] */
6559     GEN bnr, Vi = gel(V,i), T = gel(Vi,1), id = gel(Vi,2), w = gel(Vi,3);
6560     long jdeg, k0i = T[2], D = T[4], degrel = T[5];
6561 
6562     if (D != Dold) { Dold = D; bnf = dihan_bnf(D); }
6563     bnr = dihan_bnr(bnf, id);
6564     for (jdeg = 0; jdeg < degrel; jdeg++,c++)
6565     {
6566       GEN k0j = mkvecsmall2(k0i, jdeg), an = dihan(bnr, w, k0j, SB);
6567       settyp(an, t_COL); gel(M,c) = Q_primpart(an);
6568       gel(vf,c) = tag3(t_MF_DIHEDRAL, NK, bnr, w, k0j);
6569     }
6570   }
6571   Tinit = gmael3(V,1,3,3); Pm = gel(Tinit,1);
6572   V = QabM_indexrank(M, degpol(Pm)==1? NULL: Pm, ordw);
6573   return mkvec2(vf,gel(V,2));
6574 }
6575 static long
mfdihedralnewdim(long N,GEN CHI)6576 mfdihedralnewdim(long N, GEN CHI)
6577 {
6578   pari_sp av = avma;
6579   GEN S = mfdihedralnew_i(N, CHI);
6580   return gc_long(av, S? lg(gel(S,2))-1: 0);
6581 }
6582 static GEN
mfdihedralnew(long N,GEN CHI)6583 mfdihedralnew(long N, GEN CHI)
6584 {
6585   pari_sp av = avma;
6586   GEN S = mfdihedralnew_i(N, CHI);
6587   if (!S) { set_avma(av); return cgetg(1, t_VEC); }
6588   return vecpermute(gel(S,1), gel(S,2));
6589 }
6590 
6591 static long
mfdihedralcuspdim(long N,GEN CHI)6592 mfdihedralcuspdim(long N, GEN CHI)
6593 {
6594   pari_sp av = avma;
6595   GEN D, CHIP;
6596   long F, i, lD, dim;
6597 
6598   CHIP = mfchartoprimitive(CHI, &F);
6599   D = mydivisorsu(N/F); lD = lg(D);
6600   dim = mfdihedralnewdim(N, CHI); /* d = 1 */
6601   for (i = 2; i < lD; i++)
6602   {
6603     long d = D[i], a = mfdihedralnewdim(N / d, CHIP);
6604     if (a) dim += a * mynumdivu(d);
6605   }
6606   return gc_long(av,dim);
6607 }
6608 
6609 static GEN
mfbdall(GEN E,long N)6610 mfbdall(GEN E, long N)
6611 {
6612   GEN v, D = mydivisorsu(N);
6613   long i, j, nD = lg(D) - 1, nE = lg(E) - 1;
6614   v = cgetg(nD*nE + 1, t_VEC);
6615   for (j = 1; j <= nE; j++)
6616   {
6617     GEN Ej = gel(E, j);
6618     for (i = 0; i < nD; i++) gel(v, i*nE + j) = mfbd_i(Ej, D[i+1]);
6619   }
6620   return v;
6621 }
6622 static GEN
mfdihedralcusp(long N,GEN CHI)6623 mfdihedralcusp(long N, GEN CHI)
6624 {
6625   pari_sp av = avma;
6626   GEN D, CHIP, z;
6627   long F, i, lD;
6628 
6629   CHIP = mfchartoprimitive(CHI, &F);
6630   D = mydivisorsu(N/F); lD = lg(D);
6631   z = cgetg(lD, t_VEC);
6632   gel(z,1) = mfdihedralnew(N, CHI);
6633   for (i = 2; i < lD; i++) /* skip 1 */
6634   {
6635     GEN LF = mfdihedralnew(N / D[i], CHIP);
6636     gel(z,i) = mfbdall(LF, D[i]);
6637   }
6638   return gerepilecopy(av, shallowconcat1(z));
6639 }
6640 
6641 /* used to decide between ratlift and comatrix for ZM_inv; ratlift is better
6642  * when N has many divisors */
6643 static int
abundant(ulong N)6644 abundant(ulong N) { return mynumdivu(N) >= 8; }
6645 
6646 /* CHI an mfchar */
6647 static int
cmp_ord(void * E,GEN a,GEN b)6648 cmp_ord(void *E, GEN a, GEN b)
6649 {
6650   GEN chia = MF_get_CHI(a), chib = MF_get_CHI(b);
6651   (void)E; return cmpii(gmfcharorder(chia), gmfcharorder(chib));
6652 }
6653 /* mfinit structure.
6654 -- mf[1] contains [N,k,CHI,space],
6655 -- mf[2] contains vector of closures of Eisenstein series, empty if not
6656    full space.
6657 -- mf[3] contains vector of closures, so #mf[3] = dimension of cusp/new space.
6658 -- mf[4] contains the corresponding indices: either j for T(j)tf if newspace,
6659    or [M,j,d] for B(d)T(j)tf_M if cuspspace or oldspace.
6660 -- mf[5] contains the matrix M of first coefficients of basis, never cleaned.
6661  * NK is either [N,k] or [N,k,CHI].
6662  * mfinit does not do the splitting, only the basis generation. */
6663 
6664 /* Set flraw to 1 if do not need mf[5]: no mftobasis etc..., only the
6665    expansions of the basis elements are needed. */
6666 
6667 static GEN
mfinit_Nkchi(long N,long k,GEN CHI,long space,long flraw)6668 mfinit_Nkchi(long N, long k, GEN CHI, long space, long flraw)
6669 {
6670   GEN M = NULL, mf = NULL, mf1 = mkvec4(utoi(N), stoi(k), CHI, utoi(space));
6671   long sb = mfsturmNk(N, k);
6672   cachenew_t cache;
6673   if (k < 0 || badchar(N, k, CHI)) return mfEMPTY(mf1);
6674   if (k == 0) /*nothing*/;
6675   else if (k == 1)
6676   {
6677     switch (space)
6678     {
6679       case mf_NEW:
6680       case mf_FULL:
6681       case mf_CUSP: mf = mfwt1init(N, CHI, NULL, space, flraw); break;
6682       case mf_EISEN:break;
6683       case mf_OLD: pari_err_IMPL("mfinit in weight 1 for old space");
6684       default: pari_err_FLAG("mfinit");
6685     }
6686   }
6687   else /* k >= 2 */
6688   {
6689     long ord = mfcharorder(CHI);
6690     GEN z = NULL, P = (ord <= 2)? NULL: mfcharpol(CHI);
6691     switch(space)
6692     {
6693       case mf_EISEN:
6694         break;
6695       case mf_NEW:
6696         mf = mfnewinit(N, k, CHI, &cache, 1);
6697         if (mf && !flraw) { M = MF_get_M(mf); z = MF_get_Mindex(mf); }
6698         break;
6699       case mf_OLD:
6700       case mf_CUSP:
6701       case mf_FULL:
6702         mf = mfinitcusp(N, k, CHI, &cache, space);
6703         if (mf && !flraw)
6704         {
6705           GEN S = MF_get_S(mf);
6706           M = bhnmat_extend(M, sb+1, 1, S, &cache);
6707           if (space != mf_FULL) gel(mf,5) = mfcleanCHI(M, CHI, abundant(N));
6708         }
6709         dbg_cachenew(&cache);
6710         break;
6711       default: pari_err_FLAG("mfinit");
6712     }
6713     if (z) gel(mf,5) = mfclean2(M, z, P, ord);
6714   }
6715   if (!mf) mf = mfEMPTY(mf1);
6716   else
6717   {
6718     gel(mf,1) = mf1;
6719     if (flraw) gel(mf,5) = zerovec(3);
6720   }
6721   if (!space_is_cusp(space))
6722   {
6723     GEN E = mfeisensteinbasis(N, k, CHI);
6724     gel(mf,2) = E;
6725     if (!flraw)
6726     {
6727       if (M)
6728         M = shallowconcat(mfvectomat(E, sb+1, 1), M);
6729       else
6730         M = mfcoefs_mf(mf, sb+1, 1);
6731       gel(mf,5) = mfcleanCHI(M, CHI, abundant(N));
6732     }
6733   }
6734   return mf;
6735 }
6736 
6737 /* mfinit for k = nk/dk */
6738 static GEN
mfinit_Nndkchi(long N,long nk,long dk,GEN CHI,long space,long flraw)6739 mfinit_Nndkchi(long N, long nk, long dk, GEN CHI, long space, long flraw)
6740 { return (dk == 2)? mf2init_Nkchi(N, nk >> 1, CHI, space, flraw)
6741                   : mfinit_Nkchi(N, nk, CHI, space, flraw); }
6742 static GEN
mfinit_i(GEN NK,long space)6743 mfinit_i(GEN NK, long space)
6744 {
6745   GEN CHI, mf;
6746   long N, k, dk, joker;
6747   if (checkmf_i(NK))
6748   {
6749     N = mf_get_N(NK);
6750     Qtoss(mf_get_gk(NK), &k, &dk);
6751     CHI = mf_get_CHI(NK);
6752   }
6753   else if ((mf = checkMF_i(NK)))
6754   {
6755     long s = MF_get_space(mf);
6756     if (s == space) return mf;
6757     Qtoss(MF_get_gk(mf), &k, &dk);
6758     if (dk == 1 && k > 1 && space == mf_NEW && (s == mf_CUSP || s == mf_FULL))
6759       return mfinittonew(mf);
6760     N = MF_get_N(mf);
6761     CHI = MF_get_CHI(mf);
6762   }
6763   else
6764     checkNK2(NK, &N, &k, &dk, &CHI, 1);
6765   joker = !CHI || typ(CHI) == t_COL;
6766   if (joker)
6767   {
6768     GEN mf, vCHI = CHI;
6769     long i, j, l;
6770     if (CHI && lg(CHI) == 1) return cgetg(1,t_VEC);
6771     if (k < 0) return mfEMPTYall(N, sstoQ(k,dk), CHI, space);
6772     if (k == 1 && dk == 1 && space != mf_EISEN)
6773     {
6774       GEN TMP, gN, gs;
6775       if (space != mf_CUSP && space != mf_NEW)
6776         pari_err_IMPL("mfinit([N,1,wildcard], space != cusp or new space)");
6777       if (wt1empty(N)) return mfEMPTYall(N, gen_1, CHI, space);
6778       vCHI = mfwt1chars(N,vCHI);
6779       l = lg(vCHI); mf = cgetg(l, t_VEC); if (l == 1) return mf;
6780       TMP = mfwt1_pre(N); gN = utoipos(N); gs = utoi(space);
6781       for (i = j = 1; i < l; i++)
6782       {
6783         pari_sp av = avma;
6784         GEN c = gel(vCHI,i), z = mfwt1init(N, c, TMP, space, 0);
6785         if (!z) {
6786           set_avma(av);
6787           if (CHI) z = mfEMPTY(mkvec4(gN,gen_1,c,gs));
6788         }
6789         if (z) gel(mf, j++) = z;
6790       }
6791     }
6792     else
6793     {
6794       vCHI = mfchars(N,k,dk,vCHI);
6795       l = lg(vCHI); mf = cgetg(l, t_VEC);
6796       for (i = j = 1; i < l; i++)
6797       {
6798         pari_sp av = avma;
6799         GEN v = mfinit_Nndkchi(N, k, dk, gel(vCHI,i), space, 0);
6800         if (MF_get_dim(v) || CHI) gel(mf, j++) = v; else set_avma(av);
6801       }
6802     }
6803     setlg(mf,j);
6804     if (!CHI) gen_sort_inplace(mf, NULL, &cmp_ord, NULL);
6805     return mf;
6806   }
6807   return mfinit_Nndkchi(N, k, dk, CHI, space, 0);
6808 }
6809 GEN
mfinit(GEN NK,long space)6810 mfinit(GEN NK, long space)
6811 {
6812   pari_sp av = avma;
6813   return gerepilecopy(av, mfinit_i(NK, space));
6814 }
6815 
6816 /* UTILITY FUNCTIONS */
6817 static void
cusp_canon(GEN cusp,long N,long * pA,long * pC)6818 cusp_canon(GEN cusp, long N, long *pA, long *pC)
6819 {
6820   pari_sp av = avma;
6821   long A, C, tc, cg;
6822   if (N <= 0) pari_err_DOMAIN("mfcuspwidth","N","<=",gen_0,stoi(N));
6823   if (!cusp || (tc = typ(cusp)) == t_INFINITY) { *pA = 1; *pC = N; return; }
6824   if (tc != t_INT && tc != t_FRAC) pari_err_TYPE("checkcusp", cusp);
6825   Qtoss(cusp, &A,&C);
6826   if (N % C)
6827   {
6828     ulong uC;
6829     long u = Fl_invgen((C-1)%N + 1, N, &uC);
6830     A = Fl_mul(A, u, N);
6831     C = (long)uC;
6832   }
6833   cg = ugcd(C, N/C);
6834   while (ugcd(A, N) > 1) A += cg;
6835   *pA = A % N; *pC = C; set_avma(av);
6836 }
6837 static long
mfcuspcanon_width(long N,long C)6838 mfcuspcanon_width(long N, long C)
6839 { return (!C || C == N)? 1 : N / ugcd(N, Fl_sqr(umodsu(C,N),N)); }
6840 /* v = [a,c] a ZC, width of cusp (a:c) */
6841 static long
mfZC_width(long N,GEN v)6842 mfZC_width(long N, GEN v)
6843 {
6844   ulong C = umodiu(gel(v,2), N);
6845   return (C == 0)? 1: N / ugcd(N, Fl_sqr(C,N));
6846 }
6847 long
mfcuspwidth(GEN gN,GEN cusp)6848 mfcuspwidth(GEN gN, GEN cusp)
6849 {
6850   long N = 0, A, C;
6851   GEN mf;
6852   if (typ(gN) == t_INT) N = itos(gN);
6853   else if ((mf = checkMF_i(gN))) N = MF_get_N(mf);
6854   else pari_err_TYPE("mfcuspwidth", gN);
6855   cusp_canon(cusp, N, &A, &C);
6856   return mfcuspcanon_width(N, C);
6857 }
6858 
6859 /* Q a t_INT */
6860 static GEN
findq(GEN al,GEN Q)6861 findq(GEN al, GEN Q)
6862 {
6863   long n;
6864   if (typ(al) == t_FRAC && cmpii(gel(al,2), Q) <= 0)
6865     return mkvec(mkvec2(gel(al,1), gel(al,2)));
6866   n = 1 + (long)ceil(2.0781*gtodouble(glog(Q, LOWDEFAULTPREC)));
6867   return contfracpnqn(gboundcf(al,n), n);
6868 }
6869 static GEN
findqga(long N,GEN z)6870 findqga(long N, GEN z)
6871 {
6872   GEN Q, LDC, CK = NULL, DK = NULL, ma, x, y = imag_i(z);
6873   long j, l;
6874   if (gcmpgs(gmulsg(2*N, y), 1) >= 0) return NULL;
6875   x = real_i(z);
6876   Q = ground(ginv(gsqrt(gmulsg(N, y), LOWDEFAULTPREC)));
6877   LDC = findq(gmulsg(-N,x), Q);
6878   ma = gen_1; l = lg(LDC);
6879   for (j = 1; j < l; j++)
6880   {
6881     GEN D, DC = gel(LDC,j), C1 = gel(DC,2);
6882     if (cmpii(C1,Q) > 0) break;
6883     D = gel(DC,1);
6884     if (ugcdiu(D,N) == 1)
6885     {
6886       GEN C = mului(N, C1), den;
6887       den = gadd(gsqr(gmul(C,y)), gsqr(gadd(D, gmul(C,x))));
6888       if (gcmp(den, ma) < 0) { ma = den; CK = C; DK = D; }
6889     }
6890   }
6891   return DK? mkvec2(CK, DK): NULL;
6892 }
6893 
6894 static long
valNC2(GEN P,GEN E,long e)6895 valNC2(GEN P, GEN E, long e)
6896 {
6897   long i, d = 1, l = lg(P);
6898   for (i = 1; i < l; i++)
6899   {
6900     long v = u_lval(e, P[i]) << 1;
6901     if (v == E[i] + 1) v--;
6902     d *= upowuu(P[i], v);
6903   }
6904   return d;
6905 }
6906 
6907 static GEN
findqganew(long N,GEN z)6908 findqganew(long N, GEN z)
6909 {
6910   GEN MI, DI, x = real_i(z), y = imag_i(z), Ck = gen_0, Dk = gen_1, fa, P, E;
6911   long i;
6912   MI = ginv(utoi(N));
6913   DI = mydivisorsu(mysqrtu(N));
6914   fa = myfactoru(N); P = gel(fa,1); E = gel(fa,2);
6915   for (i = 1; i < lg(DI); i++)
6916   {
6917     long e = DI[i], g;
6918     GEN U, C, D, m;
6919     (void)cxredsl2(gmulsg(e, z), &U);
6920     C = gcoeff(U,2,1); if (!signe(C)) continue;
6921     D = gcoeff(U,2,2);
6922     g = ugcdiu(D,e);
6923     if (g > 1) { C = muliu(C,e/g); D = diviuexact(D,g); } else C = muliu(C,e);
6924     m = gadd(gsqr(gadd(gmul(C, x), D)), gsqr(gmul(C, y)));
6925     m = gdivgs(m, valNC2(P, E, e));
6926     if (gcmp(m, MI) < 0) { MI = m; Ck = C; Dk = D; }
6927   }
6928   return signe(Ck)? mkvec2(Ck, Dk): NULL;
6929 }
6930 
6931 /* Return z' and U = [a,b;c,d] \in SL_2(Z), z' = U*z,
6932  * Im(z')/width(U.oo) > sqrt(3)/(2N). Set *pczd = c*z+d */
6933 static GEN
cxredga0N(long N,GEN z,GEN * pU,GEN * pczd,long flag)6934 cxredga0N(long N, GEN z, GEN *pU, GEN *pczd, long flag)
6935 {
6936   GEN v = NULL, A, B, C, D;
6937   long e;
6938   if (N == 1) return cxredsl2_i(z, pU, pczd);
6939   e = gexpo(gel(z,2));
6940   if (e < 0) z = gprec_wensure(z, precision(z) + nbits2extraprec(-e));
6941   v = flag? findqganew(N,z): findqga(N,z);
6942   if (!v) { *pU = matid(2); *pczd = gen_1; return z; }
6943   C = gel(v,1);
6944   D = gel(v,2);
6945   if (!is_pm1(bezout(C,D, &B,&A))) pari_err_BUG("cxredga0N [gcd > 1]");
6946   B = negi(B);
6947   *pU = mkmat2(mkcol2(A,C), mkcol2(B,D));
6948   *pczd = gadd(gmul(C,z), D);
6949   return gdiv(gadd(gmul(A,z), B), *pczd);
6950 }
6951 
6952 static GEN
lfunthetaall(GEN b,GEN vL,GEN t,long bitprec)6953 lfunthetaall(GEN b, GEN vL, GEN t, long bitprec)
6954 {
6955   long i, l = lg(vL);
6956   GEN v = cgetg(l, t_VEC);
6957   for (i = 1; i < l; i++)
6958   {
6959     GEN T, L = gel(vL,i), a0 = gel(L,1), ldata = gel(L,2);
6960     GEN van = gel(ldata_get_an(ldata),2);
6961     if (lg(van) == 1)
6962     {
6963       T = gmul(b, a0);
6964       if (isexactzero(T)) { GEN z = real_0_bit(-bitprec); T = mkcomplex(z,z); }
6965     }
6966     else
6967     {
6968       T = gmul2n(lfuntheta(ldata, t, 0, bitprec), -1);
6969       T = gmul(b, gadd(a0, T));
6970     }
6971     gel(v,i) = T;
6972   }
6973   return l == 2? gel(v,1): v;
6974 }
6975 
6976 /* P in ZX, irreducible */
6977 static GEN
ZX_roots(GEN P,long prec)6978 ZX_roots(GEN P, long prec)
6979 {
6980   long d = degpol(P);
6981   if (d == 1) return mkvec(gen_0);
6982   if (d == 2 && isint1(gel(P,2)) && isintzero(gel(P,3)) && isint1(gel(P,4)))
6983     return mkvec2(powIs(3), gen_I()); /* order as polroots */
6984   return (ZX_sturm_irred(P) == d)? ZX_realroots_irred(P, prec)
6985                                  : QX_complex_roots(P, prec);
6986 }
6987 /* initializations for RgX_RgV_eval / RgC_embed */
6988 static GEN
rootspowers(GEN v)6989 rootspowers(GEN v)
6990 {
6991   long i, l = lg(v);
6992   GEN w = cgetg(l, t_VEC);
6993   for (i = 1; i < l; i++) gel(w,i) = gpowers(gel(v,i), l-2);
6994   return w;
6995 }
6996 /* mf embeddings attached to Q(chi)/(T), chi attached to cyclotomic P */
6997 static GEN
getembed(GEN P,GEN T,GEN zcyclo,long prec)6998 getembed(GEN P, GEN T, GEN zcyclo, long prec)
6999 {
7000   long i, l;
7001   GEN v;
7002   if (degpol(P) == 1) P = NULL; /* mfcharpol for quadratic char */
7003   if (degpol(T) == 1) T = NULL; /* dim 1 orbit */
7004   if (T && P)
7005   { /* K(y) / (T(y)), K = Q(t)/(P) cyclotomic */
7006     GEN vr = RgX_is_ZX(T)? ZX_roots(T,prec): roots(RgX_embed1(T,zcyclo), prec);
7007     v = rootspowers(vr); l = lg(v);
7008     for (i = 1; i < l; i++) gel(v,i) = mkcol3(P,zcyclo,gel(v,i));
7009   }
7010   else if (T)
7011   { /* Q(y) / (T(y)), T noncyclotomic */
7012     GEN vr = ZX_roots(T, prec);
7013     v = rootspowers(vr); l = lg(v);
7014     for (i = 1; i < l; i++) gel(v,i) = mkcol2(T, gel(v,i));
7015   }
7016   else /* cyclotomic or rational */
7017     v = mkvec(P? mkvec2(P, zcyclo): cgetg(1,t_VEC));
7018   return v;
7019 }
7020 static GEN
grootsof1_CHI(GEN CHI,long prec)7021 grootsof1_CHI(GEN CHI, long prec)
7022 { return grootsof1(mfcharorder(CHI), prec); }
7023 /* return the [Q(F):Q(chi)] embeddings of F */
7024 static GEN
mfgetembed(GEN F,long prec)7025 mfgetembed(GEN F, long prec)
7026 {
7027   GEN T = mf_get_field(F), CHI = mf_get_CHI(F), P = mfcharpol(CHI);
7028   return getembed(P, T, grootsof1_CHI(CHI, prec), prec);
7029 }
7030 static GEN
mfchiembed(GEN mf,long prec)7031 mfchiembed(GEN mf, long prec)
7032 {
7033   GEN CHI = MF_get_CHI(mf), P = mfcharpol(CHI);
7034   return getembed(P, pol_x(0), grootsof1_CHI(CHI, prec), prec);
7035 }
7036 /* mfgetembed for the successive eigenforms in MF_get_newforms */
7037 static GEN
mfeigenembed(GEN mf,long prec)7038 mfeigenembed(GEN mf, long prec)
7039 {
7040   GEN vP = MF_get_fields(mf), vF = MF_get_newforms(mf);
7041   GEN zcyclo, vE, CHI = MF_get_CHI(mf), P = mfcharpol(CHI);
7042   long i, l = lg(vP);
7043   vF = Q_remove_denom(liftpol_shallow(vF), NULL);
7044   prec += nbits2extraprec(gexpo(vF));
7045   zcyclo = grootsof1_CHI(CHI, prec);
7046   vE = cgetg(l, t_VEC);
7047   for (i = 1; i < l; i++) gel(vE,i) = getembed(P, gel(vP,i), zcyclo, prec);
7048   return vE;
7049 }
7050 
7051 static int
checkPv(GEN P,GEN v)7052 checkPv(GEN P, GEN v)
7053 { return typ(P) == t_POL && is_vec_t(typ(v)) && lg(v)-1 >= degpol(P); }
7054 static int
checkemb_i(GEN E)7055 checkemb_i(GEN E)
7056 {
7057   long t = typ(E), l = lg(E);
7058   if (t == t_VEC) return l == 1 || (l == 3 && checkPv(gel(E,1), gel(E,2)));
7059   if (t != t_COL) return 0;
7060   if (l == 3) return checkPv(gel(E,1), gel(E,2));
7061   return l == 4 && is_vec_t(typ(gel(E,2))) && checkPv(gel(E,1), gel(E,3));
7062 }
7063 static GEN
anyembed(GEN v,GEN E)7064 anyembed(GEN v, GEN E)
7065 {
7066   switch(typ(v))
7067   {
7068     case t_VEC: case t_COL: return mfvecembed(E, v);
7069     case t_MAT: return mfmatembed(E, v);
7070   }
7071   return mfembed(E, v);
7072 }
7073 GEN
mfembed0(GEN E,GEN v,long prec)7074 mfembed0(GEN E, GEN v, long prec)
7075 {
7076   pari_sp av = avma;
7077   GEN mf, vE = NULL;
7078   if (checkmf_i(E)) vE = mfgetembed(E, prec);
7079   else if ((mf = checkMF_i(E))) vE = mfchiembed(mf, prec);
7080   if (vE)
7081   {
7082     long i, l = lg(vE);
7083     GEN w;
7084     if (!v) return gerepilecopy(av, l == 2? gel(vE,1): vE);
7085     w = cgetg(l, t_VEC);
7086     for (i = 1; i < l; i++) gel(w,i) = anyembed(v, gel(vE,i));
7087     return gerepilecopy(av, l == 2? gel(w,1): w);
7088   }
7089   if (!checkemb_i(E) || !v) pari_err_TYPE("mfembed", E);
7090   return gerepilecopy(av, anyembed(v,E));
7091 }
7092 
7093 /* dummy lfun create for theta evaluation */
7094 static GEN
mfthetaancreate(GEN van,GEN N,GEN k)7095 mfthetaancreate(GEN van, GEN N, GEN k)
7096 {
7097   GEN L = zerovec(6);
7098   gel(L,1) = lfuntag(t_LFUN_GENERIC, van);
7099   gel(L,3) = mkvec2(gen_0, gen_1);
7100   gel(L,4) = k;
7101   gel(L,5) = N; return L;
7102 }
7103 /* destroy van and prepare to evaluate theta(sigma(van)), for all sigma in
7104  * embeddings vector vE */
7105 static GEN
van_embedall(GEN van,GEN vE,GEN gN,GEN gk)7106 van_embedall(GEN van, GEN vE, GEN gN, GEN gk)
7107 {
7108   GEN a0 = gel(van,1), vL;
7109   long i, lE = lg(vE), l = lg(van);
7110   van++; van[0] = evaltyp(t_VEC) | evallg(l-1); /* remove a0 */
7111   vL = cgetg(lE, t_VEC);
7112   for (i = 1; i < lE; i++)
7113   {
7114     GEN E = gel(vE,i), v = mfvecembed(E, van);
7115     gel(vL,i) = mkvec2(mfembed(E,a0), mfthetaancreate(v, gN, gk));
7116   }
7117   return vL;
7118 }
7119 
7120 static int
cusp_AC(GEN cusp,long * A,long * C)7121 cusp_AC(GEN cusp, long *A, long *C)
7122 {
7123   switch(typ(cusp))
7124   {
7125     case t_INFINITY: *A = 1; *C = 0; break;
7126     case t_INT:  *A = itos(cusp); *C = 1; break;
7127     case t_FRAC: *A = itos(gel(cusp, 1)); *C = itos(gel(cusp, 2)); break;
7128     case t_REAL: case t_COMPLEX:
7129       *A = 0; *C = 0;
7130       if (gsigne(imag_i(cusp)) <= 0)
7131         pari_err_DOMAIN("mfeval","imag(tau)","<=",gen_0,cusp);
7132       return 0;
7133     default: pari_err_TYPE("cusp_AC", cusp);
7134   }
7135   return 1;
7136 }
7137 static GEN
cusp2mat(long A,long C)7138 cusp2mat(long A, long C)
7139 { long B, D;
7140   cbezout(A, C, &D, &B);
7141   return mkmat22s(A, -B, C, D);
7142 }
7143 static GEN
mkS(void)7144 mkS(void) { return mkmat22s(0,-1,1,0); }
7145 
7146 /* if t is a cusp, return F(t), else NULL */
7147 static GEN
evalcusp(GEN mf,GEN F,GEN t,long prec)7148 evalcusp(GEN mf, GEN F, GEN t, long prec)
7149 {
7150   long A, C;
7151   GEN R;
7152   if (!cusp_AC(t, &A,&C)) return NULL;
7153   if (C % mf_get_N(F) == 0) return gel(mfcoefs_i(F, 0, 1), 1);
7154   R = mfgaexpansion(mf, F, cusp2mat(A,C), 0, prec);
7155   return gequal0(gel(R,1))? gmael(R,3,1): gen_0;
7156 }
7157 /* Evaluate an mf closure numerically, i.e., in the usual sense, either for a
7158  * single tau or a vector of tau; for each, return a vector of results
7159  * corresponding to all complex embeddings of F. If flag is nonzero, allow
7160  * replacing F by F | gamma to increase imag(gamma^(-1).tau) [ expensive if
7161  * MF_EISENSPACE not present ] */
7162 static GEN
mfeval_i(GEN mf,GEN F,GEN vtau,long flag,long bitprec)7163 mfeval_i(GEN mf, GEN F, GEN vtau, long flag, long bitprec)
7164 {
7165   GEN L0, vL, vb, sqN, vczd, vTAU, vs, van, vE;
7166   long N = MF_get_N(mf), N0, ta, lv, i, prec = nbits2prec(bitprec);
7167   GEN gN = utoipos(N), gk = mf_get_gk(F), gk1 = gsubgs(gk,1), vgk;
7168   long flscal = 0;
7169 
7170   /* gen_0 is ignored, second component assumes Ramanujan-Petersson in
7171    * 1/2-integer weight */
7172   vgk = mkvec2(gen_0, mfiscuspidal(mf,F)? gmul2n(gk1,-1): gk1);
7173   ta = typ(vtau);
7174   if (!is_vec_t(ta)) { flscal = 1; vtau = mkvec(vtau); ta = t_VEC; }
7175   lv = lg(vtau);
7176   sqN = sqrtr_abs(utor(N, prec));
7177   vs = const_vec(lv-1, NULL);
7178   vb = const_vec(lv-1, NULL);
7179   vL = cgetg(lv, t_VEC);
7180   vTAU = cgetg(lv, t_VEC);
7181   vczd = cgetg(lv, t_VEC);
7182   L0 = mfthetaancreate(NULL, gN, vgk); /* only for thetacost */
7183   vE = mfgetembed(F, prec);
7184   N0 = 0;
7185   for (i = 1; i < lv; i++)
7186   {
7187     GEN z = gel(vtau,i), tau, U;
7188     long w, n;
7189 
7190     gel(vs,i) = evalcusp(mf, F, z, prec);
7191     if (gel(vs,i)) continue;
7192     tau = cxredga0N(N, z, &U, &gel(vczd,i), flag);
7193     if (!flag) w = 0; else { w = mfZC_width(N, gel(U,1)); tau = gdivgs(tau,w); }
7194     gel(vTAU,i) = mulcxmI(gmul(tau, sqN));
7195     n = lfunthetacost(L0, real_i(gel(vTAU,i)), 0, bitprec);
7196     if (N0 < n) N0 = n;
7197     if (flag)
7198     {
7199       GEN A, al, v = mfslashexpansion(mf, F, ZM_inv(U,NULL), n, 0, &A, prec);
7200       gel(vL,i) = van_embedall(v, vE, gN, vgk);
7201       al = gel(A,1);
7202       if (!gequal0(al))
7203         gel(vb,i) = gexp(gmul(gmul(gmulsg(w,al),PiI2(prec)), tau), prec);
7204     }
7205   }
7206   if (!flag)
7207   {
7208     van = mfcoefs_i(F, N0, 1);
7209     vL = const_vec(lv-1, van_embedall(van, vE, gN, vgk));
7210   }
7211   for (i = 1; i < lv; i++)
7212   {
7213     GEN T;
7214     if (gel(vs,i)) continue;
7215     T = gpow(gel(vczd,i), gneg(gk), prec);
7216     if (flag && gel(vb,i)) T = gmul(T, gel(vb,i));
7217     gel(vs,i) = lfunthetaall(T, gel(vL,i), gel(vTAU,i), bitprec);
7218   }
7219   return flscal? gel(vs,1): vs;
7220 }
7221 
7222 static long
mfistrivial(GEN F)7223 mfistrivial(GEN F)
7224 {
7225   switch(mf_get_type(F))
7226   {
7227     case t_MF_CONST: return lg(gel(F,2)) == 1;
7228     case t_MF_LINEAR: case t_MF_LINEAR_BHN: return gequal0(gel(F,3));
7229     default: return 0;
7230   }
7231 }
7232 
7233 static long
mf_same_k(GEN mf,GEN f)7234 mf_same_k(GEN mf, GEN f) { return gequal(MF_get_gk(mf), mf_get_gk(f)); }
7235 static long
mf_same_CHI(GEN mf,GEN f)7236 mf_same_CHI(GEN mf, GEN f)
7237 {
7238   GEN F1, F2, chi1, chi2, CHI1 = MF_get_CHI(mf), CHI2 = mf_get_CHI(f);
7239   /* are the primitive chars attached to CHI1 and CHI2 equal ? */
7240   F1 = znconreyconductor(gel(CHI1,1), gel(CHI1,2), &chi1);
7241   if (typ(F1) == t_VEC) F1 = gel(F1,1);
7242   F2 = znconreyconductor(gel(CHI2,1), gel(CHI2,2), &chi2);
7243   if (typ(F2) == t_VEC) F2 = gel(F2,1);
7244   return equalii(F1,F2) && ZV_equal(chi1,chi2);
7245 }
7246 /* check k and CHI rigorously, but not coefficients nor N */
7247 static long
mfisinspace_i(GEN mf,GEN F)7248 mfisinspace_i(GEN mf, GEN F)
7249 {
7250   return mfistrivial(F) || (mf_same_k(mf,F) && mf_same_CHI(mf,F));
7251 }
7252 static void
err_space(GEN F)7253 err_space(GEN F)
7254 { pari_err_DOMAIN("mftobasis", "form", "does not belong to",
7255                   strtoGENstr("space"), F); }
7256 
7257 static long
mfcheapeisen(GEN mf)7258 mfcheapeisen(GEN mf)
7259 {
7260   long k, L, N = MF_get_N(mf);
7261   GEN P;
7262   if (N <= 70) return 1;
7263   k = itos(gceil(MF_get_gk(mf)));
7264   if (odd(k)) k--;
7265   switch (k)
7266   {
7267     case 2:  L = 190; break;
7268     case 4:  L = 162; break;
7269     case 6:
7270     case 8:  L = 88; break;
7271     case 10: L = 78; break;
7272     default: L = 66; break;
7273   }
7274   P = gel(myfactoru(N), 1);
7275   return P[lg(P)-1] <= L;
7276 }
7277 
7278 static GEN
myimag_i(GEN tau)7279 myimag_i(GEN tau)
7280 {
7281   long tc = typ(tau);
7282   if (tc == t_INFINITY || tc == t_INT || tc == t_FRAC)
7283     return gen_1;
7284   if (tc == t_VEC)
7285   {
7286     long ltau, i;
7287     GEN z = cgetg_copy(tau, &ltau);
7288     for (i=1; i<ltau; i++) gel(z,i) = myimag_i(gel(tau,i));
7289     return z;
7290   }
7291   return imag_i(tau);
7292 }
7293 
7294 static GEN
mintau(GEN vtau)7295 mintau(GEN vtau)
7296 {
7297   if (!is_vec_t(typ(vtau))) return myimag_i(vtau);
7298   return (lg(vtau) == 1)? gen_1: vecmin(myimag_i(vtau));
7299 }
7300 
7301 /* initialization for mfgaexpansion: what does not depend on cusp */
7302 static GEN
mf_eisendec(GEN mf,GEN F,long prec)7303 mf_eisendec(GEN mf, GEN F, long prec)
7304 {
7305   GEN B = liftpol_shallow(mfeisensteindec(mf, F)), v = variables_vecsmall(B);
7306   GEN Mvecj = obj_check(mf, MF_EISENSPACE);
7307   long l = lg(v), i, ord;
7308   if (lg(Mvecj) < 5) Mvecj = gel(Mvecj,1);
7309   ord = itou(gel(Mvecj,4));
7310   for (i = 1; i < l; i++)
7311     if (v[i] != 1)
7312     {
7313       GEN d;
7314       long e;
7315       B = Q_remove_denom(B, &d);
7316       e = gexpo(B);
7317       if (e > 0) prec += nbits2prec(e);
7318       B = gsubst(B, v[i], rootsof1u_cx(ord, prec));
7319       if (d) B = gdiv(B, d);
7320       break;
7321     }
7322   return B;
7323 }
7324 
7325 GEN
mfeval(GEN mf0,GEN F,GEN vtau,long bitprec)7326 mfeval(GEN mf0, GEN F, GEN vtau, long bitprec)
7327 {
7328   pari_sp av = avma;
7329   long flnew = 1;
7330   GEN mf = checkMF_i(mf0);
7331   if (!mf) pari_err_TYPE("mfeval", mf0);
7332   if (!checkmf_i(F)) pari_err_TYPE("mfeval", F);
7333   if (!mfisinspace_i(mf, F)) err_space(F);
7334   if (!obj_check(mf, MF_EISENSPACE)) flnew = mfcheapeisen(mf);
7335   if (flnew && gcmpgs(gmulsg(2*MF_get_N(mf), mintau(vtau)), 1) >= 0) flnew = 0;
7336   return gerepilecopy(av, mfeval_i(mf, F, vtau, flnew, bitprec));
7337 }
7338 
7339 static long
val(GEN v,long bit)7340 val(GEN v, long bit)
7341 {
7342   long c, l = lg(v);
7343   for (c = 1; c < l; c++)
7344     if (gexpo(gel(v,c)) > -bit) return c-1;
7345   return -1;
7346 }
7347 GEN
mfcuspval(GEN mf,GEN F,GEN cusp,long bitprec)7348 mfcuspval(GEN mf, GEN F, GEN cusp, long bitprec)
7349 {
7350   pari_sp av = avma;
7351   long lvE, w, N, sb, n, A, C, prec = nbits2prec(bitprec);
7352   GEN ga, gk, vE;
7353   mf = checkMF(mf);
7354   if (!checkmf_i(F)) pari_err_TYPE("mfcuspval",F);
7355   N = MF_get_N(mf);
7356   cusp_canon(cusp, N, &A, &C);
7357   gk = mf_get_gk(F);
7358   if (typ(gk) != t_INT)
7359   {
7360     GEN FT = mfmultheta(F), mf2 = obj_checkbuild(mf, MF_MF2INIT, &mf2init);
7361     GEN r = mfcuspval(mf2, FT, cusp, bitprec);
7362     if ((C & 3L) == 2)
7363     {
7364       GEN z = sstoQ(1,4);
7365       r = gsub(r, typ(r) == t_VEC? const_vec(lg(r)-1, z): z);
7366     }
7367     return gerepileupto(av, r);
7368   }
7369   vE = mfgetembed(F, prec);
7370   lvE = lg(vE);
7371   w = mfcuspcanon_width(N, C);
7372   sb = w * mfsturmNk(N, itos(gk));
7373   ga = cusp2mat(A,C);
7374   for (n = 8;; n = minss(sb, n << 1))
7375   {
7376     GEN R = mfgaexpansion(mf, F, ga, n, prec), res = liftpol_shallow(gel(R,3));
7377     GEN v = cgetg(lvE-1, t_VECSMALL);
7378     long j, ok = 1;
7379     res = RgC_embedall(res, vE);
7380     for (j = 1; j < lvE; j++)
7381     {
7382       v[j] = val(gel(res,j), bitprec/2);
7383       if (v[j] < 0) ok = 0;
7384     }
7385     if (ok)
7386     {
7387       res = cgetg(lvE, t_VEC);
7388       for (j = 1; j < lvE; j++) gel(res,j) = gadd(gel(R,1), sstoQ(v[j], w));
7389       return gerepilecopy(av, lvE==2? gel(res,1): res);
7390     }
7391     if (n == sb) return lvE==2? mkoo(): const_vec(lvE-1, mkoo()); /* 0 */
7392   }
7393 }
7394 
7395 long
mfiscuspidal(GEN mf,GEN F)7396 mfiscuspidal(GEN mf, GEN F)
7397 {
7398   pari_sp av = avma;
7399   GEN mf2;
7400   if (space_is_cusp(MF_get_space(mf))) return 1;
7401   if (typ(mf_get_gk(F)) == t_INT)
7402   {
7403     GEN v = mftobasis(mf,F,0), vE = vecslice(v, 1, lg(MF_get_E(mf))-1);
7404     return gc_long(av, gequal0(vE));
7405   }
7406   if (!gequal0(mfak_i(F, 0))) return 0;
7407   mf2 = obj_checkbuild(mf, MF_MF2INIT, &mf2init);
7408   return mfiscuspidal(mf2, mfmultheta(F));
7409 }
7410 
7411 /* F = vector of newforms in mftobasis format */
7412 static GEN
mffrickeeigen_i(GEN mf,GEN F,GEN vE,long prec)7413 mffrickeeigen_i(GEN mf, GEN F, GEN vE, long prec)
7414 {
7415   GEN M, Z, L0, gN = MF_get_gN(mf), gk = MF_get_gk(mf);
7416   long N0, i, lM, bit = prec2nbits(prec), k = itou(gk);
7417   long LIM = 5; /* Sturm bound is enough */
7418 
7419   L0 = mfthetaancreate(NULL, gN, gk); /* only for thetacost */
7420 START:
7421   N0 = lfunthetacost(L0, gen_1, LIM, bit);
7422   M = mfcoefs_mf(mf, N0, 1);
7423   lM = lg(F);
7424   Z = cgetg(lM, t_VEC);
7425   for (i = 1; i < lM; i++)
7426   { /* expansion of D * F[i] */
7427     GEN D, z, van = RgM_RgC_mul(M, Q_remove_denom(gel(F,i), &D));
7428     GEN L = van_embedall(van, gel(vE,i), gN, gk);
7429     long l = lg(L), j, bit_add = D? expi(D): 0;
7430     gel(Z,i) = z = cgetg(l, t_VEC);
7431     for (j = 1; j < l; j++)
7432     {
7433       GEN v, C, C0;
7434       long m, e;
7435       for (m = 0; m <= LIM; m++)
7436       {
7437         v = lfuntheta(gmael(L,j,2), gen_1, m, bit);
7438         if (gexpo(v) > bit_add - bit/2) break;
7439       }
7440       if (m > LIM) { LIM <<= 1; goto START; }
7441       C = mulcxpowIs(gdiv(v,conj_i(v)), 2*m - k);
7442       C0 = grndtoi(C, &e); if (e < 5-bit_accuracy(precision(C))) C = C0;
7443       gel(z,j) = C;
7444     }
7445   }
7446   return Z;
7447 }
7448 static GEN
mffrickeeigen(GEN mf,GEN vE,long prec)7449 mffrickeeigen(GEN mf, GEN vE, long prec)
7450 {
7451   GEN D = obj_check(mf, MF_FRICKE);
7452   if (D) { long p = gprecision(D); if (!p || p >= prec) return D; }
7453   D = mffrickeeigen_i(mf, MF_get_newforms(mf), vE, prec);
7454   return obj_insert(mf, MF_FRICKE, D);
7455 }
7456 
7457 /* integral weight, new space for primitive quadratic character CHIP;
7458  * MF = vector of embedded eigenforms coefs on mfbasis, by orbit.
7459  * Assume N > Q > 1 and (Q,f(CHIP)) = 1 */
7460 static GEN
mfatkineigenquad(GEN mf,GEN CHIP,long Q,GEN MF,long bitprec)7461 mfatkineigenquad(GEN mf, GEN CHIP, long Q, GEN MF, long bitprec)
7462 {
7463   GEN L0, la2, S, F, vP, tau, wtau, Z, va, vb, den, coe, sqrtQ, sqrtN;
7464   GEN M, gN, gk = MF_get_gk(mf);
7465   long N0, x, yq, i, j, lF, dim, muQ, prec = nbits2prec(bitprec);
7466   long N = MF_get_N(mf), k = itos(gk), NQ = N / Q;
7467 
7468   /* Q coprime to FC */
7469   F = MF_get_newforms(mf);
7470   vP = MF_get_fields(mf);
7471   lF = lg(F);
7472   Z = cgetg(lF, t_VEC);
7473   S = MF_get_S(mf); dim = lg(S) - 1;
7474   muQ = mymoebiusu(Q);
7475   if (muQ)
7476   {
7477     GEN SQ = cgetg(dim+1,t_VEC), Qk = gpow(stoi(Q), sstoQ(k-2, 2), prec);
7478     long i, bit2 = bitprec >> 1;
7479     for (j = 1; j <= dim; j++) gel(SQ,j) = mfak_i(gel(S,j), Q);
7480     for (i = 1; i < lF; i++)
7481     {
7482       GEN S = RgV_dotproduct(gel(F,i), SQ), T = gel(vP,i);
7483       long e;
7484       if (degpol(T) > 1 && typ(S) != t_POLMOD) S = gmodulo(S, T);
7485       S = grndtoi(gdiv(conjvec(S, prec), Qk), &e);
7486       if (e > -bit2) pari_err_PREC("mfatkineigenquad");
7487       if (muQ == -1) S = gneg(S);
7488       gel(Z,i) = S;
7489     }
7490     return Z;
7491   }
7492   la2 = mfchareval(CHIP, Q); /* 1 or -1 */
7493   (void)cbezout(Q, NQ, &x, &yq);
7494   sqrtQ = sqrtr_abs(utor(Q,prec));
7495   tau = mkcomplex(gadd(sstoQ(-1, NQ), ginv(utoi(1000))),
7496                   divru(sqrtQ, N));
7497   den = gaddgs(gmulsg(NQ, tau), 1);
7498   wtau = gdiv(gsub(gmulsg(x, tau), sstoQ(yq, Q)), den);
7499   coe = gpowgs(gmul(sqrtQ, den), k);
7500 
7501   sqrtN = sqrtr_abs(utor(N,prec));
7502   tau  = mulcxmI(gmul(tau,  sqrtN));
7503   wtau = mulcxmI(gmul(wtau, sqrtN));
7504   gN = utoipos(N);
7505   L0 = mfthetaancreate(NULL, gN, gk); /* only for thetacost */
7506   N0 = maxss(lfunthetacost(L0,real_i(tau), 0,bitprec),
7507              lfunthetacost(L0,real_i(wtau),0,bitprec));
7508   M = mfcoefs_mf(mf, N0, 1);
7509   va = cgetg(dim+1, t_VEC);
7510   vb = cgetg(dim+1, t_VEC);
7511   for (j = 1; j <= dim; j++)
7512   {
7513     GEN L, v = vecslice(gel(M,j), 2, N0+1); /* remove a0 */
7514     settyp(v, t_VEC); L = mfthetaancreate(v, gN, gk);
7515     gel(va,j) = lfuntheta(L, tau,0,bitprec);
7516     gel(vb,j) = lfuntheta(L,wtau,0,bitprec);
7517   }
7518   for (i = 1; i < lF; i++)
7519   {
7520     GEN z, FE = gel(MF,i);
7521     long l = lg(FE);
7522     z = cgetg(l, t_VEC);
7523     for (j = 1; j < l; j++)
7524     {
7525       GEN f = gel(FE,j), a = RgV_dotproduct(va,f), b = RgV_dotproduct(vb,f);
7526       GEN la = ground( gdiv(b, gmul(a,coe)) );
7527       if (!gequal(gsqr(la), la2)) pari_err_PREC("mfatkineigenquad");
7528       if (typ(la) == t_INT)
7529       {
7530         if (j != 1) pari_err_BUG("mfatkineigenquad");
7531         z = const_vec(l-1, la); break;
7532       }
7533       gel(z,j) = la;
7534     }
7535     gel(Z,i) = z;
7536   }
7537   return Z;
7538 }
7539 
7540 static GEN
myusqrt(ulong a,long prec)7541 myusqrt(ulong a, long prec)
7542 {
7543   if (a == 1UL) return gen_1;
7544   if (uissquareall(a, &a)) return utoipos(a);
7545   return sqrtr_abs(utor(a, prec));
7546 }
7547 /* Assume mf is a nontrivial new space, rational primitive character CHIP
7548  * and (Q,FC) = 1 */
7549 static GEN
mfatkinmatnewquad(GEN mf,GEN CHIP,long Q,long flag,long PREC)7550 mfatkinmatnewquad(GEN mf, GEN CHIP, long Q, long flag, long PREC)
7551 {
7552   GEN cM, M, D, MF, den, vE, F = MF_get_newforms(mf);
7553   long i, c, e, prec, bitprec, lF = lg(F), N = MF_get_N(mf), k = MF_get_k(mf);
7554 
7555   if (Q == 1) return mkvec4(gen_0, matid(MF_get_dim(mf)), gen_1, mf);
7556   den = gel(MF_get_Minv(mf), 2);
7557   bitprec = expi(den) + 64;
7558   if (!flag) bitprec = maxss(bitprec, prec2nbits(PREC));
7559 
7560 START:
7561   prec = nbits2prec(bitprec);
7562   vE = mfeigenembed(mf, prec);
7563   M = cgetg(lF, t_VEC);
7564   for (i = 1; i < lF; i++) gel(M,i) = RgC_embedall(gel(F,i), gel(vE,i));
7565   if (Q != N)
7566   {
7567     D = mfatkineigenquad(mf, CHIP, Q, M, bitprec);
7568     c = odd(k)? Q: 1;
7569   }
7570   else
7571   {
7572     D = mffrickeeigen(mf, vE, prec);
7573     c = mfcharmodulus(CHIP); if (odd(k)) c = -Q/c;
7574   }
7575   D = shallowconcat1(D);
7576   if (vec_isconst(D)) { MF = diagonal_shallow(D); flag = 0; }
7577   else
7578   {
7579     M = shallowconcat1(M);
7580     MF = RgM_mul(matmuldiagonal(M,D), ginv(M));
7581   }
7582   if (!flag) return mkvec4(gen_0, MF, gen_1, mf);
7583 
7584   if (c > 0)
7585     cM = myusqrt(c, PREC);
7586   else
7587   {
7588     MF = imag_i(MF); c = -c;
7589     cM = mkcomplex(gen_0, myusqrt(c,PREC));
7590   }
7591   if (c != 1) MF = RgM_Rg_mul(MF, myusqrt(c,prec));
7592   MF = grndtoi(RgM_Rg_mul(MF,den), &e);
7593   if (e > -32) { bitprec <<= 1; goto START; }
7594   MF = RgM_Rg_div(MF, den);
7595   if (is_rational_t(typ(cM)) && !isint1(cM))
7596   { MF = RgM_Rg_div(MF, cM); cM = gen_1; }
7597   return mkvec4(gen_0, MF, cM, mf);
7598 }
7599 
7600 /* let CHI mod N, Q || N, return \bar{CHI_Q} * CHI_{N/Q} */
7601 static GEN
mfcharAL(GEN CHI,long Q)7602 mfcharAL(GEN CHI, long Q)
7603 {
7604   GEN G = gel(CHI,1), c = gel(CHI,2), cycc, d, P, E, F;
7605   long l = lg(c), N = mfcharmodulus(CHI), i;
7606   if (N == Q) return mfcharconj(CHI);
7607   if (N == 1) return CHI;
7608   CHI = leafcopy(CHI);
7609   gel(CHI,2) = d = leafcopy(c);
7610   F = znstar_get_faN(G);
7611   P = gel(F,1);
7612   E = gel(F,2);
7613   cycc = znstar_get_conreycyc(G);
7614   if (!odd(Q) && equaliu(gel(P,1), 2) && E[1] >= 3)
7615     gel(d,2) = Fp_neg(gel(d,2), gel(cycc,2));
7616   else for (i = 1; i < l; i++)
7617     if (!umodui(Q, gel(P,i))) gel(d,i) = Fp_neg(gel(d,i), gel(cycc,i));
7618   return CHI;
7619 }
7620 static long
atkin_get_NQ(long N,long Q,const char * f)7621 atkin_get_NQ(long N, long Q, const char *f)
7622 {
7623   long NQ = N / Q;
7624   if (N % Q) pari_err_DOMAIN(f,"N % Q","!=",gen_0,utoi(Q));
7625   if (ugcd(NQ, Q) > 1) pari_err_DOMAIN(f,"gcd(Q,N/Q)","!=",gen_1,utoi(Q));
7626   return NQ;
7627 }
7628 
7629 /* transform mf to new_NEW if possible */
7630 static GEN
MF_set_new(GEN mf)7631 MF_set_new(GEN mf)
7632 {
7633   GEN vMjd, vj, gk = MF_get_gk(mf);
7634   long l, j;
7635   if (MF_get_space(mf) != mf_CUSP
7636       || typ(gk) != t_INT || itou(gk) == 1) return mf;
7637   vMjd = MFcusp_get_vMjd(mf); l = lg(vMjd);
7638   if (l > 1 && gel(vMjd,1)[1] != MF_get_N(mf)) return mf; /* oldspace != 0 */
7639   mf = shallowcopy(mf);
7640   gel(mf,1) = shallowcopy(gel(mf,1));
7641   MF_set_space(mf, mf_NEW);
7642   vj = cgetg(l, t_VECSMALL);
7643   for (j = 1; j < l; j++) vj[j] = gel(vMjd, j)[2];
7644   gel(mf,4) = vj; return mf;
7645 }
7646 
7647 /* if flag = 1, rationalize, else don't */
7648 static GEN
mfatkininit_i(GEN mf,long Q,long flag,long prec)7649 mfatkininit_i(GEN mf, long Q, long flag, long prec)
7650 {
7651   GEN M, B, C, CHI, CHIAL, G, chi, P, z, g, mfB, s, Mindex, Minv;
7652   long j, l, lim, ord, FC, NQ, cQ, nk, dk, N = MF_get_N(mf);
7653 
7654   B = MF_get_basis(mf); l = lg(B);
7655   M = cgetg(l, t_MAT); if (l == 1) return mkvec4(gen_0,M,gen_1,mf);
7656   Qtoss(MF_get_gk(mf), &nk,&dk);
7657   Q = labs(Q);
7658   NQ = atkin_get_NQ(N, Q, "mfatkininit");
7659   CHI = MF_get_CHI(mf);
7660   CHI = mfchartoprimitive(CHI, &FC);
7661   ord = mfcharorder(CHI);
7662   mf = MF_set_new(mf);
7663   if (MF_get_space(mf) == mf_NEW && ord <= 2 && NQ % FC == 0 && dk == 1)
7664     return mfatkinmatnewquad(mf, CHI, Q, flag, prec);
7665   /* now flag != 0 */
7666   G   = gel(CHI,1);
7667   chi = gel(CHI,2);
7668   if (Q == N) { g = mkmat22s(0, -1, N, 0); cQ = NQ; } /* Fricke */
7669   else
7670   {
7671     GEN F, gQP = utoi(ugcd(Q, FC));
7672     long t, v;
7673     chi = znchardecompose(G, chi, gQP);
7674     F = znconreyconductor(G, chi, &chi);
7675     G = znstar0(F,1);
7676     (void)cbezout(Q, NQ, &t, &v);
7677     g = mkmat22s(Q*t, 1, -N*v, Q);
7678     cQ = -NQ*v;
7679   }
7680   C = s = gen_1;
7681   /* N.B. G,chi are G_Q,chi_Q [primitive] at this point */
7682   if (lg(chi) != 1) C = ginv( znchargauss(G, chi, gen_1, prec2nbits(prec)) );
7683   if (dk == 1)
7684   { if (odd(nk)) s = myusqrt(Q,prec); }
7685   else
7686   {
7687     long r = nk >> 1; /* k-1/2 */
7688     s = gpow(utoipos(Q), mkfracss(odd(r)? 1: 3, 4), prec);
7689     if (odd(cQ))
7690     {
7691       long t = r + ((cQ-1) >> 1);
7692       s = mkcomplex(s, odd(t)? gneg(s): s);
7693     }
7694   }
7695   if (!isint1(s)) C = gmul(C, s);
7696   CHIAL = mfcharAL(CHI, Q);
7697   if (dk == 2)
7698     CHIAL = mfcharmul(CHIAL, induce(gel(CHIAL,1), utoipos(odd(Q) ? Q<<2 : Q)));
7699   CHIAL = mfchartoprimitive(CHIAL,NULL);
7700   mfB = gequal(CHIAL,CHI)? mf: mfinit_Nndkchi(N,nk,dk,CHIAL,MF_get_space(mf),0);
7701   Mindex = MF_get_Mindex(mfB);
7702   Minv = MF_get_Minv(mfB);
7703   P = z = NULL;
7704   if (ord > 2) { P = mfcharpol(CHI); z = rootsof1u_cx(ord, prec); }
7705   lim = maxss(mfsturm(mfB), mfsturm(mf)) + 1;
7706   for (j = 1; j < l; j++)
7707   {
7708     GEN v = mfslashexpansion(mf, gel(B,j), g, lim, 0, NULL, prec+EXTRAPREC64);
7709     long junk;
7710     if (!isint1(C)) v = RgV_Rg_mul(v, C);
7711     v = bestapprnf(v, P, z, prec);
7712     v = vecpermute_partial(v, Mindex, &junk);
7713     v = Minv_RgC_mul(Minv, v); /* cf mftobasis_i */
7714     gel(M, j) = v;
7715   }
7716   if (is_rational_t(typ(C)) && !gequal1(C)) { M = gdiv(M, C); C = gen_1; }
7717   if (mfB == mf) mfB = gen_0;
7718   return mkvec4(mfB, M, C, mf);
7719 }
7720 GEN
mfatkininit(GEN mf,long Q,long prec)7721 mfatkininit(GEN mf, long Q, long prec)
7722 {
7723   pari_sp av = avma;
7724   mf = checkMF(mf); return gerepilecopy(av, mfatkininit_i(mf, Q, 1, prec));
7725 }
7726 static void
checkmfa(GEN z)7727 checkmfa(GEN z)
7728 {
7729   if (typ(z) != t_VEC || lg(z) != 5 || typ(gel(z,2)) != t_MAT
7730       || !checkMF_i(gel(z,4))
7731       || (!isintzero(gel(z,1)) && !checkMF_i(gel(z,1))))
7732     pari_err_TYPE("mfatkin [please apply mfatkininit()]",z);
7733 }
7734 
7735 /* Apply atkin Q to closure F */
7736 GEN
mfatkin(GEN mfa,GEN F)7737 mfatkin(GEN mfa, GEN F)
7738 {
7739   pari_sp av = avma;
7740   GEN z, mfB, MQ, mf;
7741   checkmfa(mfa);
7742   mfB= gel(mfa,1);
7743   MQ = gel(mfa,2);
7744   mf = gel(mfa,4);
7745   if (typ(mfB) == t_INT) mfB = mf;
7746   z = RgM_RgC_mul(MQ, mftobasis_i(mf,F));
7747   return gerepileupto(av, mflinear(mfB, z));
7748 }
7749 
7750 GEN
mfatkineigenvalues(GEN mf,long Q,long prec)7751 mfatkineigenvalues(GEN mf, long Q, long prec)
7752 {
7753   pari_sp av = avma;
7754   GEN vF, L, CHI, M, mfatk, C, MQ, vE, mfB;
7755   long N, NQ, l, i;
7756 
7757   mf = checkMF(mf); N = MF_get_N(mf);
7758   vF = MF_get_newforms(mf); l = lg(vF);
7759   /* N.B. k is integral */
7760   if (l == 1) { set_avma(av); return cgetg(1, t_VEC); }
7761   L = cgetg(l, t_VEC);
7762   if (Q == 1)
7763   {
7764     GEN vP = MF_get_fields(mf);
7765     for (i = 1; i < l; i++) gel(L,i) = const_vec(degpol(gel(vP,i)), gen_1);
7766     return L;
7767   }
7768   vE = mfeigenembed(mf,prec);
7769   if (Q == N) return gerepileupto(av, mffrickeeigen(mf, vE, prec));
7770   Q = labs(Q);
7771   NQ = atkin_get_NQ(N, Q, "mfatkineigenvalues"); /* != 1 */
7772   mfatk = mfatkininit(mf, Q, prec);
7773   mfB= gel(mfatk,1); if (typ(mfB) != t_VEC) mfB = mf;
7774   MQ = gel(mfatk,2);
7775   C  = gel(mfatk,3);
7776   M = row(mfcoefs_mf(mfB,1,1), 2); /* vec of a_1(b_i) for mfbasis functions */
7777   for (i = 1; i < l; i++)
7778   {
7779     GEN c = RgV_dotproduct(RgM_RgC_mul(MQ,gel(vF,i)), M); /* C * eigen_i */
7780     gel(L,i) = Rg_embedall_i(c, gel(vE,i));
7781   }
7782   if (!gequal1(C)) L = gdiv(L, C);
7783   CHI = MF_get_CHI(mf);
7784   if (mfcharorder(CHI) <= 2 && NQ % mfcharconductor(CHI) == 0) L = ground(L);
7785   return gerepilecopy(av, L);
7786 }
7787 
7788 /* expand B_d V, keeping same length */
7789 static GEN
bdexpand(GEN V,long d)7790 bdexpand(GEN V, long d)
7791 {
7792   GEN W;
7793   long N, n;
7794   if (d == 1) return V;
7795   N = lg(V)-1; W = zerovec(N);
7796   for (n = 0; n <= (N-1)/d; n++) gel(W, n*d+1) = gel(V, n+1);
7797   return W;
7798 }
7799 /* expand B_d V, increasing length up to lim */
7800 static GEN
bdexpandall(GEN V,long d,long lim)7801 bdexpandall(GEN V, long d, long lim)
7802 {
7803   GEN W;
7804   long N, n;
7805   if (d == 1) return V;
7806   N = lg(V)-1; W = zerovec(lim);
7807   for (n = 0; n <= N-1 && n*d <= lim; n++) gel(W, n*d+1) = gel(V, n+1);
7808   return W;
7809 }
7810 
7811 static void
parse_vecj(GEN T,GEN * E1,GEN * E2)7812 parse_vecj(GEN T, GEN *E1, GEN *E2)
7813 {
7814   if (lg(T)==3) { *E1 = gel(T,1); *E2 = gel(T,2); }
7815   else { *E1 = T; *E2 = NULL; }
7816 }
7817 
7818 /* g in M_2(Z) ? */
7819 static int
check_M2Z(GEN g)7820 check_M2Z(GEN g)
7821 {  return typ(g) == t_MAT && lg(g) == 3 && lgcols(g) == 3 && RgM_is_ZM(g); }
7822 /* g in SL_2(Z) ? */
7823 static int
check_SL2Z(GEN g)7824 check_SL2Z(GEN g) { return check_M2Z(g) && equali1(ZM_det(g)); }
7825 
7826 static GEN
mfcharcxeval(GEN CHI,long n,long prec)7827 mfcharcxeval(GEN CHI, long n, long prec)
7828 {
7829   ulong ord, N = mfcharmodulus(CHI);
7830   GEN ordg;
7831   if (N == 1) return gen_1;
7832   if (ugcd(N, labs(n)) > 1) return gen_0;
7833   ordg = gmfcharorder(CHI);
7834   ord = itou(ordg);
7835   return rootsof1q_cx(znchareval_i(CHI,n,ordg), ord, prec);
7836 }
7837 
7838 static GEN
RgV_shift(GEN V,GEN gn)7839 RgV_shift(GEN V, GEN gn)
7840 {
7841   long i, n, l;
7842   GEN W;
7843   if (typ(gn) != t_INT) pari_err_BUG("RgV_shift [n not integral]");
7844   n = itos(gn);
7845   if (n < 0) pari_err_BUG("RgV_shift [n negative]");
7846   if (!n) return V;
7847   W = cgetg_copy(V, &l); if (n > l-1) n = l-1;
7848   for (i=1; i <= n; i++) gel(W,i) = gen_0;
7849   for (    ; i < l; i++) gel(W,i) = gel(V, i-n);
7850   return W;
7851 }
7852 static GEN
hash_eisengacx(hashtable * H,void * E,long w,GEN ga,long n,long prec)7853 hash_eisengacx(hashtable *H, void *E, long w, GEN ga, long n, long prec)
7854 {
7855   ulong h = H->hash(E);
7856   hashentry *e = hash_search2(H, E, h);
7857   GEN v;
7858   if (e) v = (GEN)e->val;
7859   else
7860   {
7861     v = mfeisensteingacx((GEN)E, w, ga, n, prec);
7862     hash_insert2(H, E, (void*)v, h);
7863   }
7864   return v;
7865 }
7866 static GEN
vecj_expand(GEN B,hashtable * H,long w,GEN ga,long n,long prec)7867 vecj_expand(GEN B, hashtable *H, long w, GEN ga, long n, long prec)
7868 {
7869   GEN E1, E2, v;
7870   parse_vecj(B, &E1, &E2);
7871   v = hash_eisengacx(H, (void*)E1, w, ga, n, prec);
7872   if (E2)
7873   {
7874     GEN u = hash_eisengacx(H, (void*)E2, w, ga, n, prec);
7875     GEN a = gadd(gel(v,1), gel(u,1));
7876     GEN b = RgV_mul_RgXn(gel(v,2), gel(u,2));
7877     v = mkvec2(a,b);
7878   }
7879   return v;
7880 }
7881 static GEN
shift_M(GEN M,GEN Valpha,long w)7882 shift_M(GEN M, GEN Valpha, long w)
7883 {
7884   long i, l = lg(Valpha);
7885   GEN almin = vecmin(Valpha);
7886   for (i = 1; i < l; i++)
7887   {
7888     GEN alpha = gel(Valpha, i), gsh = gmulsg(w, gsub(alpha,almin));
7889     gel(M,i) = RgV_shift(gel(M,i), gsh);
7890   }
7891   return almin;
7892 }
7893 static GEN mfeisensteinspaceinit(GEN NK);
7894 #if 0
7895 /* ga in M_2^+(Z)), n >= 0 */
7896 static GEN
7897 mfgaexpansion_init(GEN mf, GEN ga, long n, long prec)
7898 {
7899   GEN M, Mvecj, vecj, almin, Valpha;
7900   long i, w, l, N = MF_get_N(mf), c = itos(gcoeff(ga,2,1));
7901   hashtable *H;
7902 
7903   if (c % N == 0)
7904   { /* ga in G_0(N), trivial case; w = 1 */
7905     GEN chid = mfcharcxeval(MF_get_CHI(mf), itos(gcoeff(ga,2,2)), prec);
7906     return mkvec2(chid, utoi(n));
7907   }
7908 
7909   Mvecj = obj_checkbuild(mf, MF_EISENSPACE, &mfeisensteinspaceinit);
7910   if (lg(Mvecj) < 5) pari_err_IMPL("mfgaexpansion_init in this case");
7911   w = mfcuspcanon_width(N, c);
7912   vecj = gel(Mvecj, 3);
7913   l = lg(vecj);
7914   M = cgetg(l, t_VEC);
7915   Valpha = cgetg(l, t_VEC);
7916   H = hash_create(l, (ulong(*)(void*))&hash_GEN,
7917                      (int(*)(void*,void*))&gidentical, 1);
7918   for (i = 1; i < l; i++)
7919   {
7920     GEN v = vecj_expand(gel(vecj,i), H, w, ga, n, prec);
7921     gel(Valpha,i) = gel(v,1);
7922     gel(M,i) = gel(v,2);
7923   }
7924   almin = shift_M(M, Valpha, w);
7925   return mkvec3(almin, utoi(w), M);
7926 }
7927 /* half-integer weight not supported; vF = [F,eisendec(F)].
7928  * Minit = mfgaexpansion_init(mf, ga, n, prec) */
7929 static GEN
7930 mfgaexpansion_with_init(GEN Minit, GEN vF)
7931 {
7932   GEN v;
7933   if (lg(Minit) == 3)
7934   { /* ga in G_0(N) */
7935     GEN chid = gel(Minit,1), gn = gel(Minit,2);
7936     v = mfcoefs_i(gel(vF,1), itou(gn), 1);
7937     v = mkvec3(gen_0, gen_1, RgV_Rg_mul(v,chid));
7938   }
7939   else
7940   {
7941     GEN V = RgM_RgC_mul(gel(Minit,3), gel(vF,2));
7942     v = mkvec3(gel(Minit,1), gel(Minit,2), V);
7943   }
7944   return v;
7945 }
7946 #endif
7947 
7948 /* B = mfeisensteindec(F) already embedded, ga in M_2^+(Z)), n >= 0 */
7949 static GEN
mfgaexpansion_i(GEN mf,GEN B0,GEN ga,long n,long prec)7950 mfgaexpansion_i(GEN mf, GEN B0, GEN ga, long n, long prec)
7951 {
7952   GEN M, Mvecj, vecj, almin, Valpha, B, E = NULL;
7953   long i, j, w, nw, l, N = MF_get_N(mf), bit = prec2nbits(prec) / 2;
7954   hashtable *H;
7955 
7956   Mvecj = obj_check(mf, MF_EISENSPACE);
7957   if (lg(Mvecj) < 5) { E = gel(Mvecj, 2); Mvecj = gel(Mvecj, 1); }
7958   vecj = gel(Mvecj, 3);
7959   l = lg(vecj);
7960   B = cgetg(l, t_COL);
7961   M = cgetg(l, t_VEC);
7962   Valpha = cgetg(l, t_VEC);
7963   w = mfZC_width(N, gel(ga,1));
7964   nw = E ? n + w : n;
7965   H = hash_create(l, (ulong(*)(void*))&hash_GEN,
7966                      (int(*)(void*,void*))&gidentical, 1);
7967   for (i = j = 1; i < l; i++)
7968   {
7969     GEN v;
7970     if (gequal0(gel(B0,i))) continue;
7971     v = vecj_expand(gel(vecj,i), H, w, ga, nw, prec);
7972     gel(B,j) = gel(B0,i);
7973     gel(Valpha,j) = gel(v,1);
7974     gel(M,j) = gel(v,2); j++;
7975   }
7976   setlg(Valpha, j);
7977   setlg(B, j);
7978   setlg(M, j); l = j;
7979   if (l == 1) return mkvec3(gen_0, utoi(w), zerovec(n+1));
7980   almin = shift_M(M, Valpha, w);
7981   B = RgM_RgC_mul(M, B); l = lg(B);
7982   for (i = 1; i < l; i++)
7983     if (gexpo(gel(B,i)) < -bit) gel(B,i) = gen_0;
7984   settyp(B, t_VEC);
7985   if (E)
7986   {
7987     GEN v, e;
7988     long ell = 0, vB, ve;
7989     for (i = 1; i < l; i++)
7990       if (!gequal0(gel(B,i))) break;
7991     vB = i-1;
7992     v = hash_eisengacx(H, (void*)E, w, ga, n + vB, prec);
7993     e = gel(v,2); l = lg(e);
7994     for (i = 1; i < l; i++)
7995       if (!gequal0(gel(e,i))) break;
7996     ve = i-1;
7997     almin = gsub(almin, gel(v,1));
7998     if (gsigne(almin) < 0)
7999     {
8000       GEN gell = gceil(gmulsg(-w, almin));
8001       ell = itos(gell);
8002       almin = gadd(almin, gdivgs(gell, w));
8003       if (nw < ell) pari_err_IMPL("alpha < 0 in mfgaexpansion");
8004     }
8005     if (ve) { ell += ve; e = vecslice(e, ve+1, l-1); }
8006     B = vecslice(B, ell + 1, minss(n + ell + 1, lg(B)-1));
8007     B = RgV_div_RgXn(B, e);
8008   }
8009   return mkvec3(almin, utoi(w), B);
8010 }
8011 
8012 /* Theta multiplier: assume 4 | C, (C,D)=1 */
8013 static GEN
mfthetamultiplier(GEN C,GEN D)8014 mfthetamultiplier(GEN C, GEN D)
8015 {
8016   long s = kronecker(C, D);
8017   if (Mod4(D) == 1) return s > 0 ? gen_1: gen_m1;
8018   return s > 0? powIs(3): gen_I();
8019 }
8020 /* theta | [*,*;C,D] defined over Q(i) [else over Q] */
8021 static int
mfthetaI(long C,long D)8022 mfthetaI(long C, long D) { return odd(C) || (D & 3) == 3; }
8023 /* (theta | M) [0..n], assume (C,D) = 1 */
8024 static GEN
mfthetaexpansion(GEN M,long n)8025 mfthetaexpansion(GEN M, long n)
8026 {
8027   GEN w, s, al, sla, E, V = zerovec(n+1), C = gcoeff(M,2,1), D = gcoeff(M,2,2);
8028   long lim, la, f, C4 = Mod4(C);
8029   switch (C4)
8030   {
8031     case 0: al = gen_0; w = gen_1;
8032       s = mfthetamultiplier(C,D);
8033       lim = usqrt(n); gel(V, 1) = s;
8034       s = gmul2n(s, 1);
8035       for (f = 1; f <= lim; f++) gel(V, f*f + 1) = s;
8036       break;
8037     case 2: al = sstoQ(1,4); w = gen_1;
8038       E = subii(C, shifti(D,1)); /* (E, D) = 1 */
8039       s = gmul2n(mfthetamultiplier(E, D), 1);
8040       if ((!signe(E) && equalim1(D)) || (signe(E) > 0 && signe(C) < 0))
8041         s = gneg(s);
8042       lim = (usqrt(n << 2) - 1) >> 1;
8043       for (f = 0; f <= lim; f++) gel(V, f*(f+1) + 1) = s;
8044       break;
8045     default: al = gen_0; w = utoipos(4);
8046       la = (-Mod4(D)*C4) & 3L;
8047       E = negi(addii(D, mului(la, C)));
8048       s = mfthetamultiplier(E, C); /* (E,C) = 1 */
8049       if (signe(C) < 0 && signe(E) >= 0) s = gneg(s);
8050       s = gsub(s, mulcxI(s));
8051       sla = gmul(s, powIs(-la));
8052       lim = usqrt(n); gel(V, 1) = gmul2n(s, -1);
8053       for (f = 1; f <= lim; f++) gel(V, f*f + 1) = odd(f) ? sla : s;
8054       break;
8055   }
8056   return mkvec3(al, w, V);
8057 }
8058 
8059 /* F 1/2 integral weight */
8060 static GEN
mf2gaexpansion(GEN mf2,GEN F,GEN ga,long n,long prec)8061 mf2gaexpansion(GEN mf2, GEN F, GEN ga, long n, long prec)
8062 {
8063   GEN FT = mfmultheta(F), mf = obj_checkbuild(mf2, MF_MF2INIT, &mf2init);
8064   GEN res, V1, Tres, V2, al, V, gsh, C = gcoeff(ga,2,1);
8065   long w2, N = MF_get_N(mf), w = mfcuspcanon_width(N, umodiu(C,N));
8066   long ext = (Mod4(C) != 2)? 0: (w+3) >> 2;
8067   long prec2 = prec + nbits2extraprec((long)M_PI/(2*M_LN2)*sqrt(n + ext));
8068   res = mfgaexpansion(mf, FT, ga, n + ext, prec2);
8069   Tres = mfthetaexpansion(ga, n + ext);
8070   V1 = gel(res,3);
8071   V2 = gel(Tres,3);
8072   al = gsub(gel(res,1), gel(Tres,1));
8073   w2 = itos(gel(Tres,2));
8074   if (w != itos(gel(res,2)) || w % w2)
8075     pari_err_BUG("mf2gaexpansion [incorrect w2 or w]");
8076   if (w2 != w) V2 = bdexpand(V2, w/w2);
8077   V = RgV_div_RgXn(V1, V2);
8078   gsh = gfloor(gmulsg(w, al));
8079   if (!gequal0(gsh))
8080   {
8081     al = gsub(al, gdivgs(gsh, w));
8082     if (gsigne(gsh) > 0)
8083     {
8084       V = RgV_shift(V, gsh);
8085       V = vecslice(V, 1, n + 1);
8086     }
8087     else
8088     {
8089       long sh = -itos(gsh), i;
8090       if (sh > ext) pari_err_BUG("mf2gaexpansion [incorrect sh]");
8091       for (i = 1; i <= sh; i++)
8092         if (!gequal0(gel(V,i))) pari_err_BUG("mf2gaexpansion [sh too large]");
8093       V = vecslice(V, sh+1, n + sh+1);
8094     }
8095   }
8096   obj_free(mf); return mkvec3(al, stoi(w), gprec_wtrunc(V, prec));
8097 }
8098 
8099 static GEN
mfgaexpansionatkin(GEN mf,GEN F,GEN C,GEN D,long Q,long n,long prec)8100 mfgaexpansionatkin(GEN mf, GEN F, GEN C, GEN D, long Q, long n, long prec)
8101 {
8102   GEN mfa = mfatkininit_i(mf, Q, 0, prec), MQ = gel(mfa,2);
8103   long i, FC, k = MF_get_k(mf);
8104   GEN x, v, V, z, s, CHI = mfchartoprimitive(MF_get_CHI(mf), &FC);
8105 
8106   /* V = mfcoefs(F | w_Q, n), can't use mfatkin because MQ nonrational */
8107   V = RgM_RgC_mul(mfcoefs_mf(mf,n,1), RgM_RgC_mul(MQ, mftobasis_i(mf,F)));
8108   (void)bezout(utoipos(Q), C, &x, &v);
8109   s = mfchareval(CHI, (umodiu(x, FC) * umodiu(D, FC)) % FC);
8110   s = gdiv(s, gpow(utoipos(Q), sstoQ(k,2), prec));
8111   V = RgV_Rg_mul(V, s);
8112   z = rootsof1powinit(umodiu(D,Q)*umodiu(v,Q) % Q, Q, prec);
8113   for (i = 1; i <= n+1; i++) gel(V,i) = gmul(gel(V,i), rootsof1pow(z, i-1));
8114   return mkvec3(gen_0, utoipos(Q), V);
8115 }
8116 
8117 static long
inveis_extraprec(long N,GEN ga,GEN Mvecj,long n)8118 inveis_extraprec(long N, GEN ga, GEN Mvecj, long n)
8119 {
8120   long e, w = mfZC_width(N, gel(ga,1));
8121   GEN f, E = gel(Mvecj,2), v = mfeisensteingacx(E, w, ga, n, DEFAULTPREC);
8122   v = gel(v,2);
8123   f = RgV_to_RgX(v,0); n -= RgX_valrem(f, &f);
8124   e = gexpo(RgXn_inv(f, n+1));
8125   return (e > 0)? nbits2extraprec(e): 0;
8126 }
8127 /* allow F of the form [F, mf_eisendec(F)]~ */
8128 static GEN
mfgaexpansion(GEN mf,GEN F,GEN ga,long n,long prec)8129 mfgaexpansion(GEN mf, GEN F, GEN ga, long n, long prec)
8130 {
8131   GEN v, EF = NULL, res, Mvecj, c, d;
8132   long precnew, N;
8133 
8134   if (n < 0) pari_err_DOMAIN("mfgaexpansion", "n", "<", gen_0, stoi(n));
8135   if (typ(F) == t_COL && lg(F) == 3) { EF = gel(F,2); F = gel(F,1); }
8136   if (!checkmf_i(F)) pari_err_TYPE("mfgaexpansion", F);
8137   if (!check_SL2Z(ga)) pari_err_TYPE("mfgaexpansion",ga);
8138   if (typ(mf_get_gk(F)) != t_INT) return mf2gaexpansion(mf, F, ga, n, prec);
8139   c = gcoeff(ga,2,1);
8140   d = gcoeff(ga,2,2);
8141   N = MF_get_N(mf);
8142   if (!umodiu(c, mf_get_N(F)))
8143   { /* trivial case: ga in Gamma_0(N) */
8144     long w = mfcuspcanon_width(N, umodiu(c,N));
8145     GEN CHI = mf_get_CHI(F);
8146     GEN chid = mfcharcxeval(CHI, umodiu(d,mfcharmodulus(CHI)), prec);
8147     v = mfcoefs_i(F, n/w, 1); if (!isint1(chid)) v = RgV_Rg_mul(v,chid);
8148     return mkvec3(gen_0, stoi(w), bdexpandall(v,w,n+1));
8149   }
8150   mf = MF_set_new(mf);
8151   if (MF_get_space(mf) == mf_NEW)
8152   {
8153     long cN = umodiu(c,N), g = ugcd(cN,N), Q = N/g;
8154     GEN CHI = MF_get_CHI(mf);
8155     if (ugcd(cN, Q)==1 && mfcharorder(CHI) <= 2
8156                        && g % mfcharconductor(CHI) == 0
8157                        && degpol(mf_get_field(F)) == 1)
8158       return mfgaexpansionatkin(mf, F, c, d, Q, n, prec);
8159   }
8160   Mvecj = obj_checkbuild(mf, MF_EISENSPACE, &mfeisensteinspaceinit);
8161   precnew = prec;
8162   if (lg(Mvecj) < 5) precnew += inveis_extraprec(N, ga, Mvecj, n);
8163   if (!EF) EF = mf_eisendec(mf, F, precnew);
8164   res = mfgaexpansion_i(mf, EF, ga, n, precnew);
8165   return precnew == prec ? res : gprec_wtrunc(res, prec);
8166 }
8167 
8168 /* parity = -1 or +1 */
8169 static GEN
findd(long N,long parity)8170 findd(long N, long parity)
8171 {
8172   GEN L, D = mydivisorsu(N);
8173   long i, j, l = lg(D);
8174   L = cgetg(l, t_VEC);
8175   for (i = j = 1; i < l; i++)
8176   {
8177     long d = D[i];
8178     if (parity == -1) d = -d;
8179     if (sisfundamental(d)) gel(L,j++) = stoi(d);
8180   }
8181   setlg(L,j); return L;
8182 }
8183 /* does ND contain a divisor of N ? */
8184 static int
seenD(long N,GEN ND)8185 seenD(long N, GEN ND)
8186 {
8187   long j, l = lg(ND);
8188   for (j = 1; j < l; j++)
8189     if (N % ND[j] == 0) return 1;
8190   return 0;
8191 }
8192 static GEN
search_levels(GEN vN,const char * f)8193 search_levels(GEN vN, const char *f)
8194 {
8195   switch(typ(vN))
8196   {
8197     case t_INT: vN = mkvecsmall(itos(vN)); break;
8198     case t_VEC: case t_COL: vN = ZV_to_zv(vN); break;
8199     case t_VECSMALL: vN = leafcopy(vN); break;
8200     default: pari_err_TYPE(f, vN);
8201   }
8202   vecsmall_sort(vN); return vN;
8203 }
8204 GEN
mfsearch(GEN NK,GEN V,long space)8205 mfsearch(GEN NK, GEN V, long space)
8206 {
8207   pari_sp av = avma;
8208   GEN F, gk, NbyD, vN;
8209   long n, nk, dk, parity, nV, i, lvN;
8210 
8211   if (typ(NK) != t_VEC || lg(NK) != 3) pari_err_TYPE("mfsearch", NK);
8212   gk = gel(NK,2);
8213   if (typ(gmul2n(gk, 1)) != t_INT) pari_err_TYPE("mfsearch [k]", gk);
8214   switch(typ(V))
8215   {
8216     case t_VEC: V = shallowtrans(V);
8217     case t_COL: break;
8218     default: pari_err_TYPE("mfsearch [V]", V);
8219   }
8220   vN = search_levels(gel(NK,1), "mfsearch [N]");
8221   if (gequal0(V)) { set_avma(av); retmkvec(mftrivial()); }
8222   lvN = lg(vN);
8223 
8224   Qtoss(gk, &nk,&dk);
8225   parity = (dk == 1 && odd(nk)) ? -1 : 1;
8226   nV = lg(V)-2;
8227   F = cgetg(1, t_VEC);
8228   NbyD = const_vec(vN[lvN-1], cgetg(1,t_VECSMALL));
8229   for (n = 1; n < lvN; n++)
8230   {
8231     long N = vN[n];
8232     GEN L;
8233     if (N <= 0 || (dk == 2 && (N & 3))) continue;
8234     L = findd(N, parity);
8235     for (i = 1; i < lg(L); i++)
8236     {
8237       GEN mf, M, CO, gD = gel(L,i);
8238       GEN *ND = (GEN*)NbyD + itou(gD); /* points to NbyD[|D|] */
8239 
8240       if (seenD(N, *ND)) continue;
8241       mf = mfinit_Nndkchi(N, nk, dk, get_mfchar(gD), space, 1);
8242       M = mfcoefs_mf(mf, nV, 1);
8243       CO = inverseimage(M, V); if (lg(CO) == 1) continue;
8244 
8245       F = vec_append(F, mflinear(mf,CO));
8246       *ND = vecsmall_append(*ND, N); /* add to NbyD[|D|] */
8247     }
8248   }
8249   return gerepilecopy(av, F);
8250 }
8251 
8252 static GEN
search_from_split(GEN mf,GEN vap,GEN vlp)8253 search_from_split(GEN mf, GEN vap, GEN vlp)
8254 {
8255   pari_sp av = avma;
8256   long lvlp = lg(vlp), j, jv, l1;
8257   GEN v, NK, S1, S, M = NULL;
8258 
8259   S1 = gel(split_i(mf, 1, 0), 1); /* rational newforms */
8260   l1 = lg(S1);
8261   if (l1 == 1) return gc_NULL(av);
8262   v = cgetg(l1, t_VEC);
8263   S = MF_get_S(mf);
8264   NK = mf_get_NK(gel(S,1));
8265   if (lvlp > 1) M = rowpermute(mfcoefs_mf(mf, vlp[lvlp-1], 1), vlp);
8266   for (j = jv = 1; j < l1; j++)
8267   {
8268     GEN vF = gel(S1,j);
8269     long t;
8270     for (t = lvlp-1; t > 0; t--)
8271     { /* lhs = vlp[j]-th coefficient of eigenform */
8272       GEN rhs = gel(vap,t), lhs = RgMrow_RgC_mul(M, vF, t);
8273       if (!gequal(lhs, rhs)) break;
8274     }
8275     if (!t) gel(v,jv++) = mflinear_i(NK,S,vF);
8276   }
8277   if (jv == 1) return gc_NULL(av);
8278   setlg(v,jv); return v;
8279 }
8280 GEN
mfeigensearch(GEN NK,GEN AP)8281 mfeigensearch(GEN NK, GEN AP)
8282 {
8283   pari_sp av = avma;
8284   GEN k, vN, vap, vlp, vres = cgetg(1, t_VEC), D;
8285   long n, lvN, i, l, even;
8286 
8287   if (!AP) l = 1;
8288   else
8289   {
8290     l = lg(AP);
8291     if (typ(AP) != t_VEC) pari_err_TYPE("mfeigensearch",AP);
8292   }
8293   vap = cgetg(l, t_VEC);
8294   vlp = cgetg(l, t_VECSMALL);
8295   if (l > 1)
8296   {
8297     GEN perm = indexvecsort(AP, mkvecsmall(1));
8298     for (i = 1; i < l; i++)
8299     {
8300       GEN v = gel(AP,perm[i]), gp, ap;
8301       if (typ(v) != t_VEC || lg(v) != 3) pari_err_TYPE("mfeigensearch", AP);
8302       gp = gel(v,1);
8303       ap = gel(v,2);
8304       if (typ(gp) != t_INT || (typ(ap) != t_INT && typ(ap) != t_INTMOD))
8305         pari_err_TYPE("mfeigensearch", AP);
8306       gel(vap,i) = ap;
8307       vlp[i] = itos(gp)+1; if (vlp[i] < 0) pari_err_TYPE("mfeigensearch", AP);
8308     }
8309   }
8310   l = lg(NK);
8311   if (typ(NK) != t_VEC || l != 3) pari_err_TYPE("mfeigensearch",NK);
8312   k = gel(NK,2);
8313   vN = search_levels(gel(NK,1), "mfeigensearch [N]");
8314   lvN = lg(vN);
8315   vecsmall_sort(vlp);
8316   even = !mpodd(k);
8317   for (n = 1; n < lvN; n++)
8318   {
8319     pari_sp av2 = avma;
8320     GEN mf, L;
8321     long N = vN[n];
8322     if (even) D = gen_1;
8323     else
8324     {
8325       long r = (N&3L);
8326       if (r == 1 || r == 2) continue;
8327       D = stoi( corediscs(-N, NULL) ); /* < 0 */
8328     }
8329     mf = mfinit_i(mkvec3(utoipos(N), k, D), mf_NEW);
8330     L = search_from_split(mf, vap, vlp);
8331     if (L) vres = shallowconcat(vres, L); else set_avma(av2);
8332   }
8333   return gerepilecopy(av, vres);
8334 }
8335 
8336 /* tf_{N,k}(n) */
8337 static GEN
mfnewtracecache(long N,long k,long n,cachenew_t * cache)8338 mfnewtracecache(long N, long k, long n, cachenew_t *cache)
8339 {
8340   GEN C = NULL, S;
8341   long lcache;
8342   if (!n) return gen_0;
8343   S = gel(cache->vnew,N);
8344   lcache = lg(S);
8345   if (n < lcache) C = gel(S, n);
8346   if (C) cache->newHIT++;
8347   else C = mfnewtrace_i(N,k,n,cache);
8348   cache->newTOTAL++;
8349   if (n < lcache) gel(S,n) = C;
8350   return C;
8351 }
8352 
8353 static long
mfdim_Nkchi(long N,long k,GEN CHI,long space)8354 mfdim_Nkchi(long N, long k, GEN CHI, long space)
8355 {
8356   if (k < 0 || badchar(N,k,CHI)) return 0;
8357   if (k == 0)
8358     return mfcharistrivial(CHI) && !space_is_cusp(space)? 1: 0;
8359   switch(space)
8360   {
8361     case mf_NEW: return mfnewdim(N,k,CHI);
8362     case mf_CUSP:return mfcuspdim(N,k,CHI);
8363     case mf_OLD: return mfolddim(N,k,CHI);
8364     case mf_FULL:return mffulldim(N,k,CHI);
8365     case mf_EISEN: return mfeisensteindim(N,k,CHI);
8366     default: pari_err_FLAG("mfdim");
8367   }
8368   return 0;/*LCOV_EXCL_LINE*/
8369 }
8370 static long
mfwt1dimsum(long N,long space)8371 mfwt1dimsum(long N, long space)
8372 {
8373   switch(space)
8374   {
8375     case mf_NEW:  return mfwt1newdimsum(N);
8376     case mf_CUSP: return mfwt1cuspdimsum(N);
8377     case mf_OLD:  return mfwt1olddimsum(N);
8378   }
8379   pari_err_FLAG("mfdim");
8380   return 0; /*LCOV_EXCL_LINE*/
8381 }
8382 /* mfdim for k = nk/dk */
8383 static long
mfdim_Nndkchi(long N,long nk,long dk,GEN CHI,long space)8384 mfdim_Nndkchi(long N, long nk, long dk, GEN CHI, long space)
8385 { return (dk == 2)? mf2dim_Nkchi(N, nk >> 1, CHI, space)
8386                   : mfdim_Nkchi(N, nk, CHI, space); }
8387 /* FIXME: use direct dim Gamma1(N) formula, don't compute individual spaces */
8388 static long
mfwtkdimsum(long N,long k,long dk,long space)8389 mfwtkdimsum(long N, long k, long dk, long space)
8390 {
8391   GEN w = mfchars(N, k, dk, NULL);
8392   long i, j, D = 0, l = lg(w);
8393   for (i = j = 1; i < l; i++)
8394   {
8395     GEN CHI = gel(w,i);
8396     long d = mfdim_Nndkchi(N,k,dk,CHI,space);
8397     if (d) D += d * myeulerphiu(mfcharorder(CHI));
8398   }
8399   return D;
8400 }
8401 static GEN
mfwt1dims(long N,GEN vCHI,long space)8402 mfwt1dims(long N, GEN vCHI, long space)
8403 {
8404   GEN D = NULL;
8405   switch(space)
8406   {
8407     case mf_NEW: D = mfwt1newdimall(N, vCHI); break;
8408     case mf_CUSP:D = mfwt1cuspdimall(N, vCHI); break;
8409     case mf_OLD: D = mfwt1olddimall(N, vCHI); break;
8410     default: pari_err_FLAG("mfdim");
8411   }
8412   return D;
8413 }
8414 static GEN
mfwtkdims(long N,long k,long dk,GEN vCHI,long space)8415 mfwtkdims(long N, long k, long dk, GEN vCHI, long space)
8416 {
8417   GEN D, w = mfchars(N, k, dk, vCHI);
8418   long i, j, l = lg(w);
8419   D = cgetg(l, t_VEC);
8420   for (i = j = 1; i < l; i++)
8421   {
8422     GEN CHI = gel(w,i);
8423     long d = mfdim_Nndkchi(N,k,dk,CHI,space);
8424     if (vCHI)
8425       gel(D, j++) = mkvec2s(d, 0);
8426     else if (d)
8427       gel(D, j++) = fmt_dim(CHI, d, 0);
8428   }
8429   setlg(D,j); return D;
8430 }
8431 GEN
mfdim(GEN NK,long space)8432 mfdim(GEN NK, long space)
8433 {
8434   pari_sp av = avma;
8435   long N, k, dk, joker;
8436   GEN CHI, mf;
8437   if ((mf = checkMF_i(NK))) return utoi(MF_get_dim(mf));
8438   checkNK2(NK, &N, &k, &dk, &CHI, 2);
8439   if (!CHI) joker = 1;
8440   else
8441     switch(typ(CHI))
8442     {
8443       case t_INT: joker = 2; break;
8444       case t_COL: joker = 3; break;
8445       default: joker = 0; break;
8446     }
8447   if (joker)
8448   {
8449     long d;
8450     GEN D;
8451     if (k < 0) switch(joker)
8452     {
8453       case 1: return cgetg(1,t_VEC);
8454       case 2: return gen_0;
8455       case 3: return mfdim0all(CHI);
8456     }
8457     if (k == 0)
8458     {
8459       if (space_is_cusp(space)) switch(joker)
8460       {
8461         case 1: return cgetg(1,t_VEC);
8462         case 2: return gen_0;
8463         case 3: return mfdim0all(CHI);
8464       }
8465       switch(joker)
8466       {
8467         long i, l;
8468         case 1: retmkvec(fmt_dim(mfchartrivial(),0,0));
8469         case 2: return gen_1;
8470         case 3: l = lg(CHI); D = cgetg(l,t_VEC);
8471                 for (i = 1; i < l; i++)
8472                 {
8473                   long t = mfcharistrivial(gel(CHI,i));
8474                   gel(D,i) = mkvec2(t? gen_1: gen_0, gen_0);
8475                 }
8476                 return D;
8477       }
8478     }
8479     if (dk == 1 && k == 1 && space != mf_EISEN)
8480     {
8481       long fix = 0, space0 = space;
8482       if (space == mf_FULL) space = mf_CUSP; /* remove Eisenstein part */
8483       if (joker == 2)
8484       {
8485         d = mfwt1dimsum(N, space);
8486         if (space0 == mf_FULL) d += mfwtkdimsum(N,k,dk,mf_EISEN);/*add it back*/
8487         set_avma(av); return utoi(d);
8488       }
8489       /* must initialize explicitly: trivial spaces for E_k/S_k differ */
8490       if (space0 == mf_FULL)
8491       {
8492         if (!CHI) fix = 1; /* must remove 0 spaces */
8493         CHI = mfchars(N, k, dk, CHI);
8494       }
8495       D = mfwt1dims(N, CHI, space);
8496       if (space0 == mf_FULL)
8497       {
8498         GEN D2 = mfwtkdims(N, k, dk, CHI, mf_EISEN);
8499         D = merge_dims(D, D2, fix? CHI: NULL);
8500       }
8501     }
8502     else
8503     {
8504       if (joker==2) { d = mfwtkdimsum(N,k,dk,space); set_avma(av); return utoi(d); }
8505       D = mfwtkdims(N, k, dk, CHI, space);
8506     }
8507     if (!CHI) return gerepileupto(av, vecsort(D, mkvecsmall(1)));
8508     return gerepilecopy(av, D);
8509   }
8510   return utoi( mfdim_Nndkchi(N, k, dk, CHI, space) );
8511 }
8512 
8513 GEN
mfbasis(GEN NK,long space)8514 mfbasis(GEN NK, long space)
8515 {
8516   pari_sp av = avma;
8517   long N, k, dk;
8518   GEN mf, CHI;
8519   if ((mf = checkMF_i(NK))) return concat(gel(mf,2), gel(mf,3));
8520   checkNK2(NK, &N, &k, &dk, &CHI, 0);
8521   if (dk == 2) return gerepilecopy(av, mf2basis(N, k>>1, CHI, NULL, space));
8522   mf = mfinit_Nkchi(N, k, CHI, space, 1);
8523   return gerepilecopy(av, MF_get_basis(mf));
8524 }
8525 
8526 static GEN
deg1ser_shallow(GEN a1,GEN a0,long v,long e)8527 deg1ser_shallow(GEN a1, GEN a0, long v, long e)
8528 { return RgX_to_ser(deg1pol_shallow(a1, a0, v), e+2); }
8529 /* r / x + O(1) */
8530 static GEN
simple_pole(GEN r)8531 simple_pole(GEN r)
8532 {
8533   GEN S = deg1ser_shallow(gen_0, r, 0, 1);
8534   setvalp(S, -1); return S;
8535 }
8536 
8537 /* F form, E embedding; mfa = mfatkininit or root number (eigenform case) */
8538 static GEN
mflfuncreate(GEN mfa,GEN F,GEN E,GEN N,GEN gk)8539 mflfuncreate(GEN mfa, GEN F, GEN E, GEN N, GEN gk)
8540 {
8541   GEN LF = cgetg(8,t_VEC), polar = cgetg(1,t_COL), eps;
8542   long k = itou(gk);
8543   gel(LF,1) = lfuntag(t_LFUN_MFCLOS, mkvec3(F,E,gen_1));
8544   if (typ(mfa) != t_VEC)
8545     eps = mfa; /* cuspidal eigenform: root number; no poles */
8546   else
8547   { /* mfatkininit */
8548     GEN a0, b0, vF, vG, G = NULL;
8549     GEN M = gel(mfa,2), C = gel(mfa,3), mf = gel(mfa,4);
8550     M = gdiv(mfmatembed(E, M), C);
8551     vF = mfvecembed(E, mftobasis_i(mf, F));
8552     vG = RgM_RgC_mul(M, vF);
8553     if (gequal(vF,vG)) eps = gen_1;
8554     else if (gequal(vF,gneg(vG))) eps = gen_m1;
8555     else
8556     { /* not self-dual */
8557       eps = NULL;
8558       G = mfatkin(mfa, F);
8559       gel(LF,2) = lfuntag(t_LFUN_MFCLOS, mkvec3(G,E,ginv(C)));
8560       gel(LF,6) = powIs(k);
8561     }
8562     /* polar part */
8563     a0 = mfembed(E, mfcoef(F,0));
8564     b0 = eps? gmul(eps,a0): gdiv(mfembed(E, mfcoef(G,0)), C);
8565     if (!gequal0(b0))
8566     {
8567       b0 = mulcxpowIs(gmul2n(b0,1), k);
8568       polar = vec_append(polar, mkvec2(gk, simple_pole(b0)));
8569     }
8570     if (!gequal0(a0))
8571     {
8572       a0 = gneg(gmul2n(a0,1));
8573       polar = vec_append(polar, mkvec2(gen_0, simple_pole(a0)));
8574     }
8575   }
8576   if (eps) /* self-dual */
8577   {
8578     gel(LF,2) = mfcharorder(mf_get_CHI(F)) <= 2? gen_0: gen_1;
8579     gel(LF,6) = mulcxpowIs(eps,k);
8580   }
8581   gel(LF,3) = mkvec2(gen_0, gen_1);
8582   gel(LF,4) = gk;
8583   gel(LF,5) = N;
8584   if (lg(polar) == 1) setlg(LF,7); else gel(LF,7) = polar;
8585   return LF;
8586 }
8587 static GEN
mflfuncreateall(long sd,GEN mfa,GEN F,GEN vE,GEN gN,GEN gk)8588 mflfuncreateall(long sd, GEN mfa, GEN F, GEN vE, GEN gN, GEN gk)
8589 {
8590   long i, l = lg(vE);
8591   GEN L = cgetg(l, t_VEC);
8592   for (i = 1; i < l; i++)
8593     gel(L,i) = mflfuncreate(sd? gel(mfa,i): mfa, F, gel(vE,i), gN, gk);
8594   return L;
8595 }
8596 GEN
lfunmf(GEN mf,GEN F,long bitprec)8597 lfunmf(GEN mf, GEN F, long bitprec)
8598 {
8599   pari_sp av = avma;
8600   long i, l, prec = nbits2prec(bitprec);
8601   GEN L, gk, gN;
8602   mf = checkMF(mf);
8603   gk = MF_get_gk(mf);
8604   gN = MF_get_gN(mf);
8605   if (typ(gk)!=t_INT) pari_err_IMPL("half-integral weight");
8606   if (F)
8607   {
8608     GEN v;
8609     long s = MF_get_space(mf);
8610     if (!checkmf_i(F)) pari_err_TYPE("lfunmf", F);
8611     if (!mfisinspace_i(mf, F)) err_space(F);
8612     L = NULL;
8613     if ((s == mf_NEW || s == mf_CUSP || s == mf_FULL)
8614         && gequal(mfcoefs_i(F,1,1), mkvec2(gen_0,gen_1)))
8615     { /* check if eigenform */
8616       GEN vP, vF, b = mftobasis_i(mf, F);
8617       long lF, d = degpol(mf_get_field(F));
8618       v = mfsplit(mf, d, 0);
8619       vF = gel(v,1);
8620       vP = gel(v,2); lF = lg(vF);
8621       for (i = 1; i < lF; i++)
8622         if (degpol(gel(vP,i)) == d && gequal(gel(vF,i), b))
8623         {
8624           GEN vE = mfgetembed(F, prec);
8625           GEN Z = mffrickeeigen_i(mf, mkvec(b), mkvec(vE), prec);
8626           L = mflfuncreateall(1, gel(Z,1), F, vE, gN, gk);
8627           break;
8628         }
8629     }
8630     if (!L)
8631     { /* not an eigenform: costly general case */
8632       GEN mfa = mfatkininit_i(mf, itou(gN), 1, prec);
8633       L = mflfuncreateall(0,mfa, F, mfgetembed(F,prec), gN, gk);
8634     }
8635     if (lg(L) == 2) L = gel(L,1);
8636   }
8637   else
8638   {
8639     GEN M = mfeigenbasis(mf), vE = mfeigenembed(mf, prec);
8640     GEN v = mffrickeeigen(mf, vE, prec);
8641     l = lg(vE); L = cgetg(l, t_VEC);
8642     for (i = 1; i < l; i++)
8643       gel(L,i) = mflfuncreateall(1,gel(v,i), gel(M,i), gel(vE,i), gN, gk);
8644   }
8645   return gerepilecopy(av, L);
8646 }
8647 
8648 GEN
mffromell(GEN E)8649 mffromell(GEN E)
8650 {
8651   pari_sp av = avma;
8652   GEN mf, F, z, v, S;
8653   long N, i, l;
8654 
8655   checkell(E);
8656   if (ell_get_type(E) != t_ELL_Q) pari_err_TYPE("mfffromell [E not over Q]", E);
8657   N = itos(ellQ_get_N(E));
8658   mf = mfinit_i(mkvec2(utoi(N), gen_2), mf_NEW);
8659   v = split_i(mf, 1, 0);
8660   S = gel(v,1); l = lg(S); /* rational newforms */
8661   F = tag(t_MF_ELL, mkNK(N,2,mfchartrivial()), E);
8662   z = mftobasis_i(mf, F);
8663   for(i = 1; i < l; i++)
8664     if (gequal(z, gel(S,i))) break;
8665   if (i == l) pari_err_BUG("mffromell [E is not modular]");
8666   return gerepilecopy(av, mkvec3(mf, F, z));
8667 }
8668 
8669 /* returns -1 if not, degree otherwise */
8670 long
polishomogeneous(GEN P)8671 polishomogeneous(GEN P)
8672 {
8673   long i, D, l;
8674   if (typ(P) != t_POL) return 0;
8675   D = -1; l = lg(P);
8676   for (i = 2; i < l; i++)
8677   {
8678     GEN c = gel(P,i);
8679     long d;
8680     if (gequal0(c)) continue;
8681     d = polishomogeneous(c);
8682     if (d < 0) return -1;
8683     if (D < 0) D = d + i-2; else if (D != d + i-2) return -1;
8684   }
8685   return D;
8686 }
8687 
8688 /* P a t_POL, 1 if spherical, 0 otherwise */
8689 static int
RgX_isspherical(GEN Qi,GEN P)8690 RgX_isspherical(GEN Qi, GEN P)
8691 {
8692   pari_sp av = avma;
8693   GEN va, S;
8694   long lva, i, j;
8695   va = variables_vecsmall(P); lva = lg(va);
8696   if (lva > lg(Qi)) pari_err(e_MISC, "too many variables in mffromqf");
8697   S = gen_0;
8698   for (j = 1; j < lva; j++)
8699   {
8700     GEN col = gel(Qi, j), Pj = deriv(P, va[j]);
8701     for (i = 1; i <= j; i++)
8702     {
8703       GEN coe = gel(col, i);
8704       if (i != j) coe = gmul2n(coe, 1);
8705       if (!gequal0(coe)) S = gadd(S, gmul(coe, deriv(Pj, va[i])));
8706     }
8707   }
8708   return gc_bool(av, gequal0(S));
8709 }
8710 
8711 static GEN
c_QFsimple_i(long n,GEN Q,GEN P)8712 c_QFsimple_i(long n, GEN Q, GEN P)
8713 {
8714   GEN V, v = qfrep0(Q, utoi(n), 1);
8715   long i, l = lg(v);
8716   V = cgetg(l+1, t_VEC);
8717   if (!P || equali1(P))
8718   {
8719     gel(V,1) = gen_1;
8720     for (i = 2; i <= l; i++) gel(V,i) = utoi(v[i-1] << 1);
8721   }
8722   else
8723   {
8724     gel(V,1) = gcopy(P);
8725     for (i = 2; i <= l; i++) gel(V,i) = gmulgs(P, v[i-1] << 1);
8726   }
8727   return V;
8728 }
8729 
8730 /* v a t_VECSMALL of variable numbers, lg(r) >= lg(v), r is a vector of
8731  * scalars [not involving any variable in v] */
8732 static GEN
gsubstvec_i(GEN e,GEN v,GEN r)8733 gsubstvec_i(GEN e, GEN v, GEN r)
8734 {
8735   long i, l = lg(v);
8736   for(i = 1; i < l; i++) e = gsubst(e, v[i], gel(r,i));
8737   return e;
8738 }
8739 static GEN
c_QF_i(long n,GEN Q,GEN P)8740 c_QF_i(long n, GEN Q, GEN P)
8741 {
8742   pari_sp av = avma;
8743   GEN V, v, va;
8744   long i, l;
8745   if (!P || typ(P) != t_POL) return gerepileupto(av, c_QFsimple_i(n, Q, P));
8746   v = gel(minim(Q, utoi(2*n), NULL), 3);
8747   va = variables_vecsmall(P);
8748   V = zerovec(n + 1); l = lg(v);
8749   for (i = 1; i < l; i++)
8750   {
8751     pari_sp av = avma;
8752     GEN X = gel(v,i);
8753     long c = (itos(qfeval(Q, X)) >> 1) + 1;
8754     gel(V, c) = gerepileupto(av, gadd(gel(V, c), gsubstvec_i(P, va, X)));
8755   }
8756   return gmul2n(V, 1);
8757 }
8758 
8759 GEN
mffromqf(GEN Q,GEN P)8760 mffromqf(GEN Q, GEN P)
8761 {
8762   pari_sp av = avma;
8763   GEN G, Qi, F, D, N, mf, v, gk, chi;
8764   long m, d, space;
8765   if (typ(Q) != t_MAT) pari_err_TYPE("mffromqf", Q);
8766   if (!RgM_is_ZM(Q) || !qfiseven(Q))
8767     pari_err_TYPE("mffromqf [not integral or even]", Q);
8768   m = lg(Q)-1;
8769   Qi = ZM_inv(Q, &N);
8770   if (!qfiseven(Qi)) N = shifti(N, 1);
8771   d = 0;
8772   if (!P || gequal1(P)) P = NULL;
8773   else
8774   {
8775     P = simplify_shallow(P);
8776     if (typ(P) == t_POL)
8777     {
8778       d = polishomogeneous(P);
8779       if (d < 0) pari_err_TYPE("mffromqf [not homogeneous t_POL]", P);
8780       if (!RgX_isspherical(Qi, P))
8781         pari_err_TYPE("mffromqf [not a spherical t_POL]", P);
8782     }
8783   }
8784   gk = sstoQ(m + 2*d, 2);
8785   D = ZM_det(Q);
8786   if (!odd(m)) { if ((m & 3) == 2) D = negi(D); } else D = shifti(D, 1);
8787   space = d > 0 ? mf_CUSP : mf_FULL;
8788   G = znstar0(N,1);
8789   chi = mkvec2(G, znchar_quad(G,D));
8790   mf = mfinit(mkvec3(N, gk, chi), space);
8791   if (odd(d))
8792   {
8793     F = mftrivial();
8794     v = zerocol(MF_get_dim(mf));
8795   }
8796   else
8797   {
8798     F = c_QF_i(mfsturm(mf), Q, P);
8799     v = mftobasis_i(mf, F);
8800     F = mflinear(mf, v);
8801   }
8802   return gerepilecopy(av, mkvec3(mf, F, v));
8803 }
8804 
8805 /***********************************************************************/
8806 /*                          Eisenstein Series                          */
8807 /***********************************************************************/
8808 /* \sigma_{k-1}(\chi,n) */
8809 static GEN
sigchi(long k,GEN CHI,long n)8810 sigchi(long k, GEN CHI, long n)
8811 {
8812   pari_sp av = avma;
8813   GEN S = gen_1, D = mydivisorsu(u_ppo(n,mfcharmodulus(CHI)));
8814   long i, l = lg(D), ord = mfcharorder(CHI), vt = varn(mfcharpol(CHI));
8815   for (i = 2; i < l; i++) /* skip D[1] = 1 */
8816   {
8817     long d = D[i], a = mfcharevalord(CHI, d, ord);
8818     S = gadd(S, Qab_Czeta(a, ord, powuu(d, k-1), vt));
8819   }
8820   return gerepileupto(av,S);
8821 }
8822 
8823 /* write n = n0*n1*n2, (n0,N1*N2) = 1, n1 | N1^oo, n2 | N2^oo;
8824  * return NULL if (n,N1,N2) > 1, else return factoru(n0) */
8825 static GEN
sigchi2_dec(long n,long N1,long N2,long * pn1,long * pn2)8826 sigchi2_dec(long n, long N1, long N2, long *pn1, long *pn2)
8827 {
8828   GEN P0, E0, P, E, fa = myfactoru(n);
8829   long i, j, l;
8830   *pn1 = 1;
8831   *pn2 = 1;
8832   if (N1 == 1 && N2 == 1) return fa;
8833   P = gel(fa,1); l = lg(P);
8834   E = gel(fa,2);
8835   P0 = cgetg(l, t_VECSMALL);
8836   E0 = cgetg(l, t_VECSMALL);
8837   for (i = j = 1; i < l; i++)
8838   {
8839     long p = P[i], e = E[i];
8840     if (N1 % p == 0)
8841     {
8842       if (N2 % p == 0) return NULL;
8843       *pn1 *= upowuu(p,e);
8844     }
8845     else if (N2 % p == 0)
8846       *pn2 *= upowuu(p,e);
8847     else { P0[j] = p; E0[j] = e; j++; }
8848   }
8849   setlg(P0, j);
8850   setlg(E0, j); return mkvec2(P0,E0);
8851 }
8852 
8853 /* sigma_{k-1}(\chi_1,\chi_2,n), ord multiple of lcm(ord(CHI1),ord(CHI2)) */
8854 static GEN
sigchi2(long k,GEN CHI1,GEN CHI2,long n,long ord)8855 sigchi2(long k, GEN CHI1, GEN CHI2, long n, long ord)
8856 {
8857   pari_sp av = avma;
8858   GEN S, D;
8859   long i, l, n1, n2, vt, N1 = mfcharmodulus(CHI1), N2 = mfcharmodulus(CHI2);
8860   D = sigchi2_dec(n, N1, N2, &n1, &n2); if (!D) return gc_const(av, gen_0);
8861   D = divisorsu_fact(D); l = lg(D);
8862   vt = varn(mfcharpol(CHI1));
8863   for (i = 1, S = gen_0; i < l; i++)
8864   { /* S += d^(k-1)*chi1(d)*chi2(n/d) */
8865     long a, d = n2*D[i], nd = n1*D[l-i]; /* (d,N1)=1; (n/d,N2) = 1 */
8866     a = mfcharevalord(CHI1, d, ord) + mfcharevalord(CHI2, nd, ord);
8867     if (a >= ord) a -= ord;
8868     S = gadd(S, Qab_Czeta(a, ord, powuu(d, k-1), vt));
8869   }
8870   return gerepileupto(av, S);
8871 }
8872 
8873 /**************************************************************************/
8874 /**           Dirichlet characters with precomputed values               **/
8875 /**************************************************************************/
8876 /* CHI mfchar */
8877 static GEN
mfcharcxinit(GEN CHI,long prec)8878 mfcharcxinit(GEN CHI, long prec)
8879 {
8880   GEN G = gel(CHI,1), chi = gel(CHI,2), z, V;
8881   GEN v = ncharvecexpo(G, znconrey_normalized(G,chi));
8882   long n, l = lg(v), o = mfcharorder(CHI);
8883   V = cgetg(l, t_VEC);
8884   z = grootsof1(o, prec); /* Mod(t, Phi_o(t)) -> e(1/o) */
8885   for (n = 1; n < l; n++) gel(V,n) = v[n] < 0? gen_0: gel(z, v[n]+1);
8886   return mkvecn(6, G, chi, gmfcharorder(CHI), v, V, mfcharpol(CHI));
8887 }
8888 /* v a "CHIvec" */
8889 static long
CHIvec_N(GEN v)8890 CHIvec_N(GEN v) { return itou(znstar_get_N(gel(v,1))); }
8891 static GEN
CHIvec_CHI(GEN v)8892 CHIvec_CHI(GEN v)
8893 { return mkvec4(gel(v,1), gel(v,2), gel(v,3), gel(v,6)); }
8894 /* character order */
8895 static long
CHIvec_ord(GEN v)8896 CHIvec_ord(GEN v) { return itou(gel(v,3)); }
8897 /* character exponents, i.e. t such that chi(n) = e(t) */
8898 static GEN
CHIvec_expo(GEN v)8899 CHIvec_expo(GEN v) { return gel(v,4); }
8900 /* character values chi(n) */
8901 static GEN
CHIvec_val(GEN v)8902 CHIvec_val(GEN v) { return gel(v,5); }
8903 /* CHI(n) */
8904 static GEN
mychareval(GEN v,long n)8905 mychareval(GEN v, long n)
8906 {
8907   long N = CHIvec_N(v), ind = n%N;
8908   if (ind <= 0) ind += N;
8909   return gel(CHIvec_val(v), ind);
8910 }
8911 /* return c such that CHI(n) = e(c / ordz) or -1 if (n,N) > 1 */
8912 static long
mycharexpo(GEN v,long n)8913 mycharexpo(GEN v, long n)
8914 {
8915   long N = CHIvec_N(v), ind = n%N;
8916   if (ind <= 0) ind += N;
8917   return CHIvec_expo(v)[ind];
8918 }
8919 /* faster than mfcharparity */
8920 static long
CHIvec_parity(GEN v)8921 CHIvec_parity(GEN v) { return mycharexpo(v,-1) ? -1: 1; }
8922 /**************************************************************************/
8923 
8924 static ulong
sigchi2_Fl(long k,GEN CHI1vec,GEN CHI2vec,long n,GEN vz,ulong p)8925 sigchi2_Fl(long k, GEN CHI1vec, GEN CHI2vec, long n, GEN vz, ulong p)
8926 {
8927   pari_sp av = avma;
8928   long ordz = lg(vz)-2, i, l, n1, n2;
8929   ulong S = 0;
8930   GEN D = sigchi2_dec(n, CHIvec_N(CHI1vec), CHIvec_N(CHI2vec), &n1, &n2);
8931   if (!D) return gc_ulong(av,S);
8932   D = divisorsu_fact(D);
8933   l = lg(D);
8934   for (i = 1; i < l; i++)
8935   { /* S += d^(k-1)*chi1(d)*chi2(n/d) */
8936     long a, d = n2*D[i], nd = n1*D[l-i]; /* (d,N1)=1, (n/d,N2)=1 */
8937     a = mycharexpo(CHI2vec, nd) + mycharexpo(CHI1vec, d);
8938     if (a >= ordz) a -= ordz;
8939     S = Fl_add(S, Qab_Czeta_Fl(a, vz, Fl_powu(d,k-1,p), p), p);
8940   }
8941   return gc_ulong(av,S);
8942 }
8943 
8944 /**********************************************************************/
8945 /* Fourier expansions of Eisenstein series                            */
8946 /**********************************************************************/
8947 /* L(CHI_t,0) / 2, CHI_t(n) = CHI(n)(t/n) as a character modulo N*t,
8948  * order(CHI) | ord != 0 */
8949 static GEN
charLFwt1(long N,GEN CHI,long ord,long t)8950 charLFwt1(long N, GEN CHI, long ord, long t)
8951 {
8952   GEN S;
8953   long r, vt;
8954 
8955   if (N == 1 && t == 1) return mkfrac(gen_m1,stoi(4));
8956   S = gen_0; vt = varn(mfcharpol(CHI));
8957   for (r = 1; r < N; r++)
8958   { /* S += r*chi(r) */
8959     long a, c;
8960     if (ugcd(N,r) != 1) continue;
8961     a = mfcharevalord(CHI,r,ord);
8962     c = (t != 1 && kross(t, r) < 0)? -r: r;
8963     S = gadd(S, Qab_Czeta(a, ord, stoi(c), vt));
8964   }
8965   return gdivgs(S, -2*N);
8966 }
8967 /* L(CHI,0) / 2, mod p */
8968 static ulong
charLFwt1_Fl(GEN CHIvec,GEN vz,ulong p)8969 charLFwt1_Fl(GEN CHIvec, GEN vz, ulong p)
8970 {
8971   long r, m = CHIvec_N(CHIvec);
8972   ulong S;
8973   if (m == 1) return Rg_to_Fl(mkfrac(gen_m1,stoi(4)), p);
8974   S = 0;
8975   for (r = 1; r < m; r++)
8976   { /* S += r*chi(r) */
8977     long a = mycharexpo(CHIvec,r);
8978     if (a < 0) continue;
8979     S = Fl_add(S, Qab_Czeta_Fl(a, vz, r, p), p);
8980   }
8981   return Fl_div(Fl_neg(S,p), 2*m, p);
8982 }
8983 /* L(CHI_t,1-k) / 2, CHI_t(n) = CHI(n) * (t/n), order(CHI) | ord != 0;
8984  * assume conductor of CHI_t divides N */
8985 static GEN
charLFwtk(long N,long k,GEN CHI,long ord,long t)8986 charLFwtk(long N, long k, GEN CHI, long ord, long t)
8987 {
8988   GEN S, P, dS;
8989   long r, vt;
8990 
8991   if (k == 1) return charLFwt1(N, CHI, ord, t);
8992   if (N == 1 && t == 1) return gdivgs(bernfrac(k),-2*k);
8993   S = gen_0; vt = varn(mfcharpol(CHI));
8994   P = ZX_rescale(Q_remove_denom(bernpol(k,0), &dS), utoi(N));
8995   dS = mul_denom(dS, stoi(-2*N*k));
8996   for (r = 1; r < N; r++)
8997   { /* S += P(r)*chi(r) */
8998     long a;
8999     GEN C;
9000     if (ugcd(r,N) != 1) continue;
9001     a = mfcharevalord(CHI,r,ord);
9002     C = poleval(P, utoi(r));
9003     if (t != 1 && kross(t, r) < 0) C = gneg(C);
9004     S = gadd(S, Qab_Czeta(a, ord, C, vt));
9005   }
9006   return gdiv(S, dS);
9007 }
9008 /* L(CHI,1-k) / 2, mod p */
9009 static ulong
charLFwtk_Fl(long k,GEN CHIvec,GEN vz,ulong p)9010 charLFwtk_Fl(long k, GEN CHIvec, GEN vz, ulong p)
9011 {
9012   GEN P;
9013   long r, m;
9014   ulong S;
9015   if (k == 1) return charLFwt1_Fl(CHIvec, vz, p);
9016   m = CHIvec_N(CHIvec);
9017   if (m == 1) return Rg_to_Fl(gdivgs(bernfrac(k),-2*k), p);
9018   S = 0;
9019   P = RgX_to_Flx(RgX_rescale(bernpol(k,0), utoi(m)), p);
9020   for (r = 1; r < m; r++)
9021   { /* S += P(r)*chi(r) */
9022     long a = mycharexpo(CHIvec,r);
9023     if (a < 0) continue;
9024     S = Fl_add(S, Qab_Czeta_Fl(a, vz, Flx_eval(P,r,p), p), p);
9025   }
9026   return Fl_div(Fl_neg(S,p), 2*k*m, p);
9027 }
9028 
9029 static GEN
mfeisenstein2_0(long k,GEN CHI1,GEN CHI2,long ord)9030 mfeisenstein2_0(long k, GEN CHI1, GEN CHI2, long ord)
9031 {
9032   long N1 = mfcharmodulus(CHI1), N2 = mfcharmodulus(CHI2);
9033   if (k == 1 && N1 == 1) return charLFwtk(N2, 1, CHI2, ord, 1);
9034   if (N2 == 1) return charLFwtk(N1, k, CHI1, ord, 1);
9035   return gen_0;
9036 }
9037 static ulong
mfeisenstein2_0_Fl(long k,GEN CHI1vec,GEN CHI2vec,GEN vz,ulong p)9038 mfeisenstein2_0_Fl(long k, GEN CHI1vec, GEN CHI2vec, GEN vz, ulong p)
9039 {
9040   if (k == 1 && CHIvec_N(CHI1vec) == 1)
9041     return charLFwtk_Fl(k, CHI2vec, vz, p);
9042   else if (CHIvec_N(CHI2vec) == 1)
9043     return charLFwtk_Fl(k, CHI1vec, vz, p);
9044   else return 0;
9045 }
9046 static GEN
NK_eisen2(long k,GEN CHI1,GEN CHI2,long ord)9047 NK_eisen2(long k, GEN CHI1, GEN CHI2, long ord)
9048 {
9049   long o, N = mfcharmodulus(CHI1)*mfcharmodulus(CHI2);
9050   GEN CHI = mfcharmul(CHI1, CHI2);
9051   o = mfcharorder(CHI);
9052   if ((ord & 3) == 2) ord >>= 1;
9053   if ((o & 3) == 2) o >>= 1;
9054   if (ord != o) pari_err_IMPL("mfeisenstein for these characters");
9055   return mkNK(N, k, CHI);
9056 }
9057 static GEN
mfeisenstein_i(long k,GEN CHI1,GEN CHI2)9058 mfeisenstein_i(long k, GEN CHI1, GEN CHI2)
9059 {
9060   long s = 1, ord, vt;
9061   GEN E0, NK, vchi, T;
9062   if (CHI2) { CHI2 = get_mfchar(CHI2); if (mfcharparity(CHI2) < 0) s = -s; }
9063   if (CHI1) { CHI1 = get_mfchar(CHI1); if (mfcharparity(CHI1) < 0) s = -s; }
9064   if (s != m1pk(k)) return mftrivial();
9065   if (!CHI1) CHI1 = mfchartrivial();
9066   if (!CHI2)
9067   { /* E_k(chi1) */
9068     vt = varn(mfcharpol(CHI1));
9069     ord = mfcharorder(CHI1);
9070     NK = mkNK(mfcharmodulus(CHI1), k, CHI1);
9071     E0 = charLFwtk(mfcharmodulus(CHI1), k, CHI1, ord, 1);
9072     vchi = mkvec3(E0, mkvec(mfcharpol(CHI1)), CHI1);
9073     return tag(t_MF_EISEN, NK, vchi);
9074   }
9075   /* E_k(chi1,chi2) */
9076   vt = varn(mfcharpol(CHI1));
9077   ord = ulcm(mfcharorder(CHI1), mfcharorder(CHI2));
9078   NK = NK_eisen2(k, CHI1, CHI2, ord);
9079   E0 = mfeisenstein2_0(k, CHI1, CHI2, ord);
9080   T = mkvec(polcyclo(ord, vt));
9081   vchi = mkvec4(E0, T, CHI1, CHI2);
9082   return tag2(t_MF_EISEN, NK, vchi, mkvecsmall2(ord,0));
9083 }
9084 GEN
mfeisenstein(long k,GEN CHI1,GEN CHI2)9085 mfeisenstein(long k, GEN CHI1, GEN CHI2)
9086 {
9087   pari_sp av = avma;
9088   if (k < 1) pari_err_DOMAIN("mfeisenstein", "k", "<", gen_1, stoi(k));
9089   return gerepilecopy(av, mfeisenstein_i(k, CHI1, CHI2));
9090 }
9091 
9092 static GEN
mfeisenstein2all(long N0,GEN NK,long k,GEN CHI1,GEN CHI2,GEN T,long o)9093 mfeisenstein2all(long N0, GEN NK, long k, GEN CHI1, GEN CHI2, GEN T, long o)
9094 {
9095   GEN E, E0 = mfeisenstein2_0(k, CHI1,CHI2, o), vchi = mkvec4(E0, T, CHI1,CHI2);
9096   long j, d = (lg(T)==4)? itou(gmael(T,3,1)): 1;
9097   E = cgetg(d+1, t_VEC);
9098   for (j=1; j<=d; j++) gel(E,j) = tag2(t_MF_EISEN, NK,vchi,mkvecsmall2(o,j-1));
9099   return mfbdall(E, N0 / mf_get_N(gel(E,1)));
9100 }
9101 
9102 /* list of characters on G = (Z/NZ)^*, v[i] = NULL if (i,N) > 1, else
9103  * the conductor of Conrey label i, [conductor, primitive char].
9104  * Trivial chi (label 1) comes first */
9105 static GEN
zncharsG(GEN G)9106 zncharsG(GEN G)
9107 {
9108   long i, l, N = itou(znstar_get_N(G));
9109   GEN vCHI, V;
9110   if (N == 1) return mkvec2(gen_1,cgetg(1,t_COL));
9111   vCHI = const_vec(N,NULL);
9112   V = cyc2elts(znstar_get_conreycyc(G));
9113   l = lg(V);
9114   for (i = 1; i < l; i++)
9115   {
9116     GEN chi0, chi = zc_to_ZC(gel(V,i)), n, F;
9117     F = znconreyconductor(G, chi, &chi0);
9118     if (typ(F) != t_INT) F = gel(F,1);
9119     n = znconreyexp(G, chi);
9120     gel(vCHI, itos(n)) = mkvec2(chi0, F);
9121   }
9122   return vCHI;
9123 }
9124 
9125 /* CHI primitive, f(CHI) | N. Return pairs (CHI1,CHI2) both primitive
9126  * such that f(CHI1)*f(CHI2) | N and CHI1 * CHI2 = CHI;
9127  * if k = 1, CHI1 is even; if k = 2, omit (1,1) if CHI = 1 */
9128 static GEN
mfeisensteinbasis_i(long N0,long k,GEN CHI)9129 mfeisensteinbasis_i(long N0, long k, GEN CHI)
9130 {
9131   GEN G = gel(CHI,1), chi = gel(CHI,2), vT = const_vec(myeulerphiu(N0), NULL);
9132   GEN CHI0, GN, chiN, Lchi, LG, V, RES, NK, T, C = mfcharpol(CHI);
9133   long i, j, l, n, n1, N, ord = mfcharorder(CHI);
9134   long F = mfcharmodulus(CHI), vt = varn(mfcharpol(CHI));
9135 
9136   CHI0 = (F == 1)? CHI: mfchartrivial();
9137   j = 1; RES = cgetg(N0+1, t_VEC);
9138   T = gel(vT,ord) = Qab_trace_init(ord, ord, C, C);
9139   if (F != 1 || k != 2)
9140   { /* N1 = 1 */
9141     NK = mkNK(F, k, CHI);
9142     gel(RES, j++) = mfeisenstein2all(N0, NK, k, CHI0, CHI, T, ord);
9143     if (F != 1 && k != 1)
9144       gel(RES, j++) = mfeisenstein2all(N0, NK, k, CHI, CHI0, T, ord);
9145   }
9146   if (N0 == 1) { setlg(RES,j); return RES; }
9147   GN = G; chiN = chi;
9148   if (F == N0) N = N0;
9149   else
9150   {
9151     GEN faN = myfactoru(N0), P = gel(faN,1), E = gel(faN,2);
9152     long lP = lg(P);
9153     for (i = N = 1; i < lP; i++)
9154     {
9155       long p = P[i];
9156       N *= upowuu(p, maxuu(E[i]/2, z_lval(F,p)));
9157     }
9158     if ((N & 3) == 2) N >>= 1;
9159     if (N == 1) { setlg(RES,j); return RES; }
9160     if (F != N)
9161     {
9162       GN = znstar0(utoipos(N),1);
9163       chiN = zncharinduce(G, chi, GN);
9164     }
9165   }
9166   LG = const_vec(N, NULL); /* LG[d] = znstar(d,1) or NULL */
9167   gel(LG,1) = gel(CHI0,1);
9168   gel(LG,F) = G;
9169   gel(LG,N) = GN;
9170   Lchi = coprimes_zv(N);
9171   n = itou(znconreyexp(GN,chiN));
9172   V = zncharsG(GN); l = lg(V);
9173   for (n1 = 2; n1 < l; n1++) /* skip 1 (trivial char) */
9174   {
9175     GEN v = gel(V,n1), w, chi1, chi2, G1, G2, CHI1, CHI2;
9176     long N12, N1, N2, no, o12, t, m;
9177     if (!Lchi[n1] || n1 == n) continue; /* skip trivial chi2 */
9178     chi1 = gel(v,1); N1 = itou(gel(v,2)); /* conductor of chi1 */
9179     w = gel(V, Fl_div(n,n1,N));
9180     chi2 = gel(w,1); N2 = itou(gel(w,2)); /* conductor of chi2 */
9181     N12 = N1 * N2;
9182     if (N0 % N12) continue;
9183 
9184     G1 = gel(LG,N1); if (!G1) gel(LG,N1) = G1 = znstar0(utoipos(N1), 1);
9185     if (k == 1 && zncharisodd(G1,chi1)) continue;
9186     G2 = gel(LG,N2); if (!G2) gel(LG,N2) = G2 = znstar0(utoipos(N2), 1);
9187     CHI1 = mfcharGL(G1, chi1);
9188     CHI2 = mfcharGL(G2, chi2);
9189     o12 = ulcm(mfcharorder(CHI1), mfcharorder(CHI2));
9190     /* remove Galois orbit: same trace */
9191     no = Fl_powu(n1, ord, N);
9192     for (t = 1+ord, m = n1; t <= o12; t += ord)
9193     { /* m <-> CHI1^t, if t in Gal(Q(chi1,chi2)/Q), omit (CHI1^t,CHI2^t) */
9194       m = Fl_mul(m, no, N); if (!m) break;
9195       if (ugcd(t, o12) == 1) Lchi[m] = 0;
9196     }
9197     T = gel(vT,o12);
9198     if (!T) T = gel(vT,o12) = Qab_trace_init(o12, ord, polcyclo(o12,vt), C);
9199     NK = mkNK(N12, k, CHI);
9200     gel(RES, j++) = mfeisenstein2all(N0, NK, k, CHI1, CHI2, T, o12);
9201   }
9202   setlg(RES,j); return RES;
9203 }
9204 
9205 static GEN
mfbd_E2(GEN E2,long d,GEN CHI)9206 mfbd_E2(GEN E2, long d, GEN CHI)
9207 {
9208   GEN E2d = mfbd_i(E2, d);
9209   GEN F = mkvec2(E2, E2d), L = mkvec2(gen_1, utoineg(d));
9210   /* cannot use mflinear_i: E2 and E2d do not have the same level */
9211   return tag3(t_MF_LINEAR, mkNK(d,2,CHI), F, L, gen_1);
9212 }
9213 /* C-basis of E_k(Gamma_0(N),chi). If k = 1, the first basis element must not
9214  * vanish at oo [used in mfwt1basis]. Here E_1(CHI), whose q^0 coefficient
9215  * does not vanish (since L(CHI,0) does not) *if* CHI is not trivial; which
9216  * must be the case in weight 1.
9217  *
9218  * (k>=3): In weight k >= 3, basis is B(d) E(CHI1,(CHI/CHI1)_prim), where
9219  * CHI1 is primitive modulo N1, and if N2 is the conductor of CHI/CHI1
9220  * then d*N1*N2 | N.
9221  * (k=2): In weight k=2, same if CHI is nontrivial. If CHI is trivial, must
9222  * not take CHI1 trivial, and must add E_2(tau)-dE_2(d tau)), where
9223  * d|N, d > 1.
9224  * (k=1): In weight k=1, same as k >= 3 except that we restrict to CHI1 even */
9225 static GEN
mfeisensteinbasis(long N,long k,GEN CHI)9226 mfeisensteinbasis(long N, long k, GEN CHI)
9227 {
9228   long i, F;
9229   GEN L;
9230   if (badchar(N, k, CHI)) return cgetg(1, t_VEC);
9231   if (k == 0) return mfcharistrivial(CHI)? mkvec(mf1()): cgetg(1, t_VEC);
9232   CHI = mfchartoprimitive(CHI, &F);
9233   L = mfeisensteinbasis_i(N, k, CHI);
9234   if (F == 1 && k == 2)
9235   {
9236     GEN v, E2 = mfeisenstein(2, NULL, NULL), D = mydivisorsu(N);
9237     long nD = lg(D)-1;
9238     v = cgetg(nD, t_VEC); L = vec_append(L,v);
9239     for (i = 1; i < nD; i++) gel(v,i) = mfbd_E2(E2, D[i+1], CHI);
9240   }
9241   return lg(L) == 1? L: shallowconcat1(L);
9242 }
9243 
9244 static GEN
not_in_space(GEN F,long flag)9245 not_in_space(GEN F, long flag)
9246 {
9247   if (!flag) err_space(F);
9248   return cgetg(1, t_COL);
9249 }
9250 /* when flag set, no error */
9251 GEN
mftobasis(GEN mf,GEN F,long flag)9252 mftobasis(GEN mf, GEN F, long flag)
9253 {
9254   pari_sp av2, av = avma;
9255   GEN G, v, y, gk;
9256   long N, B, ismf = checkmf_i(F);
9257 
9258   mf = checkMF(mf);
9259   if (ismf)
9260   {
9261     if (mfistrivial(F)) return zerocol(MF_get_dim(mf));
9262     if (!mf_same_k(mf, F) || !mf_same_CHI(mf, F)) return not_in_space(F, flag);
9263   }
9264   N = MF_get_N(mf);
9265   gk = MF_get_gk(mf);
9266   if (ismf)
9267   {
9268     long NF = mf_get_N(F);
9269     B = maxuu(mfsturmNgk(NF,gk), mfsturmNgk(N,gk)) + 1;
9270     v = mfcoefs_i(F,B,1);
9271   }
9272   else
9273   {
9274     B = mfsturmNgk(N, gk) + 1;
9275     switch(typ(F))
9276     { /* F(0),...,F(lg(v)-2) */
9277       case t_SER: v = sertocol(F); settyp(v,t_VEC); break;
9278       case t_VEC: v = F; break;
9279       case t_COL: v = shallowtrans(F); break;
9280       default: pari_err_TYPE("mftobasis",F);
9281                v = NULL;/*LCOV_EXCL_LINE*/
9282     }
9283     if (flag) B = minss(B, lg(v)-2);
9284   }
9285   y = mftobasis_i(mf, v);
9286   if (typ(y) == t_VEC)
9287   {
9288     if (flag) return gerepilecopy(av, y);
9289     pari_err(e_MISC, "not enough coefficients in mftobasis");
9290   }
9291   av2 = avma;
9292   if (MF_get_space(mf) == mf_FULL || mfsturm(mf)+1 == B) return y;
9293   G = mflinear(mf, y);
9294   if (!gequal(v, mfcoefs_i(G, lg(v)-2,1))) y = NULL;
9295   if (!y) { set_avma(av); return not_in_space(F, flag); }
9296   set_avma(av2); return gerepileupto(av, y);
9297 }
9298 
9299 /* assume N > 0; first cusp is always 0 */
9300 static GEN
mfcusps_i(long N)9301 mfcusps_i(long N)
9302 {
9303   long i, c, l;
9304   GEN D, v;
9305 
9306   if (N == 1) return mkvec(gen_0);
9307   D = mydivisorsu(N); l = lg(D); /* left on stack */
9308   c = mfnumcuspsu_fact(myfactoru(N));
9309   v = cgetg(c + 1, t_VEC);
9310   for (i = c = 1; i < l; i++)
9311   {
9312     long C = D[i], NC = D[l-i], lima = ugcd(C, NC), A0, A;
9313     for (A0 = 0; A0 < lima; A0++)
9314       if (ugcd(A0, lima) == 1)
9315       {
9316         A = A0; while (ugcd(A,C) > 1) A += lima;
9317         gel(v, c++) = sstoQ(A, C);
9318       }
9319   }
9320   return v;
9321 }
9322 /* List of cusps of Gamma_0(N) */
9323 GEN
mfcusps(GEN gN)9324 mfcusps(GEN gN)
9325 {
9326   long N;
9327   GEN mf;
9328   if (typ(gN) == t_INT) N = itos(gN);
9329   else if ((mf = checkMF_i(gN))) N = MF_get_N(mf);
9330   else { pari_err_TYPE("mfcusps", gN); N = 0; }
9331   if (N <= 0) pari_err_DOMAIN("mfcusps", "N", "<=", gen_0, stoi(N));
9332   return mfcusps_i(N);
9333 }
9334 
9335 long
mfcuspisregular(GEN NK,GEN cusp)9336 mfcuspisregular(GEN NK, GEN cusp)
9337 {
9338   long v, N, dk, nk, t, o;
9339   GEN mf, CHI, go, A, C, g, c, d;
9340   if ((mf = checkMF_i(NK)))
9341   {
9342     GEN gk = MF_get_gk(mf);
9343     N = MF_get_N(mf);
9344     CHI = MF_get_CHI(mf);
9345     Qtoss(gk, &nk, &dk);
9346   }
9347   else
9348     checkNK2(NK, &N, &nk, &dk, &CHI, 0);
9349   if (typ(cusp) == t_INFINITY) return 1;
9350   if (typ(cusp) == t_FRAC) { A = gel(cusp,1); C = gel(cusp,2); }
9351   else { A = cusp; C = gen_1; }
9352   g = diviuexact(mului(N,C), ugcd(N, Fl_sqr(umodiu(C,N), N)));
9353   c = mulii(negi(C),g);
9354   d = addiu(mulii(A,g), 1);
9355   if (!CHI) return 1;
9356   go = gmfcharorder(CHI);
9357   v = vali(go); if (v < 2) go = shifti(go, 2-v);
9358   t = itou( znchareval(gel(CHI,1), gel(CHI,2), d, go) );
9359   if (dk == 1) return t == 0;
9360   o = itou(go);
9361   if (kronecker(c,d) < 0) t = Fl_add(t, o/2, o);
9362   if (Mod4(d) == 1) return t == 0;
9363   t = Fl_sub(t, Fl_mul(o/4, nk, o), o);
9364   return t == 0;
9365 }
9366 
9367 /* Some useful closures */
9368 
9369 /* sum_{d|n} d^k */
9370 static GEN
mysumdivku(ulong n,ulong k)9371 mysumdivku(ulong n, ulong k)
9372 {
9373   GEN fa = myfactoru(n);
9374   return k == 1? usumdiv_fact(fa): usumdivk_fact(fa,k);
9375 }
9376 static GEN
c_Ek(long n,long d,GEN F)9377 c_Ek(long n, long d, GEN F)
9378 {
9379   GEN E = cgetg(n + 2, t_VEC), C = gel(F,2);
9380   long i, k = mf_get_k(F);
9381   gel (E, 1) = gen_1;
9382   for (i = 1; i <= n; i++)
9383   {
9384     pari_sp av = avma;
9385     gel(E, i+1) = gerepileupto(av, gmul(C, mysumdivku(i*d, k-1)));
9386   }
9387   return E;
9388 }
9389 
9390 GEN
mfEk(long k)9391 mfEk(long k)
9392 {
9393   pari_sp av = avma;
9394   GEN E0, NK;
9395   if (k < 0 || odd(k)) pari_err_TYPE("mfEk [incorrect k]", stoi(k));
9396   if (!k) return mf1();
9397   E0 = gdivsg(-2*k, bernfrac(k));
9398   NK = mkNK(1,k,mfchartrivial());
9399   return gerepilecopy(av, tag(t_MF_Ek, NK, E0));
9400 }
9401 
9402 GEN
mfDelta(void)9403 mfDelta(void)
9404 {
9405   pari_sp av = avma;
9406   return gerepilecopy(av, tag0(t_MF_DELTA, mkNK(1,12,mfchartrivial())));
9407 }
9408 
9409 GEN
mfTheta(GEN psi)9410 mfTheta(GEN psi)
9411 {
9412   pari_sp av = avma;
9413   GEN N, gk, psi2;
9414   long par;
9415   if (!psi) { psi = mfchartrivial(); N = utoipos(4); par = 1; }
9416   else
9417   {
9418     long FC;
9419     psi = get_mfchar(psi);
9420     FC = mfcharconductor(psi);
9421     if (mfcharmodulus(psi) != FC)
9422       pari_err_TYPE("mfTheta [nonprimitive character]", psi);
9423     par = mfcharparity(psi);
9424     N = shifti(sqru(FC),2);
9425   }
9426   if (par > 0) { gk = ghalf; psi2 = psi; }
9427   else { gk = gsubsg(2, ghalf); psi2 = mfcharmul(psi, get_mfchar(stoi(-4))); }
9428   return gerepilecopy(av, tag(t_MF_THETA, mkgNK(N, gk, psi2, pol_x(1)), psi));
9429 }
9430 
9431 /* Output 0 if not desired eta product: if flag=0 (default) require
9432  * holomorphic at cusps. If flag set, accept meromorphic, but sill in some
9433  * modular function space */
9434 GEN
mffrometaquo(GEN eta,long flag)9435 mffrometaquo(GEN eta, long flag)
9436 {
9437   pari_sp av = avma;
9438   GEN NK, N, k, BR, P;
9439   long v, cusp = 0;
9440   if (!etaquotype(&eta, &N,&k,&P, &v, NULL, flag? NULL: &cusp) || cusp < 0)
9441     return gc_const(av, gen_0);
9442   if (lg(gel(eta,1)) == 1) { set_avma(av); return mf1(); }
9443   BR = mkvec2(ZV_to_zv(gel(eta,1)), ZV_to_zv(gel(eta,2)));
9444   if (v < 0) v = 0;
9445   NK = mkgNK(N, k, get_mfchar(P), pol_x(1));
9446   return gerepilecopy(av, tag2(t_MF_ETAQUO, NK, BR, utoi(v)));
9447 }
9448 
9449 /* Q^(-r) */
9450 static GEN
RgXn_negpow(GEN Q,long r,long L)9451 RgXn_negpow(GEN Q, long r, long L)
9452 {
9453   if (r < 0) r = -r; else Q = RgXn_inv_i(Q, L);
9454   if (r != 1) Q = RgXn_powu_i(Q, r, L);
9455   return Q;
9456 }
9457 /* flag same as in mffrometaquo: if set, accept meromorphic. */
9458 static GEN
mfisetaquo_i(GEN F,long flag)9459 mfisetaquo_i(GEN F, long flag)
9460 {
9461   GEN gk, P, E, M, S, G, CHI, v, w;
9462   long b, l, L, N, vS, m, j;
9463   const long bextra = 10;
9464 
9465   if (!checkmf_i(F)) pari_err_TYPE("mfisetaquo",F);
9466   CHI = mf_get_CHI(F); if (mfcharorder(CHI) > 2) return NULL;
9467   N = mf_get_N(F);
9468   gk = mf_get_gk(F);
9469   b = mfsturmNgk(N, gk);
9470   L = maxss(N, b) + bextra;
9471   S = mfcoefs_i(F, L, 1);
9472   if (!RgV_is_ZV(S)) return NULL;
9473   for (vS = 1; vS <= L+1; vS++)
9474     if (signe(gel(S,vS))) break;
9475   vS--;
9476   if (vS >= bextra - 1) { L += vS; S = mfcoefs_i(F, L, 1); }
9477   if (vS) { S = vecslice(S, vS+1, L+1); L -= vS; }
9478   S = RgV_to_RgX(S, 0); l = lg(S)-2;
9479   P = cgetg(l, t_COL);
9480   E = cgetg(l, t_COL); w = v = gen_0; /* w = weight, v = valuation */
9481   for (m = j = 1; m+2 < lg(S); m++)
9482   {
9483     GEN c = gel(S,m+2);
9484     long r;
9485     if (is_bigint(c)) return NULL;
9486     r = -itos(c);
9487     if (r)
9488     {
9489       S = ZXn_mul(S, RgXn_negpow(eta_ZXn(m, L), r, L), L);
9490       gel(P,j) = utoipos(m);
9491       gel(E,j) = stoi(r);
9492       v = addmuliu(v, gel(E,j), m);
9493       w = addis(w, r);
9494       j++;
9495     }
9496   }
9497   if (!equalii(w, gmul2n(gk, 1)) || (!flag && !equalii(v, muluu(24,vS))))
9498     return NULL;
9499   setlg(P, j);
9500   setlg(E, j); M = mkmat2(P, E); G = mffrometaquo(M, flag);
9501   return (typ(G) != t_INT
9502           && (mfsturmmf(G) <= b + bextra || mfisequal(F, G, b)))? M: NULL;
9503 }
9504 GEN
mfisetaquo(GEN F,long flag)9505 mfisetaquo(GEN F, long flag)
9506 {
9507   pari_sp av = avma;
9508   GEN M = mfisetaquo_i(F, flag);
9509   return M? gerepilecopy(av, M): gc_const(av, gen_0);
9510 }
9511 
9512 #if 0
9513 /* number of primitive characters modulo N */
9514 static ulong
9515 numprimchars(ulong N)
9516 {
9517   GEN fa, P, E;
9518   long i, l;
9519   ulong n;
9520   if ((N & 3) == 2) return 0;
9521   fa = myfactoru(N);
9522   P = gel(fa,1); l = lg(P);
9523   E = gel(fa,2);
9524   for (i = n = 1; i < l; i++)
9525   {
9526     ulong p = P[i], e = E[i];
9527     if (e == 2) n *= p-2; else n *= (p-1)*(p-1)*upowuu(p,e-2);
9528   }
9529   return n;
9530 }
9531 #endif
9532 
9533 /* Space generated by products of two Eisenstein series */
9534 
9535 static int
cmp_small_priority(void * E,GEN a,GEN b)9536 cmp_small_priority(void *E, GEN a, GEN b)
9537 {
9538   GEN prio = (GEN)E;
9539   return cmpss(prio[(long)a], prio[(long)b]);
9540 }
9541 static long
znstar_get_expo(GEN G)9542 znstar_get_expo(GEN G) { return itou(cyc_get_expo(znstar_get_cyc(G))); }
9543 
9544 /* Return [vchi, bymod, vG]:
9545  * vG[f] = znstar(f,1) for f a conductor of (at least) a char mod N; else NULL
9546  * bymod[f] = vecsmall of conrey indexes of chars modulo f | N; else NULL
9547  * vchi[n] = a list of CHIvec [G0,chi0,o,ncharvecexpo(G0,nchi0),...]:
9548  *   chi0 = primitive char attached to Conrey Mod(n,N)
9549  * (resp. NULL if (n,N) > 1) */
9550 static GEN
charsmodN(long N)9551 charsmodN(long N)
9552 {
9553   GEN D, G, prio, phio, dummy = cgetg(1,t_VEC);
9554   GEN vP, vG = const_vec(N,NULL), vCHI  = const_vec(N,NULL);
9555   GEN bymod = const_vec(N,NULL);
9556   long pn, i, l, vt = fetch_user_var("t");
9557   D = mydivisorsu(N); l = lg(D);
9558   for (i = 1; i < l; i++)
9559     gel(bymod, D[i]) = vecsmalltrunc_init(myeulerphiu(D[i])+1);
9560   gel(vG,N) = G = znstar0(utoipos(N),1);
9561   pn = znstar_get_expo(G);  /* exponent(Z/NZ)^* */
9562   vP = const_vec(pn,NULL);
9563   for (i = 1; i <= N; i++)
9564   {
9565     GEN P, gF, G0, chi0, nchi0, chi, v, go;
9566     long j, F, o;
9567     if (ugcd(i,N) != 1) continue;
9568     chi = znconreylog(G, utoipos(i));
9569     gF = znconreyconductor(G, chi, &chi0);
9570     F = (typ(gF) == t_INT)? itou(gF): itou(gel(gF,1));
9571     G0 = gel(vG, F); if (!G0) G0 = gel(vG,F) = znstar0(gF, 1);
9572     nchi0 = znconreylog_normalize(G0,chi0);
9573     go = gel(nchi0,1); o = itou(go); /* order(chi0) */
9574     v = ncharvecexpo(G0, nchi0);
9575     if (!equaliu(go, pn)) v = zv_z_mul(v, pn / o);
9576     P = gel(vP, o); if (!P) P = gel(vP,o) = polcyclo(o,vt);
9577     /* mfcharcxinit with dummy complex powers */
9578     gel(vCHI,i) = mkvecn(6, G0, chi0, go, v, dummy, P);
9579     D = mydivisorsu(N / F); l = lg(D);
9580     for (j = 1; j < l; j++) vecsmalltrunc_append(gel(bymod, F*D[j]), i);
9581   }
9582   phio = zero_zv(pn); l = lg(vCHI); prio = cgetg(l, t_VEC);
9583   for (i = 1; i < l; i++)
9584   {
9585     GEN CHI = gel(vCHI,i);
9586     long o;
9587     if (!CHI) continue;
9588     o = CHIvec_ord(CHI);
9589     if (!phio[o]) phio[o] = myeulerphiu(o);
9590     prio[i] = phio[o];
9591   }
9592   l = lg(bymod);
9593   /* sort characters by increasing value of phi(order) */
9594   for (i = 1; i < l; i++)
9595   {
9596     GEN z = gel(bymod,i);
9597     if (z) gen_sort_inplace(z, (void*)prio, &cmp_small_priority, NULL);
9598   }
9599   return mkvec3(vCHI, bymod, vG);
9600 }
9601 
9602 static GEN
mfeisenstein2pure(long k,GEN CHI1,GEN CHI2,long ord,GEN P,long lim)9603 mfeisenstein2pure(long k, GEN CHI1, GEN CHI2, long ord, GEN P, long lim)
9604 {
9605   GEN c, V = cgetg(lim+2, t_COL);
9606   long n;
9607   c = mfeisenstein2_0(k, CHI1, CHI2, ord);
9608   if (P) c = grem(c, P);
9609   gel(V,1) = c;
9610   for (n=1; n <= lim; n++)
9611   {
9612     c = sigchi2(k, CHI1, CHI2, n, ord);
9613     if (P) c = grem(c, P);
9614     gel(V,n+1) = c;
9615   }
9616   return V;
9617 }
9618 static GEN
mfeisenstein2pure_Fl(long k,GEN CHI1vec,GEN CHI2vec,GEN vz,ulong p,long lim)9619 mfeisenstein2pure_Fl(long k, GEN CHI1vec, GEN CHI2vec, GEN vz, ulong p, long lim)
9620 {
9621   GEN V = cgetg(lim+2, t_VECSMALL);
9622   long n;
9623   V[1] = mfeisenstein2_0_Fl(k, CHI1vec, CHI2vec, vz, p);
9624   for (n=1; n <= lim; n++) V[n+1] = sigchi2_Fl(k, CHI1vec, CHI2vec, n, vz, p);
9625   return V;
9626 }
9627 
9628 static GEN
getcolswt2(GEN M,GEN D,ulong p)9629 getcolswt2(GEN M, GEN D, ulong p)
9630 {
9631   GEN R, v = gel(M,1);
9632   long i, l = lg(M) - 1;
9633   R = cgetg(l, t_MAT); /* skip D[1] = 1 */
9634   for (i = 1; i < l; i++)
9635   {
9636     GEN w = Flv_Fl_mul(gel(M,i+1), D[i+1], p);
9637     gel(R,i) = Flv_sub(v, w, p);
9638   }
9639   return R;
9640 }
9641 static GEN
expandbd(GEN V,long d)9642 expandbd(GEN V, long d)
9643 {
9644   long L, n, nd;
9645   GEN W;
9646   if (d == 1) return V;
9647   L = lg(V)-1; W = zerocol(L); /* nd = n/d */
9648   for (n = nd = 0; n < L; n += d, nd++) gel(W, n+1) = gel(V, nd+1);
9649   return W;
9650 }
9651 static GEN
expandbd_Fl(GEN V,long d)9652 expandbd_Fl(GEN V, long d)
9653 {
9654   long L, n, nd;
9655   GEN W;
9656   if (d == 1) return V;
9657   L = lg(V)-1; W = zero_Flv(L); /* nd = n/d */
9658   for (n = nd = 0; n < L; n += d, nd++) W[n+1] = V[nd+1];
9659   return W;
9660 }
9661 static void
getcols_i(GEN * pM,GEN * pvj,GEN gk,GEN CHI1vec,GEN CHI2vec,long NN1,GEN vz,ulong p,long lim)9662 getcols_i(GEN *pM, GEN *pvj, GEN gk, GEN CHI1vec, GEN CHI2vec, long NN1, GEN vz,
9663           ulong p, long lim)
9664 {
9665   GEN CHI1 = CHIvec_CHI(CHI1vec), CHI2 = CHIvec_CHI(CHI2vec);
9666   long N2 = CHIvec_N(CHI2vec);
9667   GEN vj, M, D = mydivisorsu(NN1/N2);
9668   long i, l = lg(D), k = gk[2];
9669   GEN V = mfeisenstein2pure_Fl(k, CHI1vec, CHI2vec, vz, p, lim);
9670   M = cgetg(l, t_MAT);
9671   for (i = 1; i < l; i++) gel(M,i) = expandbd_Fl(V, D[i]);
9672   if (k == 2 && N2 == 1 && CHIvec_N(CHI1vec) == 1)
9673   {
9674     M = getcolswt2(M, D, p); l--;
9675     D = vecslice(D, 2, l);
9676   }
9677   *pM = M;
9678   *pvj = vj = cgetg(l, t_VEC);
9679   for (i = 1; i < l; i++) gel(vj,i) = mkvec4(gk, CHI1, CHI2, utoipos(D[i]));
9680 }
9681 
9682 /* find all CHI1, CHI2 mod N such that CHI1*CHI2 = CHI, f(CHI1)*f(CHI2) | N.
9683  * set M = mfcoefs(B_e E(CHI1,CHI2), lim), vj = [e,i1,i2] */
9684 static void
getcols(GEN * pM,GEN * pv,long k,long nCHI,GEN allN,GEN vz,ulong p,long lim)9685 getcols(GEN *pM, GEN *pv, long k, long nCHI, GEN allN, GEN vz, ulong p,
9686         long lim)
9687 {
9688   GEN vCHI = gel(allN,1), gk = utoi(k);
9689   GEN M = cgetg(1,t_MAT), v = cgetg(1,t_VEC);
9690   long i1, N = lg(vCHI)-1;
9691   for (i1 = 1; i1 <= N; i1++)
9692   {
9693     GEN CHI1vec = gel(vCHI, i1), CHI2vec, M1, v1;
9694     long NN1, i2;
9695     if (!CHI1vec) continue;
9696     if (k == 1 && CHIvec_parity(CHI1vec) == -1) continue;
9697     NN1 = N/CHIvec_N(CHI1vec); /* N/f(chi1) */;
9698     i2 = Fl_div(nCHI,i1, N);
9699     if (!i2) i2 = 1;
9700     CHI2vec = gel(vCHI,i2);
9701     if (NN1 % CHIvec_N(CHI2vec)) continue; /* f(chi1)f(chi2) | N ? */
9702     getcols_i(&M1, &v1, gk, CHI1vec, CHI2vec, NN1, vz, p, lim);
9703     M = shallowconcat(M, M1);
9704     v = shallowconcat(v, v1);
9705   }
9706   *pM = M;
9707   *pv = v;
9708 }
9709 
9710 static void
update_Mj(GEN * M,GEN * vecj,GEN * pz,ulong p)9711 update_Mj(GEN *M, GEN *vecj, GEN *pz, ulong p)
9712 {
9713   GEN perm;
9714   *pz = Flm_indexrank(*M, p); perm = gel(*pz,2);
9715   *M = vecpermute(*M, perm);
9716   *vecj = vecpermute(*vecj, perm);
9717 }
9718 static int
getcolsgen(long dim,GEN * pM,GEN * pvj,GEN * pz,long k,long ell,long nCHI,GEN allN,GEN vz,ulong p,long lim)9719 getcolsgen(long dim, GEN *pM, GEN *pvj, GEN *pz, long k, long ell, long nCHI,
9720            GEN allN, GEN vz, ulong p, long lim)
9721 {
9722   GEN vCHI = gel(allN,1), bymod = gel(allN,2), gell = utoi(ell);
9723   long i1, N = lg(vCHI)-1;
9724   long L = lim+1;
9725   if (lg(*pvj)-1 >= dim) update_Mj(pM, pvj, pz, p);
9726   if (lg(*pvj)-1 == dim) return 1;
9727   for (i1 = 1; i1 <= N; i1++)
9728   {
9729     GEN CHI1vec = gel(vCHI, i1), T;
9730     long par1, j, l, N1, NN1;
9731 
9732     if (!CHI1vec) continue;
9733     par1 = CHIvec_parity(CHI1vec);
9734     if (ell == 1 && par1 == -1) continue;
9735     if (odd(ell)) par1 = -par1;
9736     N1 = CHIvec_N(CHI1vec);
9737     NN1 = N/N1;
9738     T = gel(bymod, NN1); l = lg(T);
9739     for (j = 1; j < l; j++)
9740     {
9741       long i2 = T[j], l1, l2, j1, s, nC;
9742       GEN M, M1, M2, vj, vj1, vj2, CHI2vec = gel(vCHI, i2);
9743       if (CHIvec_parity(CHI2vec) != par1) continue;
9744       nC = Fl_div(nCHI, Fl_mul(i1,i2,N), N);
9745       getcols(&M2, &vj2, k-ell, nC, allN, vz, p, lim);
9746       l2 = lg(M2); if (l2 == 1) continue;
9747       getcols_i(&M1, &vj1, gell, CHI1vec, CHI2vec, NN1, vz, p, lim);
9748       l1 = lg(M1);
9749       M1 = Flm_to_FlxV(M1, 0);
9750       M2 = Flm_to_FlxV(M2, 0);
9751       M  = cgetg((l1-1)*(l2-1) + 1, t_MAT);
9752       vj = cgetg((l1-1)*(l2-1) + 1, t_VEC);
9753       for (j1 = s = 1; j1 < l1; j1++)
9754       {
9755         GEN E = gel(M1,j1), v = gel(vj1,j1);
9756         long j2;
9757         for (j2 = 1; j2 < l2; j2++, s++)
9758         {
9759           GEN c = Flx_to_Flv(Flxn_mul(E, gel(M2,j2), L, p), L);
9760           gel(M,s) = c;
9761           gel(vj,s) = mkvec2(v, gel(vj2,j2));
9762         }
9763       }
9764       *pM = shallowconcat(*pM, M);
9765       *pvj = shallowconcat(*pvj, vj);
9766       if (lg(*pvj)-1 >= dim) update_Mj(pM, pvj, pz, p);
9767       if (lg(*pvj)-1 == dim) return 1;
9768     }
9769   }
9770   if (ell == 1)
9771   {
9772     update_Mj(pM, pvj, pz, p);
9773     return (lg(*pvj)-1 == dim);
9774   }
9775   return 0;
9776 }
9777 
9778 static GEN
mkF2bd(long d,long lim)9779 mkF2bd(long d, long lim)
9780 {
9781   GEN V = zerovec(lim + 1);
9782   long n;
9783   gel(V, 1) = ginv(stoi(-24));
9784   for (n = 1; n <= lim/d; n++) gel(V, n*d + 1) = mysumdivku(n, 1);
9785   return V;
9786 }
9787 
9788 static GEN
mkeisen(GEN E,long ord,GEN P,long lim)9789 mkeisen(GEN E, long ord, GEN P, long lim)
9790 {
9791   long k = itou(gel(E,1)), e = itou(gel(E,4));
9792   GEN CHI1 = gel(E,2), CHI2 = gel(E,3);
9793   if (k == 2 && mfcharistrivial(CHI1) && mfcharistrivial(CHI2))
9794     return gsub(mkF2bd(1,lim), gmulgs(mkF2bd(e,lim), e));
9795   else
9796   {
9797     GEN V = mfeisenstein2pure(k, CHI1, CHI2, ord, P, lim);
9798     return expandbd(V, e);
9799   }
9800 }
9801 static GEN
mkM(GEN vj,long pn,GEN P,long lim)9802 mkM(GEN vj, long pn, GEN P, long lim)
9803 {
9804   long j, l = lg(vj), L = lim+1;
9805   GEN M = cgetg(l, t_MAT);
9806   for (j = 1; j < l; j++)
9807   {
9808     GEN E1, E2;
9809     parse_vecj(gel(vj,j), &E1,&E2);
9810     E1 = RgV_to_RgX(mkeisen(E1, pn, P, lim), 0);
9811     if (E2)
9812     {
9813       E2 = RgV_to_RgX(mkeisen(E2, pn, P, lim), 0);
9814       E1 = RgXn_mul(E1, E2, L);
9815     }
9816     E1 = RgX_to_RgC(E1, L);
9817     if (P && E2) E1 = RgXQV_red(E1, P);
9818     gel(M,j) = E1;
9819   }
9820   return M;
9821 }
9822 
9823 /* assume N > 2 */
9824 static GEN
mffindeisen1(long N)9825 mffindeisen1(long N)
9826 {
9827   GEN G = znstar0(utoipos(N), 1), L = chargalois(G, NULL), chi0 = NULL;
9828   long j, m = N, l = lg(L);
9829   for (j = 1; j < l; j++)
9830   {
9831     GEN chi = gel(L,j);
9832     long r = myeulerphiu(itou(zncharorder(G,chi)));
9833     if (r >= m) continue;
9834     chi = znconreyfromchar(G, chi);
9835     if (zncharisodd(G,chi)) { m = r; chi0 = chi; if (r == 1) break; }
9836   }
9837   if (!chi0) pari_err_BUG("mffindeisen1 [no Eisenstein series found]");
9838   chi0 = znchartoprimitive(G,chi0);
9839   return mfcharGL(gel(chi0,1), gel(chi0,2));
9840 }
9841 
9842 static GEN
mfeisensteinspaceinit_i(long N,long k,GEN CHI)9843 mfeisensteinspaceinit_i(long N, long k, GEN CHI)
9844 {
9845   GEN M, Minv, vj, vG, GN, allN, P, vz, z = NULL;
9846   long nCHI, lim, ell, ord, dim = mffulldim(N, k, CHI);
9847   ulong r, p;
9848 
9849   if (!dim) retmkvec3(cgetg(1,t_VECSMALL),
9850                       mkvec2(cgetg(1,t_MAT),gen_1),cgetg(1,t_VEC));
9851   lim = mfsturmNk(N, k) + 1;
9852   allN = charsmodN(N);
9853   vG = gel(allN,3);
9854   GN = gel(vG,N);
9855   ord = znstar_get_expo(GN);
9856   P = ord <= 2? NULL: polcyclo(ord, varn(mfcharpol(CHI)));
9857   CHI = induce(GN, CHI); /* lift CHI mod N before mfcharno*/
9858   nCHI = mfcharno(CHI);
9859   r = QabM_init(ord, &p);
9860   vz = Fl_powers(r, ord, p);
9861   getcols(&M, &vj, k, nCHI, allN, vz, p, lim);
9862   for (ell = k>>1; ell >= 1; ell--)
9863     if (getcolsgen(dim, &M, &vj, &z, k, ell, nCHI, allN, vz, p, lim)) break;
9864   if (!z) update_Mj(&M, &vj, &z, p);
9865   if (lg(vj) - 1 < dim) return NULL;
9866   M = mkM(vj, ord, P, lim);
9867   Minv = QabM_Minv(rowpermute(M, gel(z,1)), P, ord);
9868   return mkvec4(gel(z,1), Minv, vj, utoi(ord));
9869 }
9870 /* true mf */
9871 static GEN
mfeisensteinspaceinit(GEN mf)9872 mfeisensteinspaceinit(GEN mf)
9873 {
9874   pari_sp av = avma;
9875   GEN z, CHI = MF_get_CHI(mf);
9876   long N = MF_get_N(mf), k = MF_get_k(mf);
9877   if (!CHI) CHI = mfchartrivial();
9878   z = mfeisensteinspaceinit_i(N, k, CHI);
9879   if (!z)
9880   {
9881     GEN E, CHIN = mffindeisen1(N), CHI0 = mfchartrivial();
9882     z = mfeisensteinspaceinit_i(N, k+1, mfcharmul(CHI, CHIN));
9883     if (z) E = mkvec4(gen_1, CHI0, CHIN, gen_1);
9884     else
9885     {
9886       z = mfeisensteinspaceinit_i(N, k+2, CHI);
9887       E = mkvec4(gen_2, CHI0, CHI0, utoipos(N));
9888     }
9889     z = mkvec2(z, E);
9890   }
9891   return gerepilecopy(av, z);
9892 }
9893 
9894 /* decomposition of modular form on eisenspace */
9895 static GEN
mfeisensteindec(GEN mf,GEN F)9896 mfeisensteindec(GEN mf, GEN F)
9897 {
9898   pari_sp av = avma;
9899   GEN M, Mindex, Mvecj, V, B, CHI;
9900   long o, ord;
9901 
9902   Mvecj = obj_checkbuild(mf, MF_EISENSPACE, &mfeisensteinspaceinit);
9903   if (lg(Mvecj) < 5)
9904   {
9905     GEN E, e = gel(Mvecj,2), gkE = gel(e,1);
9906     long dE = itou(gel(e,4));
9907     Mvecj = gel(Mvecj,1);
9908     E = mfeisenstein(itou(gkE), NULL, gel(e,3));
9909     if (dE != 1) E = mfbd_E2(E, dE, gel(e,2)); /* here k = 2 */
9910     F = mfmul(F, E);
9911   }
9912   M = gel(Mvecj, 2);
9913   if (lg(M) == 1) return cgetg(1, t_VEC);
9914   Mindex = gel(Mvecj, 1);
9915   ord = itou(gel(Mvecj,4));
9916   V = mfcoefs(F, Mindex[lg(Mindex)-1]-1, 1); settyp(V, t_COL);
9917   CHI = mf_get_CHI(F);
9918   o = mfcharorder(CHI);
9919   if (o > 2 && o != ord)
9920   { /* convert Mod(.,polcyclo(o)) to Mod(., polcyclo(N)) for o | N,
9921      * o and N both != 2 (mod 4) */
9922     GEN z, P = gel(M,4); /* polcyclo(ord) */
9923     long vt = varn(P);
9924     z = gmodulo(pol_xn(ord/o, vt), P);
9925     if (ord % o) pari_err_TYPE("mfeisensteindec", V);
9926     V = gsubst(liftpol_shallow(V), vt, z);
9927   }
9928   B = Minv_RgC_mul(M, vecpermute(V, Mindex));
9929   return gerepileupto(av, B);
9930 }
9931 
9932 /*********************************************************************/
9933 /*                        END EISENSPACE                             */
9934 /*********************************************************************/
9935 
9936 static GEN
sertocol2(GEN S,long l)9937 sertocol2(GEN S, long l)
9938 {
9939   GEN C = cgetg(l + 2, t_COL);
9940   long i;
9941   for (i = 0; i <= l; i++) gel(C, i+1) = polcoef_i(S, i, -1);
9942   return C;
9943 }
9944 
9945 /* Compute polynomial P0 such that F=E4^(k/4)P0(E6/E4^(3/2)). */
9946 static GEN
mfcanfindp0(GEN F,long k)9947 mfcanfindp0(GEN F, long k)
9948 {
9949   pari_sp ltop = avma;
9950   GEN E4, E6, V, V1, Q, W, res, M, B;
9951   long l, j;
9952   l = k/6 + 2;
9953   V = mfcoefsser(F,l);
9954   E4 = mfcoefsser(mfEk(4),l);
9955   E6 = mfcoefsser(mfEk(6),l);
9956   V1 = gdiv(V, gpow(E4, sstoQ(k,4), 0));
9957   Q = gdiv(E6, gpow(E4, sstoQ(3,2), 0));
9958   W = gpowers(Q, l - 1);
9959   M = cgetg(l + 1, t_MAT);
9960   for (j = 1; j <= l; j++) gel(M,j) = sertocol2(gel(W,j), l);
9961   B = sertocol2(V1, l);
9962   res = inverseimage(M, B);
9963   if (lg(res) == 1) err_space(F);
9964   return gerepilecopy(ltop, gtopolyrev(res, 0));
9965 }
9966 
9967 /* Compute the first n+1 Taylor coeffs at tau=I of a modular form
9968  * on SL_2(Z). */
9969 GEN
mftaylor(GEN F,long n,long flreal,long prec)9970 mftaylor(GEN F, long n, long flreal, long prec)
9971 {
9972   pari_sp ltop = avma;
9973   GEN P0, Pm1 = gen_0, v;
9974   GEN X2 = mkpoln(3, ghalf,gen_0,gneg(ghalf)); /* (x^2-1) / 2 */
9975   long k, m;
9976   if (!checkmf_i(F)) pari_err_TYPE("mftaylor",F);
9977   k = mf_get_k(F);
9978   if (mf_get_N(F) != 1 || k < 0) pari_err_IMPL("mftaylor for this form");
9979   P0 = mfcanfindp0(F, k);
9980   v = cgetg(n+2, t_VEC); gel(v, 1) = RgX_coeff(P0,0);
9981   for (m = 0; m < n; m++)
9982   {
9983     GEN P1 = gdivgs(gmulsg(-(k + 2*m), RgX_shift(P0,1)), 12);
9984     P1 = gadd(P1, gmul(X2, RgX_deriv(P0)));
9985     if (m) P1 = gsub(P1, gdivgs(gmulsg(m*(m+k-1), Pm1), 144));
9986     Pm1 = P0; P0 = P1;
9987     gel(v, m+2) = RgX_coeff(P0, 0);
9988   }
9989   if (flreal)
9990   {
9991     GEN pi2 = Pi2n(1, prec), pim4 = gmulsg(-2, pi2), VPC;
9992     GEN C = gmulsg(3, gdiv(gpowgs(ggamma(ginv(utoi(4)), prec), 8), gpowgs(pi2, 6)));
9993     /* E_4(i): */
9994     GEN facn = gen_1;
9995     VPC = gpowers(gmul(pim4, gsqrt(C, prec)), n);
9996     C = gpow(C, sstoQ(k,4), prec);
9997     for (m = 0; m <= n; m++)
9998     {
9999       gel(v, m+1) = gdiv(gmul(C, gmul(gel(v, m+1), gel(VPC, m+1))), facn);
10000       facn = gmulgs(facn, m+1);
10001     }
10002   }
10003   return gerepilecopy(ltop, v);
10004 }
10005 
10006 #if 0
10007 /* To be used in mfeigensearch() */
10008 GEN
10009 mfreadratfile()
10010 {
10011   GEN eqn;
10012   pariFILE *F = pari_fopengz("rateigen300.gp");
10013   eqn = gp_readvec_stream(F->file);
10014   pari_fclose(F);
10015   return eqn;
10016 }
10017 #endif
10018  /*****************************************************************/
10019 /*           EISENSTEIN CUSPS: COMPLEX DIRECTLY: one F_k         */
10020 /*****************************************************************/
10021 
10022 /* CHIvec = charinit(CHI); data = [N1g/g1,N2g/g2,g1/g,g2/g,C/g1,C/g2,
10023  * (N1g/g1)^{-1},(N2g/g2)^{-1}] */
10024 
10025 /* nm = n/m;
10026  * z1 = powers of \z_{C/g}^{(Ae/g)^{-1}},
10027  * z2 = powers of \z_N^{A^{-1}(g1g2/C)}]
10028  * N.B. : we compute value and conjugate at the end, so it is (Ae/g)^{-1}
10029  * and not -(Ae/g)^{-1} */
10030 static GEN
eiscnm(long nm,long m,GEN CHI1vec,GEN CHI2vec,GEN data,GEN z1)10031 eiscnm(long nm, long m, GEN CHI1vec, GEN CHI2vec, GEN data, GEN z1)
10032 {
10033   long Cg1 = data[5], s10 = (nm*data[7]) % Cg1, r10 = (nm - data[1]*s10) / Cg1;
10034   long Cg2 = data[6], s20 = (m *data[8]) % Cg2, r20 = (m  - data[2]*s20) / Cg2;
10035   long j1, r1, s1;
10036   GEN T = gen_0;
10037   for (j1 = 0, r1 = r10, s1 = s10; j1 < data[3]; j1++, r1 -= data[1], s1 += Cg1)
10038   {
10039     GEN c1 = mychareval(CHI1vec, r1);
10040     if (!gequal0(c1))
10041     {
10042       long j2, r2, s2;
10043       GEN S = gen_0;
10044       for (j2 = 0, r2 = r20, s2 = s20; j2 < data[4]; j2++, r2 -= data[2], s2 += Cg2)
10045       {
10046         GEN c2 = mychareval(CHI2vec, r2);
10047         if (!gequal0(c2)) S = gadd(S, gmul(c2, rootsof1pow(z1, s1*s2)));
10048       }
10049       T = gadd(T, gmul(c1, S));
10050     }
10051   }
10052   return conj_i(T);
10053 }
10054 
10055 static GEN
fg1g2n(long n,long k,GEN CHI1vec,GEN CHI2vec,GEN data,GEN z1,GEN z2)10056 fg1g2n(long n, long k, GEN CHI1vec, GEN CHI2vec, GEN data, GEN z1, GEN z2)
10057 {
10058   pari_sp av = avma;
10059   GEN S = gen_0, D = mydivisorsu(n);
10060   long i, l = lg(D);
10061   for (i = 1; i < l; i++)
10062   {
10063     long m = D[i], nm = D[l-i]; /* n/m */
10064     GEN u = eiscnm( nm,  m, CHI1vec, CHI2vec, data, z1);
10065     GEN v = eiscnm(-nm, -m, CHI1vec, CHI2vec, data, z1);
10066     GEN w = odd(k) ? gsub(u, v) : gadd(u, v);
10067     S = gadd(S, gmul(powuu(m, k-1), w));
10068   }
10069   return gerepileupto(av, gmul(S, rootsof1pow(z2, n)));
10070 }
10071 
10072 static GEN
gausssumcx(GEN CHIvec,long prec)10073 gausssumcx(GEN CHIvec, long prec)
10074 {
10075   GEN z, S, V;
10076   long m, N = CHIvec_N(CHIvec);
10077   if (N == 1) return gen_1;
10078   V = CHIvec_val(CHIvec);
10079   z = rootsof1u_cx(N, prec);
10080   S = gmul(z, gel(V, N));
10081   for (m = N-1; m >= 1; m--) S = gmul(z, gadd(gel(V, m), S));
10082   return S;
10083 }
10084 
10085 /* Computation of Q_k(\z_N^s) as a polynomial in \z_N^s. FIXME: explicit
10086  * formula ? */
10087 static GEN
mfqk(long k,long N)10088 mfqk(long k, long N)
10089 {
10090   GEN X, P, ZI, Q, Xm1, invden;
10091   long i;
10092   ZI = gdivgs(RgX_shift_shallow(RgV_to_RgX(identity_ZV(N-1), 0), 1), N);
10093   if (k == 1) return ZI;
10094   P = gsubgs(pol_xn(N,0), 1);
10095   invden = RgXQ_powu(ZI, k, P);
10096   X = pol_x(0); Q = gneg(X); Xm1 = gsubgs(X, 1);
10097   for (i = 2; i < k; i++)
10098     Q = RgX_shift_shallow(ZX_add(gmul(Xm1, ZX_deriv(Q)), gmulsg(-i, Q)), 1);
10099   return RgXQ_mul(Q, invden, P);
10100 }
10101 
10102 /* CHI mfchar; M is a multiple of the conductor of CHI, but is NOT
10103  * necessarily its modulus */
10104 static GEN
mfskcx(long k,GEN CHI,long M,long prec)10105 mfskcx(long k, GEN CHI, long M, long prec)
10106 {
10107   GEN S, CHIvec, P;
10108   long F, m, i, l;
10109   CHI = mfchartoprimitive(CHI, &F);
10110   CHIvec = mfcharcxinit(CHI, prec);
10111   if (F == 1) S = gdivgs(bernfrac(k), k);
10112   else
10113   {
10114     GEN Q = mfqk(k, F), V = CHIvec_val(CHIvec);
10115     S = gmul(gel(V, F), RgX_coeff(Q, 0));
10116     for (m = 1; m < F; m++) S = gadd(S, gmul(gel(V, m), RgX_coeff(Q, m)));
10117     S = conj_i(S);
10118   }
10119   /* prime divisors of M not dividing f(chi) */
10120   P = gel(myfactoru(u_ppo(M/F,F)), 1); l = lg(P);
10121   for (i = 1; i < l; i++)
10122   {
10123     long p = P[i];
10124     S = gmul(S, gsubsg(1, gdiv(mychareval(CHIvec, p), powuu(p, k))));
10125   }
10126   return gmul(gmul(gausssumcx(CHIvec, prec), S), powuu(M/F, k));
10127 }
10128 
10129 static GEN
f00_i(long k,GEN CHI1vec,GEN CHI2vec,GEN G2,GEN S,long prec)10130 f00_i(long k, GEN CHI1vec, GEN CHI2vec, GEN G2, GEN S, long prec)
10131 {
10132   GEN c, a;
10133   long N1 = CHIvec_N(CHI1vec), N2 = CHIvec_N(CHI2vec);
10134   if (S[2] != N1) return gen_0;
10135   c = mychareval(CHI1vec, S[3]);
10136   if (isintzero(c)) return gen_0;
10137   a = mfskcx(k, mfchardiv(CHIvec_CHI(CHI2vec), CHIvec_CHI(CHI1vec)), N1*N2, prec);
10138   a = gmul(a, conj_i(gmul(c,G2)));
10139   return gdiv(a, mulsi(-N2, powuu(S[1], k-1)));
10140 }
10141 
10142 static GEN
f00(long k,GEN CHI1vec,GEN CHI2vec,GEN G1,GEN G2,GEN data,long prec)10143 f00(long k, GEN CHI1vec,GEN CHI2vec, GEN G1,GEN G2, GEN data, long prec)
10144 {
10145   GEN T1, T2;
10146   T2 = f00_i(k, CHI1vec, CHI2vec, G2, data, prec);
10147   if (k > 1) return T2;
10148   T1 = f00_i(k, CHI2vec, CHI1vec, G1, data, prec);
10149   return gadd(T1, T2);
10150 }
10151 
10152 /* ga in SL_2(Z), find beta [a,b;c,d] in Gamma_0(N) and mu in Z such that
10153  * beta * ga * T^u = [A',B';C',D'] with C' | N and N | B', C' > 0 */
10154 static void
mfgatogap(GEN ga,long N,long * pA,long * pC,long * pD,long * pd,long * pmu)10155 mfgatogap(GEN ga, long N, long *pA, long *pC, long *pD, long *pd, long *pmu)
10156 {
10157   GEN A = gcoeff(ga,1,1), B = gcoeff(ga,1,2);
10158   GEN C = gcoeff(ga,2,1), D = gcoeff(ga,2,2), a, b, c, d;
10159   long t, Ap, Cp, B1, D1, mu;
10160   Cp = itou(bezout(muliu(A,N), C, &c, &d)); /* divides N */
10161   t = 0;
10162   if (Cp > 1)
10163   { /* (d, N/Cp) = 1, find t such that (d - t*(A*N/Cp), N) = 1 */
10164     long dN = umodiu(d,Cp), Q = (N/Cp * umodiu(A,Cp)) % Cp;
10165     while (ugcd(dN, Cp) > 1) { t++; dN = Fl_sub(dN, Q, Cp); }
10166   }
10167   if (t)
10168   {
10169     c = addii(c, mului(t, diviuexact(C,Cp)));
10170     d = subii(d, mului(t, muliu(A, N/Cp))); /* (d,N) = 1 */
10171   }
10172   D1 = umodiu(mulii(d,D), N);
10173   (void)bezout(d, mulis(c,-N), &a, &b); /* = 1 */
10174   t = 0; Ap = umodiu(addii(mulii(a,A), mulii(b,C)), N); /* (Ap,Cp) = 1 */
10175   while (ugcd(Ap, N) > 1) { t++; Ap = Fl_add(Ap, Cp, N); }
10176   B1 = umodiu(a,N)*umodiu(B,N) + umodiu(b,N)*umodiu(D,N) + t*D1;
10177   B1 %= N;
10178   *pmu = mu = Fl_neg(Fl_div(B1, Ap, N), N);
10179   /* A', D' and d only needed modulo N */
10180   *pd = umodiu(d, N);
10181   *pA = Ap;
10182   *pC = Cp; *pD = (D1 + Cp*mu) % N;
10183 }
10184 
10185 #if 0
10186 /* CHI is a mfchar, return alpha(CHI) */
10187 static long
10188 mfalchi(GEN CHI, long AN, long cg)
10189 {
10190   GEN G = gel(CHI,1), chi = gel(CHI,2), go = gmfcharorder(CHI);
10191   long o = itou(go), a = itos( znchareval(G, chi, stoi(1 + AN/cg), go) );
10192   if (a < 0 || (cg * a) % o) pari_err_BUG("mfalchi");
10193   return (cg * a) / o;
10194 }
10195 #endif
10196 /* return A such that CHI1(t) * CHI2(t) = e(A) or NULL if (t,N1*N2) > 1 */
10197 static GEN
mfcharmuleval(GEN CHI1vec,GEN CHI2vec,long t)10198 mfcharmuleval(GEN CHI1vec, GEN CHI2vec, long t)
10199 {
10200   long a1 = mycharexpo(CHI1vec, t), o1 = CHIvec_ord(CHI1vec);
10201   long a2 = mycharexpo(CHI2vec, t), o2 = CHIvec_ord(CHI2vec);;
10202   if (a1 < 0 || a2 < 0) return NULL;
10203   return sstoQ(a1*o2 + a2*o1, o1*o2);
10204 }
10205 static GEN
mfcharmulcxeval(GEN CHI1vec,GEN CHI2vec,long t,long prec)10206 mfcharmulcxeval(GEN CHI1vec, GEN CHI2vec, long t, long prec)
10207 {
10208   GEN A = mfcharmuleval(CHI1vec, CHI2vec, t);
10209   long n, d;
10210   if (!A) return gen_0;
10211   Qtoss(A, &n,&d); return rootsof1q_cx(n, d, prec);
10212 }
10213 /* alpha(CHI1 * CHI2) */
10214 static long
mfalchi2(GEN CHI1vec,GEN CHI2vec,long AN,long cg)10215 mfalchi2(GEN CHI1vec, GEN CHI2vec, long AN, long cg)
10216 {
10217   GEN A = mfcharmuleval(CHI1vec, CHI2vec, 1 + AN/cg);
10218   long a;
10219   if (!A) pari_err_BUG("mfalchi2");
10220   A = gmulsg(cg, A);
10221   if (typ(A) != t_INT) pari_err_BUG("mfalchi2");
10222   a = itos(A) % cg; if (a < 0) a += cg;
10223   return a;
10224 }
10225 
10226 /* return g = (a,b), set u >= 0 s.t. g = a * u (mod b) */
10227 static long
mybezout(long a,long b,long * pu)10228 mybezout(long a, long b, long *pu)
10229 {
10230   long junk, g = cbezout(a, b, pu, &junk);
10231   if (*pu < 0) *pu += b/g;
10232   return g;
10233 }
10234 
10235 /* E = [k, CHI1,CHI2, e], CHI1 and CHI2 primitive mfchars such that,
10236  * CHI1(-1)*CHI2(-1) = (-1)^k; expansion of (B_e (E_k(CHI1,CHI2))) | ga.
10237  * w is the width for the space of the calling function. */
10238 static GEN
mfeisensteingacx(GEN E,long w,GEN ga,long lim,long prec)10239 mfeisensteingacx(GEN E, long w, GEN ga, long lim, long prec)
10240 {
10241   GEN CHI1vec, CHI2vec, CHI1 = gel(E,2), CHI2 = gel(E,3), v, S, ALPHA;
10242   GEN G1, G2, z1, z2, data;
10243   long k = itou(gel(E,1)), e = itou(gel(E,4));
10244   long N1 = mfcharmodulus(CHI1);
10245   long N2 = mfcharmodulus(CHI2), N = e * N1 * N2;
10246   long NsurC, cg, wN, A, C, Ai, d, mu, alchi, na, da;
10247   long eg, g, gH, U, u0, u1, u2, Aig, H, m, n, t, Cg, NC1, NC2;
10248 
10249   mfgatogap(ga, N, &A, &C, &Ai, &d, &mu);
10250   CHI1vec = mfcharcxinit(CHI1, prec);
10251   CHI2vec = mfcharcxinit(CHI2, prec);
10252   NsurC = N/C; cg  = ugcd(C, NsurC); wN = NsurC / cg;
10253   if (w%wN) pari_err_BUG("mfeisensteingacx [wN does not divide w]");
10254   alchi = mfalchi2(CHI1vec, CHI2vec, A*N, cg);
10255   ALPHA = sstoQ(alchi, NsurC);
10256 
10257   g = mybezout(A*e, C, &u0); Cg = C/g; eg = e/g;
10258   NC1 = mybezout(N1, Cg, &u1);
10259   NC2 = mybezout(N2, Cg, &u2);
10260   H = (NC1*NC2*g)/Cg;
10261   Aig = (Ai*H)%N; if (Aig < 0) Aig += N;
10262   z1 = rootsof1powinit(u0, Cg, prec);
10263   z2 = rootsof1powinit(Aig, N, prec);
10264   data = mkvecsmalln(8, N1/NC1, N2/NC2, NC1, NC2, Cg/NC1, Cg/NC2, u1, u2);
10265   v = zerovec(lim + 1);
10266   /* need n*H = alchi (mod cg) */
10267   gH = mybezout(H, cg, &U);
10268   if (gH > 1)
10269   {
10270     if (alchi % gH) return mkvec2(gen_0, v);
10271     alchi /= gH; cg /= gH; H /= gH;
10272   }
10273   G1 = gausssumcx(CHI1vec, prec);
10274   G2 = gausssumcx(CHI2vec, prec);
10275   if (!alchi)
10276     gel(v,1) = f00(k, CHI1vec,CHI2vec,G1,G2, mkvecsmall3(NC2,Cg,A*eg), prec);
10277   n = Fl_mul(alchi,U,cg); if (!n) n = cg;
10278   m = (n*H - alchi) / cg; /* positive, exact division */
10279   for (; m <= lim; n+=cg, m+=H)
10280     gel(v, m+1) = fg1g2n(n, k, CHI1vec, CHI2vec, data, z1,z2);
10281   t = (2*e)/g; if (odd(k)) t = -t;
10282   v = gdiv(v, gmul(conj_i(gmul(G1,G2)), mulsi(t, powuu(eg*N2/NC2, k-1))));
10283   if (k == 2 && N1 == 1 && N2 == 1) v = gsub(mkF2bd(wN,lim), gmulsg(e,v));
10284 
10285   Qtoss(ALPHA, &na,&da);
10286   S = conj_i( mfcharmulcxeval(CHI1vec,CHI2vec,d,prec) ); /* CHI(1/d) */
10287   if (wN > 1)
10288   {
10289     GEN z = rootsof1powinit(-mu, wN, prec);
10290     long i, l = lg(v);
10291     for (i = 1; i < l; i++) gel(v,i) = gmul(gel(v,i), rootsof1pow(z,i-1));
10292   }
10293   v = RgV_Rg_mul(v, gmul(S, rootsof1q_cx(-mu*na, da, prec)));
10294   return mkvec2(ALPHA, bdexpand(v, w/wN));
10295 }
10296 
10297 /*****************************************************************/
10298 /*                       END EISENSTEIN CUSPS                    */
10299 /*****************************************************************/
10300 
10301 static GEN
mfchisimpl(GEN CHI)10302 mfchisimpl(GEN CHI)
10303 {
10304   GEN G, chi;
10305   if (typ(CHI) == t_INT) return CHI;
10306   G = gel(CHI, 1); chi = gel(CHI, 2);
10307   switch(mfcharorder(CHI))
10308   {
10309     case 1: chi = gen_1; break;
10310     case 2: chi = znchartokronecker(G,chi,1); break;
10311     default:chi = mkintmod(znconreyexp(G,chi), znstar_get_N(G)); break;
10312   }
10313   return chi;
10314 }
10315 
10316 GEN
mfparams(GEN F)10317 mfparams(GEN F)
10318 {
10319   pari_sp av = avma;
10320   GEN z, mf, CHI;
10321   if ((mf = checkMF_i(F)))
10322   {
10323     long N = MF_get_N(mf);
10324     GEN gk = MF_get_gk(mf);
10325     CHI = MF_get_CHI(mf);
10326     z = mkvec5(utoi(N), gk, CHI, utoi(MF_get_space(mf)), mfcharpol(CHI));
10327   }
10328   else
10329   {
10330     if (!checkmf_i(F)) pari_err_TYPE("mfparams", F);
10331     z = vec_append(mf_get_NK(F), mfcharpol(mf_get_CHI(F)));
10332   }
10333   gel(z,3) = mfchisimpl(gel(z,3));
10334   return gerepilecopy(av, z);
10335 }
10336 
10337 GEN
mfisCM(GEN F)10338 mfisCM(GEN F)
10339 {
10340   pari_sp av = avma;
10341   forprime_t S;
10342   GEN D, v;
10343   long N, k, lD, sb, p, i;
10344   if (!checkmf_i(F)) pari_err_TYPE("mfisCM", F);
10345   N = mf_get_N(F);
10346   k = mf_get_k(F); if (N < 0 || k < 0) pari_err_IMPL("mfisCM for this F");
10347   D = mfunram(N, -1);
10348   lD = lg(D);
10349   sb = maxss(mfsturmNk(N, k), 4*N);
10350   v = mfcoefs_i(F, sb, 1);
10351   u_forprime_init(&S, 2, sb);
10352   while ((p = u_forprime_next(&S)))
10353   {
10354     GEN ap = gel(v, p+1);
10355     if (!gequal0(ap))
10356       for (i = 1; i < lD; i++)
10357         if (kross(D[i], p) == -1) { D = vecsplice(D, i); lD--; }
10358   }
10359   if (lD == 1) return gc_const(av, gen_0);
10360   if (lD == 2) { set_avma(av); return stoi(D[1]); }
10361   if (k > 1) pari_err_BUG("mfisCM");
10362   return gerepileupto(av, zv_to_ZV(D));
10363 }
10364 
10365 static long
mfspace_i(GEN mf,GEN F)10366 mfspace_i(GEN mf, GEN F)
10367 {
10368   GEN v, vF, gk;
10369   long n, nE, i, l, s, N;
10370 
10371   mf = checkMF(mf); s = MF_get_space(mf);
10372   if (!F) return s;
10373   if (!checkmf_i(F)) pari_err_TYPE("mfspace",F);
10374   v = mftobasis(mf, F, 1);
10375   n = lg(v)-1; if (!n) return -1;
10376   nE = lg(MF_get_E(mf))-1;
10377   switch(s)
10378   {
10379     case mf_NEW: case mf_OLD: case mf_EISEN: return s;
10380     case mf_FULL:
10381       if (mf_get_type(F) == t_MF_THETA) return mf_EISEN;
10382       if (!gequal0(vecslice(v,1,nE)))
10383         return gequal0(vecslice(v,nE+1,n))? mf_EISEN: mf_FULL;
10384   }
10385   /* mf is mf_CUSP or mf_FULL, F a cusp form */
10386   gk = mf_get_gk(F);
10387   if (typ(gk) == t_FRAC || equali1(gk)) return mf_CUSP;
10388   vF = mftonew_i(mf, vecslice(v, nE+1, n), &N);
10389   if (N != MF_get_N(mf)) return mf_OLD;
10390   l = lg(vF);
10391   for (i = 1; i < l; i++)
10392     if (itos(gmael(vF,i,1)) != N) return mf_CUSP;
10393   return mf_NEW;
10394 }
10395 long
mfspace(GEN mf,GEN F)10396 mfspace(GEN mf, GEN F)
10397 { pari_sp av = avma; return gc_long(av, mfspace_i(mf,F)); }
10398 static GEN
lfunfindchi(GEN ldata,GEN van,long prec)10399 lfunfindchi(GEN ldata, GEN van, long prec)
10400 {
10401   GEN gN = ldata_get_conductor(ldata), gk = ldata_get_k(ldata);
10402   GEN G = znstar0(gN,1), cyc = znstar_get_conreycyc(G), L, go, vz;
10403   long N = itou(gN), odd = typ(gk) == t_INT && mpodd(gk);
10404   long i, j, o, l, B0 = 2, B = lg(van)-1, bit = 10 - prec2nbits(prec);
10405 
10406   /* if van is integral, chi must be trivial */
10407   if (typ(van) == t_VECSMALL) return mfcharGL(G, zerocol(lg(cyc)-1));
10408   L = cyc2elts(cyc); l = lg(L);
10409   for (i = j = 1; i < l; i++)
10410   {
10411     GEN chi = zc_to_ZC(gel(L,i));
10412     if (zncharisodd(G,chi) == odd) gel(L,j++) = mfcharGL(G,chi);
10413   }
10414   setlg(L,j); l = j;
10415   if (l <= 2) return gel(L,1);
10416   o = znstar_get_expo(G); go = utoi(o);
10417   vz = grootsof1(o, prec);
10418   for (;;)
10419   {
10420     long n;
10421     for (n = B0; n <= B; n++)
10422     {
10423       GEN an, r;
10424       long j;
10425       if (ugcd(n, N) != 1) continue;
10426       an = gel(van,n); if (gexpo(an) < bit) continue;
10427       r = gdiv(an, conj_i(an));
10428       for (i = 1; i < l; i++)
10429       {
10430         GEN CHI = gel(L,i);
10431         if (gexpo(gsub(r, gel(vz, znchareval_i(CHI,n,go)+1))) > bit)
10432           gel(L,i) = NULL;
10433       }
10434       for (i = j = 1; i < l; i++)
10435         if (gel(L,i)) gel(L,j++) = gel(L,i);
10436       l = j; setlg(L,l);
10437       if (l == 2) return gel(L,1);
10438     }
10439     B0 = B+1; B <<= 1;
10440     van = ldata_vecan(ldata_get_an(ldata), B, prec);
10441   }
10442 }
10443 
10444 GEN
mffromlfun(GEN L,long prec)10445 mffromlfun(GEN L, long prec)
10446 {
10447   pari_sp av = avma;
10448   GEN ldata = lfunmisc_to_ldata_shallow(L), Vga = ldata_get_gammavec(ldata);
10449   GEN van, a0, CHI, NK, gk = ldata_get_k(ldata);
10450   long N, space;
10451   if (!gequal(Vga, mkvec2(gen_0, gen_1))) pari_err_TYPE("mffromlfun", L);
10452   N = itou(ldata_get_conductor(ldata));
10453   van = ldata_vecan(ldata_get_an(ldata), mfsturmNgk(N,gk) + 2, prec);
10454   CHI = lfunfindchi(ldata, van, prec);
10455   if (typ(van) != t_VEC) van = vecsmall_to_vec_inplace(van);
10456   space = (lg(ldata) == 7)? mf_CUSP: mf_FULL;
10457   a0 = (space == mf_CUSP)? gen_0: gneg(lfun(L, gen_0, prec2nbits(prec)));
10458   NK = mkvec3(utoi(N), gk, mfchisimpl(CHI));
10459   return gerepilecopy(av, mkvec3(NK, utoi(space), shallowconcat(a0, van)));
10460 }
10461 /*******************************************************************/
10462 /*                                                                 */
10463 /*                       HALF-INTEGRAL WEIGHT                      */
10464 /*                                                                 */
10465 /*******************************************************************/
10466 /* We use the prefix mf2; k represents the weight -1/2, so e.g.
10467    k = 2 is weight 5/2. N is the level, so 4\mid N, and CHI is the
10468    character, always even. */
10469 
10470 static long
lamCO(long r,long s,long p)10471 lamCO(long r, long s, long p)
10472 {
10473   if ((s << 1) <= r)
10474   {
10475     long rp = r >> 1;
10476     if (odd(r)) return upowuu(p, rp) << 1;
10477     else return (p + 1)*upowuu(p, rp - 1);
10478   }
10479   else return upowuu(p, r - s) << 1;
10480 }
10481 
10482 static int
condC(GEN faN,GEN valF)10483 condC(GEN faN, GEN valF)
10484 {
10485   GEN P = gel(faN, 1), E = gel(faN, 2);
10486   long l = lg(P), i;
10487   for (i = 1; i < l; i++)
10488     if ((P[i] & 3L) == 3)
10489     {
10490       long r = E[i];
10491       if (odd(r) || r < (valF[i] << 1)) return 1;
10492     }
10493   return 0;
10494 }
10495 
10496 /* returns 2*zetaCO; weight is k + 1/2 */
10497 static long
zeta2CO(GEN faN,GEN valF,long r2,long s2,long k)10498 zeta2CO(GEN faN, GEN valF, long r2, long s2, long k)
10499 {
10500   if (r2 >= 4) return lamCO(r2, s2, 2) << 1;
10501   if (r2 == 3) return 6;
10502   if (condC(faN, valF)) return 4;
10503   if (odd(k)) return s2 ? 3 : 5; else return s2 ? 5: 3;
10504 }
10505 
10506 /* returns 4 times last term in formula */
10507 static long
dim22(long N,long F,long k)10508 dim22(long N, long F, long k)
10509 {
10510   pari_sp av = avma;
10511   GEN vF, faN = myfactoru(N), P = gel(faN, 1), E = gel(faN, 2);
10512   long i, D, l = lg(P);
10513   vF = cgetg(l, t_VECSMALL);
10514   for (i = 1; i < l; i++) vF[i] = u_lval(F, P[i]);
10515   D = zeta2CO(faN, vF, E[1], vF[1], k);
10516   for (i = 2; i < l; i++) D *= lamCO(E[i], vF[i], P[i]);
10517   return gc_long(av,D);
10518 }
10519 
10520 /* PSI not necessarily primitive, of conductor F */
10521 static int
charistotallyeven(GEN PSI,long F)10522 charistotallyeven(GEN PSI, long F)
10523 {
10524   pari_sp av = avma;
10525   GEN P = gel(myfactoru(F), 1);
10526   GEN G = gel(PSI,1), psi = gel(PSI,2);
10527   long i;
10528   for (i = 1; i < lg(P); i++)
10529   {
10530     GEN psip = znchardecompose(G, psi, utoipos(P[i]));
10531     if (zncharisodd(G, psip)) return gc_bool(av,0);
10532   }
10533   return gc_bool(av,1);
10534 }
10535 
10536 static GEN
get_PSI(GEN CHI,long t)10537 get_PSI(GEN CHI, long t)
10538 {
10539   long r = t & 3L, t2 = (r == 2 || r == 3) ? t << 2 : t;
10540   return mfcharmul_i(CHI, induce(gel(CHI,1), utoipos(t2)));
10541 }
10542 /* space = mf_CUSP, mf_EISEN or mf_FULL, weight k + 1/2 */
10543 static long
mf2dimwt12(long N,GEN CHI,long space)10544 mf2dimwt12(long N, GEN CHI, long space)
10545 {
10546   pari_sp av = avma;
10547   GEN D = mydivisorsu(N >> 2);
10548   long i, l = lg(D), dim3 = 0, dim4 = 0;
10549 
10550   CHI = induceN(N, CHI);
10551   for (i = 1; i < l; i++)
10552   {
10553     long rp, t = D[i], Mt = D[l-i];
10554     GEN PSI = get_PSI(CHI,t);
10555     rp = mfcharconductor(PSI);
10556     if (Mt % (rp*rp) == 0) { dim4++; if (charistotallyeven(PSI,rp)) dim3++; }
10557   }
10558   set_avma(av);
10559   switch (space)
10560   {
10561     case mf_CUSP: return dim4 - dim3;
10562     case mf_EISEN:return dim3;
10563     case mf_FULL: return dim4;
10564   }
10565   return 0; /*LCOV_EXCL_LINE*/
10566 }
10567 
10568 static long
mf2dimwt32(long N,GEN CHI,long F,long space)10569 mf2dimwt32(long N, GEN CHI, long F, long space)
10570 {
10571   long D;
10572   switch(space)
10573   {
10574     case mf_CUSP: D = mypsiu(N) - 6*dim22(N, F, 1);
10575       if (D%24) pari_err_BUG("mfdim");
10576       return D/24 + mf2dimwt12(N, CHI, 4);
10577     case mf_FULL: D = mypsiu(N) + 6*dim22(N, F, 0);
10578       if (D%24) pari_err_BUG("mfdim");
10579       return D/24 + mf2dimwt12(N, CHI, 1);
10580     case mf_EISEN: D = dim22(N, F, 0) + dim22(N, F, 1);
10581       if (D & 3L) pari_err_BUG("mfdim");
10582       return (D >> 2) - mf2dimwt12(N, CHI, 3);
10583   }
10584   return 0; /*LCOV_EXCL_LINE*/
10585 }
10586 
10587 /* F = conductor(CHI), weight k = r+1/2 */
10588 static long
checkmf2(long N,long r,GEN CHI,long F,long space)10589 checkmf2(long N, long r, GEN CHI, long F, long space)
10590 {
10591   switch(space)
10592   {
10593     case mf_FULL: case mf_CUSP: case mf_EISEN: break;
10594     case mf_NEW: case mf_OLD:
10595       pari_err_TYPE("half-integral weight [new/old spaces]", utoi(space));
10596     default:
10597       pari_err_TYPE("half-integral weight [incorrect space]",utoi(space));
10598   }
10599   if (N & 3L)
10600     pari_err_DOMAIN("half-integral weight", "N % 4", "!=", gen_0, stoi(N));
10601   return r >= 0 && mfcharparity(CHI) == 1 && N % F == 0;
10602 }
10603 
10604 /* weight k = r + 1/2 */
10605 static long
mf2dim_Nkchi(long N,long r,GEN CHI,ulong space)10606 mf2dim_Nkchi(long N, long r, GEN CHI, ulong space)
10607 {
10608   long D, D2, F = mfcharconductor(CHI);
10609   if (!checkmf2(N, r, CHI, F, space)) return 0;
10610   if (r == 0) return mf2dimwt12(N, CHI, space);
10611   if (r == 1) return mf2dimwt32(N, CHI, F, space);
10612   if (space == mf_EISEN)
10613   {
10614     D = dim22(N, F, r) + dim22(N, F, 1-r);
10615     if (D & 3L) pari_err_BUG("mfdim");
10616     return D >> 2;
10617   }
10618   D2 = space == mf_FULL? dim22(N, F, 1-r): -dim22(N, F, r);
10619   D = (2*r-1)*mypsiu(N) + 6*D2;
10620   if (D%24) pari_err_BUG("mfdim");
10621   return D/24;
10622 }
10623 
10624 /* weight k=r+1/2 */
10625 static GEN
mf2init_Nkchi(long N,long r,GEN CHI,long space,long flraw)10626 mf2init_Nkchi(long N, long r, GEN CHI, long space, long flraw)
10627 {
10628   GEN CHI1, Minv, Minvmat, B, M, gk = gaddsg(r,ghalf);
10629   GEN mf1 = mkvec4(utoi(N),gk,CHI,utoi(space));
10630   long L;
10631   if (!checkmf2(N, r, CHI, mfcharconductor(CHI), space)) return mfEMPTY(mf1);
10632   if (space==mf_EISEN) pari_err_IMPL("half-integral weight Eisenstein space");
10633   L = mfsturmNgk(N, gk) + 1;
10634   B = mf2basis(N, r, CHI, &CHI1, space);
10635   M = mflineardivtomat(N,B,L); /* defined modulo T = charpol(CHI) */
10636   if (flraw) M = mkvec3(gen_0,gen_0,M);
10637   else
10638   {
10639     long o1 = mfcharorder(CHI1), o = mfcharorder(CHI);
10640     M = mfcleanCHI(M, CHI, 0);
10641     Minv = gel(M,2);
10642     Minvmat = RgM_Minv_mul(NULL, Minv); /* mod T */
10643     if (o1 != o)
10644     {
10645       GEN tr = Qab_trace_init(o, o1, mfcharpol(CHI), mfcharpol(CHI1));
10646       Minvmat = QabM_tracerel(tr, 0, Minvmat);
10647     }
10648     /* Minvmat mod T1 = charpol(CHI1) */
10649     B = vecmflineardiv_linear(B, Minvmat);
10650     gel(M,3) = RgM_Minv_mul(gel(M,3), Minv);
10651     gel(M,2) = mkMinv(matid(lg(B)-1), NULL,NULL,NULL);
10652   }
10653   return mkmf(mf1, cgetg(1,t_VEC), B, gen_0, M);
10654 }
10655 
10656 /**************************************************************************/
10657 /*                          Kohnen + space                                */
10658 /**************************************************************************/
10659 
10660 static GEN
mfkohnenbasis_i(GEN mf,GEN CHI,long eps,long sb)10661 mfkohnenbasis_i(GEN mf, GEN CHI, long eps, long sb)
10662 {
10663   GEN M = mfcoefs_mf(mf, sb, 1), p, P;
10664   long c, i, n = mfcharorder(CHI), l = sb + 2;
10665   p = cgetg(l, t_VECSMALL);
10666   /* keep the a_n, n = (2 or 2+eps) mod 4 */
10667   for (i = 3, c = 1; i < l; i+=4) p[c++] = i;
10668   for (i = 3+eps;    i < l; i+=4) p[c++] = i;
10669   P = n <= 2? NULL: mfcharpol(CHI);
10670   setlg(p, c);
10671   return QabM_ker(rowpermute(M, p), P, n);
10672 }
10673 GEN
mfkohnenbasis(GEN mf)10674 mfkohnenbasis(GEN mf)
10675 {
10676   pari_sp av = avma;
10677   GEN gk, CHI, CHIP, K;
10678   long N4, r, eps, sb;
10679   mf = checkMF(mf);
10680   if (MF_get_space(mf) != mf_CUSP)
10681     pari_err_TYPE("mfkohnenbasis [not a cuspidal space", mf);
10682   if (!MF_get_dim(mf)) return cgetg(1, t_MAT);
10683   N4 = MF_get_N(mf) >> 2; gk = MF_get_gk(mf); CHI = MF_get_CHI(mf);
10684   if (typ(gk) == t_INT) pari_err_TYPE("mfkohnenbasis", gk);
10685   r = MF_get_r(mf);
10686   CHIP = mfcharchiliftprim(CHI, N4);
10687   eps = CHIP==CHI? 1: -1;
10688   if (odd(r)) eps = -eps;
10689   if (uissquarefree(N4))
10690   {
10691     long d = mfdim_Nkchi(N4, 2*r, mfcharpow(CHI, gen_2), mf_CUSP);
10692     sb = mfsturmNgk(N4 << 2, gk) + 1;
10693     K = mfkohnenbasis_i(mf, CHIP, eps, sb);
10694     if (lg(K) - 1 == d) return gerepilecopy(av, K);
10695   }
10696   sb = mfsturmNgk(N4 << 4, gk) + 1;
10697   K = mfkohnenbasis_i(mf, CHIP, eps, sb);
10698   return gerepilecopy(av, K);
10699 }
10700 
10701 static GEN
get_Shimura(GEN mf,GEN CHI,GEN vB,long t)10702 get_Shimura(GEN mf, GEN CHI, GEN vB, long t)
10703 {
10704   long N = MF_get_N(mf), r = MF_get_k(mf) >> 1;
10705   long i, d = MF_get_dim(mf), sb = mfsturm_mf(mf);
10706   GEN a = cgetg(d+1, t_MAT);
10707   for (i = 1; i <= d; i++)
10708   {
10709     pari_sp av = avma;
10710     GEN f = c_deflate(sb*sb, t, gel(vB,i));
10711     f = mftobasis_i(mf, RgV_shimura(f, sb, t, N, r, CHI));
10712     gel(a,i) = gerepileupto(av, f);
10713   }
10714   return a;
10715 }
10716 static long
QabM_rank(GEN M,GEN P,long n)10717 QabM_rank(GEN M, GEN P, long n)
10718 {
10719   GEN z = QabM_indexrank(M, P, n);
10720   return lg(gel(z,2))-1;
10721 }
10722 /* discard T[*i] */
10723 static void
discard_Ti(GEN T,long * i,long * lt)10724 discard_Ti(GEN T, long *i, long *lt)
10725 {
10726   long j, l = *lt-1;
10727   for (j = *i; j < l; j++) T[j] = T[j+1];
10728   (*i)--; *lt = l;
10729 }
10730 /* return [mf3, bijection, mfkohnenbasis, codeshi] */
10731 static GEN
mfkohnenbijection_i(GEN mf)10732 mfkohnenbijection_i(GEN mf)
10733 {
10734   GEN CHI = MF_get_CHI(mf), K = mfkohnenbasis(mf);
10735   GEN mres, dMi, Mi, M, C, vB, mf3, SHI, T, P;
10736   long N4 = MF_get_N(mf)>>2, r = MF_get_r(mf), dK = lg(K) - 1;
10737   long i, c, n, oldr, lt, ltold, sb3, t, limt;
10738   const long MAXlt = 100;
10739 
10740   mf3 = mfinit_Nkchi(N4, r<<1, mfcharpow(CHI,gen_2), mf_CUSP, 0);
10741   if (MF_get_dim(mf3) != dK)
10742     pari_err_BUG("mfkohnenbijection [different dimensions]");
10743   if (!dK) return mkvec4(mf3, cgetg(1, t_MAT), K, cgetg(1, t_VEC));
10744   CHI = mfcharchiliftprim(CHI, N4);
10745   n = mfcharorder(CHI);
10746   P = n<=2? NULL: mfcharpol(CHI);
10747   SHI = cgetg(MAXlt, t_COL);
10748   T = cgetg(MAXlt, t_VECSMALL);
10749   sb3 = mfsturm_mf(mf3);
10750   limt = 6; oldr = 0; vB = C = M = NULL;
10751   for (t = lt = ltold = 1; lt < MAXlt; t++)
10752   {
10753     pari_sp av;
10754     if (!uissquarefree(t)) continue;
10755     T[lt++] = t; if (t <= limt) continue;
10756     av = avma;
10757     if (vB) gunclone(vB);
10758     /* could improve the rest but 99% of running time is spent here */
10759     vB = gclone( RgM_mul(mfcoefs_mf(mf, t*sb3*sb3, 1), K) );
10760     set_avma(av);
10761     for (i = ltold; i < lt; i++)
10762     {
10763       pari_sp av;
10764       long r;
10765       M = get_Shimura(mf3, CHI, vB, T[i]);
10766       r = QabM_rank(M, P, n); if (!r) { discard_Ti(T, &i, &lt); continue; }
10767       gel(SHI, i) = M; setlg(SHI, i+1);
10768       if (r >= dK) { C = vecsmall_ei(dK, i); goto DONE; }
10769       if (i == 1) { oldr = r; continue; }
10770       av = avma; M = shallowmatconcat(SHI);
10771       r = QabM_rank(M, P, n); /* >= rank(sum C[j] SHI[j]), probably sharp */
10772       if (r >= dK)
10773       {
10774         M = RgV_sum(SHI);
10775         if (QabM_rank(M, P, n) >= dK) { C = const_vecsmall(dK, 1); goto DONE; }
10776         C = random_Flv(dK, 16);
10777         M = RgV_zc_mul(SHI, C);
10778         if (QabM_rank(M, P, n) >= dK) goto DONE;
10779       }
10780       else if (r == oldr) discard_Ti(T, &i, &lt);
10781       oldr = r; set_avma(av);
10782     }
10783     limt *= 2; ltold = lt;
10784   }
10785   pari_err_BUG("mfkohnenbijection");
10786 DONE:
10787   gunclone(vB); lt = lg(SHI);
10788   Mi = QabM_pseudoinv(M,P,n, NULL,&dMi); Mi = RgM_Rg_div(Mi,dMi);
10789   mres = cgetg(lt, t_VEC);
10790   for (i = c = 1; i < lt; i++)
10791     if (C[i]) gel(mres,c++) = mkvec2s(T[i], C[i]);
10792   setlg(mres,c); return mkvec4(mf3, Mi, K, mres);
10793 }
10794 GEN
mfkohnenbijection(GEN mf)10795 mfkohnenbijection(GEN mf)
10796 {
10797   pari_sp av = avma;
10798   long N;
10799   mf = checkMF(mf); N = MF_get_N(mf);
10800   if (!uissquarefree(N >> 2))
10801     pari_err_TYPE("mfkohnenbijection [N/4 not squarefree]", utoi(N));
10802   if (MF_get_space(mf) != mf_CUSP || MF_get_r(mf) == 0 || !mfshimura_space_cusp(mf))
10803     pari_err_TYPE("mfkohnenbijection [incorrect mf for Kohnen]", mf);
10804   return gerepilecopy(av, mfkohnenbijection_i(mf));
10805 }
10806 
10807 static int
checkbij_i(GEN b)10808 checkbij_i(GEN b)
10809 {
10810   return typ(b) == t_VEC && lg(b) == 5 && checkMF_i(gel(b,1))
10811          && typ(gel(b,2)) == t_MAT
10812          && typ(gel(b,3)) == t_MAT
10813          && typ(gel(b,4)) == t_VEC;
10814 }
10815 
10816 /* bij is the output of mfkohnenbijection */
10817 GEN
mfkohneneigenbasis(GEN mf,GEN bij)10818 mfkohneneigenbasis(GEN mf, GEN bij)
10819 {
10820   pari_sp av = avma;
10821   GEN mf3, mf30, B, KM, M, k;
10822   long r, i, l, N4;
10823   mf = checkMF(mf);
10824   if (!checkbij_i(bij))
10825     pari_err_TYPE("mfkohneneigenbasis [bijection]", bij);
10826   if (MF_get_space(mf) != mf_CUSP)
10827     pari_err_TYPE("mfkohneneigenbasis [not a cuspidal space]", mf);
10828   if (!MF_get_dim(mf))
10829     retmkvec3(cgetg(1, t_VEC), cgetg(1, t_VEC), cgetg(1, t_VEC));
10830   N4 = MF_get_N(mf) >> 2; k = MF_get_gk(mf);
10831   if (typ(k) == t_INT) pari_err_TYPE("mfkohneneigenbasis", k);
10832   if (!uissquarefree(N4))
10833     pari_err_TYPE("mfkohneneigenbasis [N not squarefree]", utoipos(N4));
10834   r = MF_get_r(mf);
10835   KM = RgM_mul(gel(bij,3), gel(bij,2));
10836   mf3 = gel(bij,1);
10837   mf30 = mfinit_Nkchi(N4, 2*r, MF_get_CHI(mf3), mf_NEW, 0);
10838   B = mfcoefs_mf(mf30, mfsturm_mf(mf3), 1); l = lg(B);
10839   M = cgetg(l, t_MAT);
10840   for (i=1; i<l; i++) gel(M,i) = RgM_RgC_mul(KM, mftobasis_i(mf3, gel(B,i)));
10841   return gerepilecopy(av, mkvec3(mf30, M, RgM_mul(M, MF_get_newforms(mf30))));
10842 }
10843 /*************************** End Kohnen ************************************/
10844 /***************************************************************************/
10845 
10846 static GEN desc(GEN F);
10847 static GEN
desc_mfeisen(GEN F)10848 desc_mfeisen(GEN F)
10849 {
10850   GEN R, gk = mf_get_gk(F);
10851   if (typ(gk) == t_FRAC)
10852     R = gsprintf("H_{%Ps}", gk);
10853   else
10854   {
10855     GEN vchi = gel(F, 2), CHI = mfchisimpl(gel(vchi, 3));
10856     long k = itou(gk);
10857     if (lg(vchi) < 5) R = gsprintf("F_%ld(%Ps)", k, CHI);
10858     else
10859     {
10860       GEN CHI2 = mfchisimpl(gel(vchi, 4));
10861       R = gsprintf("F_%ld(%Ps, %Ps)", k, CHI, CHI2);
10862     }
10863   }
10864   return R;
10865 }
10866 static GEN
desc_hecke(GEN F)10867 desc_hecke(GEN F)
10868 {
10869   long n, N;
10870   GEN D = gel(F,2);
10871   if (typ(D) == t_VECSMALL) { N = D[3]; n = D[1]; }
10872   else { GEN nN = gel(D,2); n = nN[1]; N = nN[2]; } /* half integer */
10873   return gsprintf("T_%ld(%ld)(%Ps)", N, n, desc(gel(F,3)));
10874 }
10875 static GEN
desc_linear(GEN FLD,GEN dL)10876 desc_linear(GEN FLD, GEN dL)
10877 {
10878   GEN F = gel(FLD,2), L = gel(FLD,3), R = strtoGENstr("LIN([");
10879   long n = lg(F) - 1, i;
10880   for (i = 1; i <= n; i++)
10881   {
10882     R = shallowconcat(R, desc(gel(F,i))); if (i == n) break;
10883     R = shallowconcat(R, strtoGENstr(", "));
10884   }
10885   return shallowconcat(R, gsprintf("], %Ps)", gdiv(L, dL)));
10886 }
10887 static GEN
desc_dihedral(GEN F)10888 desc_dihedral(GEN F)
10889 {
10890   GEN bnr = gel(F,2), D = nf_get_disc(bnr_get_nf(bnr)), f = bnr_get_mod(bnr);
10891   GEN cyc = bnr_get_cyc(bnr);
10892   GEN w = gel(F,3), chin = zv_to_ZV(gel(w,2)), o = utoi(gel(w,1)[1]);
10893   GEN chi = char_denormalize(cyc, o, chin);
10894   if (lg(gel(f,2)) == 1) f = gel(f,1);
10895   return gsprintf("DIH(%Ps, %Ps, %Ps, %Ps)",D,f,cyc,chi);
10896 }
10897 
10898 static void
unpack0(GEN * U)10899 unpack0(GEN *U)
10900 { if (U) *U = mkvec2(cgetg(1, t_VEC), cgetg(1, t_VEC)); }
10901 static void
unpack2(GEN F,GEN * U)10902 unpack2(GEN F, GEN *U)
10903 { if (U) *U = mkvec2(mkvec2(gel(F,2), gel(F,3)), cgetg(1, t_VEC)); }
10904 static void
unpack23(GEN F,GEN * U)10905 unpack23(GEN F, GEN *U)
10906 { if (U) *U = mkvec2(mkvec(gel(F,2)), mkvec(gel(F,3))); }
10907 static GEN
desc_i(GEN F,GEN * U)10908 desc_i(GEN F, GEN *U)
10909 {
10910   switch(mf_get_type(F))
10911   {
10912     case t_MF_CONST: unpack0(U); return gsprintf("CONST(%Ps)", gel(F,2));
10913     case t_MF_EISEN: unpack0(U); return desc_mfeisen(F);
10914     case t_MF_Ek: unpack0(U); return gsprintf("E_%ld", mf_get_k(F));
10915     case t_MF_DELTA: unpack0(U); return gsprintf("DELTA");
10916     case t_MF_THETA: unpack0(U);
10917       return gsprintf("THETA(%Ps)", mfchisimpl(gel(F,2)));
10918     case t_MF_ETAQUO: unpack0(U);
10919       return gsprintf("ETAQUO(%Ps, %Ps)", gel(F,2), gel(F,3));
10920     case t_MF_ELL: unpack0(U);
10921       return gsprintf("ELL(%Ps)", vecslice(gel(F,2), 1, 5));
10922     case t_MF_TRACE: unpack0(U); return gsprintf("TR(%Ps)", mfparams(F));
10923     case t_MF_NEWTRACE: unpack0(U); return gsprintf("TR^new(%Ps)", mfparams(F));
10924     case t_MF_DIHEDRAL: unpack0(U); return desc_dihedral(F);
10925     case t_MF_MUL: unpack2(F, U);
10926       return gsprintf("MUL(%Ps, %Ps)", desc(gel(F,2)), desc(gel(F,3)));
10927     case t_MF_DIV: unpack2(F, U);
10928       return gsprintf("DIV(%Ps, %Ps)", desc(gel(F,2)), desc(gel(F,3)));
10929     case t_MF_POW: unpack23(F, U);
10930       return gsprintf("POW(%Ps, %ld)", desc(gel(F,2)), itos(gel(F,3)));
10931     case t_MF_SHIFT: unpack23(F, U);
10932       return gsprintf("SHIFT(%Ps, %ld)", desc(gel(F,2)), itos(gel(F,3)));
10933     case t_MF_DERIV: unpack23(F, U);
10934       return gsprintf("DER^%ld(%Ps)", itos(gel(F,3)), desc(gel(F,2)));
10935     case t_MF_DERIVE2: unpack23(F, U);
10936       return gsprintf("DERE2^%ld(%Ps)", itos(gel(F,3)), desc(gel(F,2)));
10937     case t_MF_TWIST: unpack23(F, U);
10938       return gsprintf("TWIST(%Ps, %Ps)", desc(gel(F,2)), gel(F,3));
10939     case t_MF_BD: unpack23(F, U);
10940       return gsprintf("B(%ld)(%Ps)", itou(gel(F,3)), desc(gel(F,2)));
10941     case t_MF_BRACKET:
10942       if (U) *U = mkvec2(mkvec2(gel(F,2), gel(F,3)), mkvec(gel(F,4)));
10943       return gsprintf("MULRC_%ld(%Ps, %Ps)", itos(gel(F,4)), desc(gel(F,2)), desc(gel(F,3)));
10944     case t_MF_LINEAR_BHN:
10945     case t_MF_LINEAR:
10946       if (U) *U = mkvec2(gel(F,2), mkvec(gdiv(gel(F,3), gel(F,4))));
10947       return desc_linear(F,gel(F,4));
10948     case t_MF_HECKE:
10949       if (U) *U = mkvec2(mkvec(gel(F,3)), mkvec(stoi(gel(F,2)[1])));
10950       return desc_hecke(F);
10951     default: pari_err_TYPE("mfdescribe",F);
10952     return NULL;/*LCOV_EXCL_LINE*/
10953   }
10954 }
10955 static GEN
desc(GEN F)10956 desc(GEN F) { return desc_i(F, NULL); }
10957 GEN
mfdescribe(GEN F,GEN * U)10958 mfdescribe(GEN F, GEN *U)
10959 {
10960   pari_sp av = avma;
10961   GEN mf;
10962   if ((mf = checkMF_i(F)))
10963   {
10964     const char *f = NULL;
10965     switch (MF_get_space(mf))
10966     {
10967       case mf_NEW:  f = "S_%Ps^new(G_0(%ld, %Ps))"; break;
10968       case mf_CUSP: f = "S_%Ps(G_0(%ld, %Ps))"; break;
10969       case mf_OLD:  f = "S_%Ps^old(G_0(%ld, %Ps))"; break;
10970       case mf_EISEN:f = "E_%Ps(G_0(%ld, %Ps))"; break;
10971       case mf_FULL: f = "M_%Ps(G_0(%ld, %Ps))"; break;
10972     }
10973     if (U) *U = cgetg(1, t_VEC);
10974     return gsprintf(f, MF_get_gk(mf), MF_get_N(mf), mfchisimpl(MF_get_CHI(mf)));
10975   }
10976   if (!checkmf_i(F)) pari_err_TYPE("mfdescribe", F);
10977   F = desc_i(F, U);
10978   gerepileall(av, U ? 2: 1, &F, U);
10979   return F;
10980 }
10981 
10982 /***********************************************************************/
10983 /*               Eisenstein series H_r of weight r+1/2                 */
10984 /***********************************************************************/
10985 /* radical(u_ppo(g,q)) */
10986 static long
u_pporad(long g,long q)10987 u_pporad(long g, long q)
10988 {
10989   GEN F = myfactoru(g), P = gel(F,1);
10990   long i, l, n;
10991   if (q == 1) return zv_prod(P);
10992   l = lg(P);
10993   for (i = n = 1; i < l; i++)
10994   {
10995     long p = P[i];
10996     if (q % p) n *= p;
10997   }
10998   return n;
10999 }
11000 static void
c_F2TH4(long n,GEN * pF2,GEN * pTH4)11001 c_F2TH4(long n, GEN *pF2, GEN *pTH4)
11002 {
11003   GEN v = mfcoefs_i(mfEk(2), n, 1), v2 = bdexpand(v,2), v4 = bdexpand(v,4);
11004   GEN F2 = gdivgs(ZC_add(ZC_sub(v, ZC_z_mul(v2,3)), ZC_z_mul(v4,2)), -24);
11005   GEN TH4 = gdivgs(ZC_sub(v, ZC_z_mul(v4,4)), -3);
11006   settyp(F2,t_VEC); *pF2 = F2;
11007   settyp(TH4,t_VEC);*pTH4= TH4;
11008 }
11009 /* r > 0, N >= 0 */
11010 static GEN
mfEHcoef(long r,long N)11011 mfEHcoef(long r, long N)
11012 {
11013   long D0, f, i, l;
11014   GEN S, Df;
11015 
11016   if (r == 1) return hclassno(utoi(N));
11017   if (N == 0) return gdivgs(bernfrac(2*r), -2*r);
11018   if (r&1L)
11019   {
11020     long s = N&3L; if (s == 2 || s == 1) return gen_0;
11021     D0 = mycoredisc2neg(N,&f);
11022   }
11023   else
11024   {
11025     long s = N&3L; if (s == 2 || s == 3) return gen_0;
11026     D0 = mycoredisc2pos(N,&f);
11027   }
11028   Df = mydivisorsu(u_pporad(f, D0)); l = lg(Df);
11029   S = gen_0;
11030   for (i = 1; i < l; i++)
11031   {
11032     long d = Df[i], s = mymoebiusu(d)*kross(D0, d); /* != 0 */
11033     GEN c = gmul(powuu(d, r-1), mysumdivku(f/d, 2*r-1));
11034     S = s > 0? addii(S, c): subii(S, c);
11035   }
11036   return gmul(lfunquadneg_naive(D0, r), S);
11037 }
11038 static GEN
mfEHmat(long lim,long r)11039 mfEHmat(long lim, long r)
11040 {
11041   long j, l, d = r/2;
11042   GEN f2, th4, th3, v, vth4, vf2;
11043   c_F2TH4(lim, &f2, &th4);
11044   f2 =  RgV_to_ser(f2, 0, lim+3);
11045   th4 = RgV_to_ser(th4, 0, lim+3);
11046   th3 = RgV_to_ser(c_theta(lim, 1, mfchartrivial()), 0, lim+3);
11047   if (odd(r)) th3 = gpowgs(th3, 3);
11048   vth4 = gpowers(th4, d);
11049   vf2 = gpowers0(f2, d, th3); /* th3 f2^j */
11050   l = d+2; v = cgetg(l, t_VEC);
11051   for (j = 1; j < l; j++)
11052     gel(v, j) = ser2rfrac_i(gmul(gel(vth4, l-j), gel(vf2, j)));
11053   return RgXV_to_RgM(v, lim);
11054 }
11055 static GEN
Hfind(long r,GEN * pden)11056 Hfind(long r, GEN *pden)
11057 {
11058   long lim = (r/2)+3, i;
11059   GEN res, M, B;
11060 
11061   if (r <= 0) pari_err_DOMAIN("mfEH", "r", "<=", gen_0, stoi(r));
11062   M = mfEHmat(lim, r);
11063   B = cgetg(lim+1, t_COL);
11064   for (i = 1; i <= lim; i++) gel(B, i) = mfEHcoef(r, i-1);
11065   res = QM_gauss(M, B);
11066   if (lg(res) == 1) pari_err_BUG("mfEH");
11067   return Q_remove_denom(res,pden);
11068 }
11069 GEN
mfEH(GEN gk)11070 mfEH(GEN gk)
11071 {
11072   pari_sp av = avma;
11073   GEN v, d, NK, gr = gsub(gk, ghalf);
11074   long r;
11075   if (typ(gr) != t_INT) pari_err_TYPE("mfEH", gk);
11076   r = itos(gr);
11077   switch (r)
11078   {
11079     case 1: v=cgetg(1,t_VEC); d=gen_1; break;
11080     case 2: v=mkvec2s(1,-20); d=utoipos(120); break;
11081     case 3: v=mkvec2s(-1,14); d=utoipos(252); break;
11082     case 4: v=mkvec3s(1,-16,16); d=utoipos(240); break;
11083     case 5: v=mkvec3s(-1,22,-88); d=utoipos(132); break;
11084     case 6: v=mkvec4s(691,-18096,110136,-4160); d=utoipos(32760); break;
11085     case 7: v=mkvec4s(-1,30,-240,224); d=utoipos(12); break;
11086     default: v = Hfind(r, &d); break;
11087   }
11088   NK = mkgNK(utoipos(4), gaddgs(ghalf,r), mfchartrivial(), pol_x(1));
11089   return gerepilecopy(av, tag(t_MF_EISEN, NK, mkvec2(v,d)));
11090 }
11091 
11092 /**********************************************************/
11093 /*             T(f^2) for half-integral weight            */
11094 /**********************************************************/
11095 
11096 /* T_p^2 V, p2 = p^2, c1 = chi(p) (-1/p)^r p^(r-1), c2 = chi(p^2)*p^(2r-1) */
11097 static GEN
tp2apply(GEN V,long p,long p2,GEN c1,GEN c2)11098 tp2apply(GEN V, long p, long p2, GEN c1, GEN c2)
11099 {
11100   long lw = (lg(V) - 2)/p2 + 1, m, n;
11101   GEN a0 = gel(V,1), W = cgetg(lw + 1, t_VEC);
11102 
11103   gel(W,1) = gequal0(a0)? gen_0: gmul(a0, gaddsg(1, c2));
11104   for (n = 1; n < lw; n++)
11105   {
11106     GEN c = gel(V, p2*n + 1);
11107     if (n%p) c = gadd(c, gmulsg(kross(n,p), gmul(gel(V,n+1), c1)));
11108     gel(W, n+1) = c; /* a(p^2*n) + c1 * (n/p) a(n) */
11109   }
11110   for (m = 1, n = p2; n < lw; m++, n += p2)
11111     gel(W, n+1) = gadd(gel(W,n+1), gmul(gel(V,m+1), c2));
11112   return W;
11113 }
11114 
11115 /* T_{p^{2e}} V; can derecursify [Purkait, Hecke operators in half-integral
11116  * weight, Prop 4.3], not worth it */
11117 static GEN
tp2eapply(GEN V,long p,long p2,long e,GEN q,GEN c1,GEN c2)11118 tp2eapply(GEN V, long p, long p2, long e, GEN q, GEN c1, GEN c2)
11119 {
11120   GEN V4 = NULL;
11121   if (e > 1)
11122   {
11123     V4 = vecslice(V, 1, (lg(V) - 2)/(p2*p2) + 1);
11124     V = tp2eapply(V, p, p2, e-1, q, c1, c2);
11125   }
11126   V = tp2apply(V, p, p2, c1, c2);
11127   if (e > 1)
11128     V = gsub(V, (e == 2)? gmul(q, V4)
11129                         : gmul(c2, tp2eapply(V4, p, p2, e-2, q, c1, c2)));
11130   return V;
11131 }
11132 /* weight k = r+1/2 */
11133 static GEN
RgV_heckef2(long n,long d,GEN V,GEN F,GEN DATA)11134 RgV_heckef2(long n, long d, GEN V, GEN F, GEN DATA)
11135 {
11136   GEN CHI = mf_get_CHI(F), fa = gel(DATA,1), P = gel(fa,1), E = gel(fa,2);
11137   long i, l = lg(P), r = mf_get_r(F), s4 = odd(r)? -4: 4, k2m2 = (r<<1)-1;
11138   if (typ(V) == t_COL) V = shallowtrans(V);
11139   for (i = 1; i < l; i++)
11140   { /* p does not divide N */
11141     long p = P[i], e = E[i], p2 = p*p;
11142     GEN c1, c2, a, b, q = NULL, C = mfchareval(CHI,p), C2 = gsqr(C);
11143     a = r? powuu(p,r-1): mkfrac(gen_1,utoipos(p)); /* p^(r-1) = p^(k-3/2) */
11144     b = r? mulii(powuu(p,r), a): a; /* p^(2r-1) = p^(2k-2) */
11145     c1 = gmul(C, gmulsg(kross(s4,p),a));
11146     c2 = gmul(C2, b);
11147     if (e > 1)
11148     {
11149       q = r? powuu(p,k2m2): a;
11150       if (e == 2) q = gmul(q, sstoQ(p+1,p)); /* special case T_{p^4} */
11151       q = gmul(C2, q); /* chi(p^2) [ p^(2k-2) or (p+1)p^(2k-3) ] */
11152     }
11153     V = tp2eapply(V, p, p2, e, q, c1, c2);
11154   }
11155   return c_deflate(n, d, V);
11156 }
11157 
11158 static GEN
GL2toSL2(GEN g,GEN * abd)11159 GL2toSL2(GEN g, GEN *abd)
11160 {
11161   GEN A, B, C, D, u, v, a, b, d, q;
11162   g = Q_primpart(g);
11163   if (!check_M2Z(g)) pari_err_TYPE("GL2toSL2", g);
11164   A = gcoeff(g,1,1); B = gcoeff(g,1,2);
11165   C = gcoeff(g,2,1); D = gcoeff(g,2,2);
11166   a = bezout(A, C, &u, &v);
11167   if (!equali1(a)) { A = diviiexact(A,a); C = diviiexact(C,a); }
11168   d = subii(mulii(A,D), mulii(B,C));
11169   if (signe(d) <= 0) pari_err_TYPE("GL2toSL2",g);
11170   q = dvmdii(addii(mulii(u,B), mulii(v,D)), d, &b);
11171   *abd = (equali1(a) && equali1(d))? NULL: mkvec3(a, b, d);
11172   return mkmat22(A, subii(mulii(q,A), v), C, addii(mulii(q,C), u));
11173 }
11174 
11175 static GEN
Rg_approx(GEN t,long bit)11176 Rg_approx(GEN t, long bit)
11177 {
11178   GEN a = real_i(t), b = imag_i(t);
11179   long e1 = gexpo(a), e2 = gexpo(b);
11180   if (e2 < -bit) { t = e1 < -bit? gen_0: a; }
11181   else if (e1 < -bit) t = gmul(b, gen_I());
11182   return t;
11183 }
11184 static GEN
RgV_approx(GEN v,long bit)11185 RgV_approx(GEN v, long bit)
11186 {
11187   long i, l = lg(v);
11188   GEN w = cgetg_copy(v, &l);
11189   for (i = 1; i < lg(v); i++) gel(w,i) = Rg_approx(gel(v,i), bit);
11190   return w;
11191 }
11192 /* m != 2 (mod 4), D t_INT; V has "denominator" D, recognize in Q(zeta_m) */
11193 static GEN
bestapprnf2(GEN V,long m,GEN D,long prec)11194 bestapprnf2(GEN V, long m, GEN D, long prec)
11195 {
11196   long i, j, f, vt = fetch_user_var("t"), bit = prec2nbits_mul(prec, 0.8);
11197   GEN Tinit, Vl, H, Pf, P = polcyclo(m, vt);
11198 
11199   V = liftpol_shallow(V);
11200   V = gmul(RgV_approx(V, bit), D);
11201   V = bestapprnf(V, P, NULL, prec);
11202   Vl = liftpol_shallow(V);
11203   H = coprimes_zv(m);
11204   for (i = 2; i < m; i++)
11205   {
11206     if (H[i] != 1) continue;
11207     if (!gequal(Vl, vecGalois(Vl, i, P))) H[i] = 0;
11208     else for (j = i; j < m; j *= i) H[i] = 3;
11209   }
11210   f = znstar_conductor_bits(Flv_to_F2v(H));
11211   if (f == 1) return gdiv(V, D);
11212   if (f == m) return gmodulo(gdiv(V, D), P);
11213   Pf = polcyclo(f, vt);
11214   Tinit = Qab_trace_init(m, f, P, Pf);
11215   Vl = QabV_tracerel(Tinit, 0, Vl);
11216   return gmodulo(gdiv(Vl, muliu(D, degpol(P)/degpol(Pf))), Pf);
11217 }
11218 
11219 /* f | ga expansion; [f, mf_eisendec(f)]~ allowed */
11220 GEN
mfslashexpansion(GEN mf,GEN f,GEN ga,long n,long flrat,GEN * params,long prec)11221 mfslashexpansion(GEN mf, GEN f, GEN ga, long n, long flrat, GEN *params, long prec)
11222 {
11223   pari_sp av = avma;
11224   GEN a, b, d, res, al, V, M, ad, abd, gk, A, awd = NULL;
11225   long i, w;
11226 
11227   mf = checkMF(mf);
11228   gk = MF_get_gk(mf);
11229   M = GL2toSL2(ga, &abd);
11230   if (abd) { a = gel(abd,1); b = gel(abd,2); d = gel(abd,3); }
11231   else { a = d = gen_1; b = gen_0; }
11232   ad = gdiv(a,d);
11233   res = mfgaexpansion(mf, f, M, n, prec);
11234   al = gel(res,1);
11235   w = itou(gel(res,2));
11236   V = gel(res,3);
11237   if (flrat)
11238   {
11239     GEN CHI = MF_get_CHI(mf);
11240     long N = MF_get_N(mf), F = mfcharconductor(CHI);
11241     long ord = mfcharorder(CHI), k, deg;
11242     long B = umodiu(gcoeff(M,1,2), N);
11243     long C = umodiu(gcoeff(M,2,1), N);
11244     long D = umodiu(gcoeff(M,2,2), N);
11245     long CD = (C * D) % N, BC = (B * C) % F;
11246     GEN CV, t;
11247     /* weight of f * Theta in 1/2-integral weight */
11248     k = typ(gk) == t_INT? (long) itou(gk): MF_get_r(mf)+1;
11249     CV = odd(k) ? powuu(N, k - 1) : powuu(N, k >> 1);
11250     deg = ulcm(ulcm(ord, N/ugcd(N,CD)), F/ugcd(F,BC));
11251     if ((deg & 3) == 2) deg >>= 1;
11252     if (typ(gk) != t_INT && odd(deg) && mfthetaI(C,D)) deg <<= 2;
11253     V = bestapprnf2(V, deg, CV, prec);
11254     if (abd && !signe(b))
11255     { /* can [a,0; 0,d] be simplified to id ? */
11256       long nk, dk; Qtoss(gk, &nk, &dk);
11257       if (ispower(ad, utoipos(2*dk), &t)) /* t^(2*dk) = a/d or t = NULL */
11258       {
11259         V = RgV_Rg_mul(V, powiu(t,nk));
11260         awd = gdiv(a, muliu(d,w));
11261       }
11262     }
11263   }
11264   else if (abd)
11265   { /* ga = M * [a,b;0,d] * rational, F := f | M = q^al * \sum V[j] q^(j/w) */
11266     GEN u, t = NULL, wd = muliu(d,w);
11267     /* a > 0, 0 <= b < d; f | ga = (a/d)^(k/2) * F(tau + b/d) */
11268     if (signe(b))
11269     {
11270       long ns, ds;
11271       GEN z;
11272       Qtoss(gdiv(b, wd), &ns, &ds); z = rootsof1powinit(ns, ds, prec);
11273       for (i = 1; i <= n+1; i++) gel(V,i) = gmul(gel(V,i), rootsof1pow(z, i-1));
11274       if (!gequal0(al)) t = gexp(gmul(PiI2(prec), gmul(al, gdiv(b,d))), prec);
11275     }
11276     awd = gdiv(a, wd);
11277     u = gpow(ad, gmul2n(gk,-1), prec);
11278     t = t? gmul(t, u): u;
11279     V = RgV_Rg_mul(V, t);
11280   }
11281   if (!awd) A = mkmat22(a, b, gen_0, d);
11282   else
11283   { /* rescale and update w from [a,0; 0,d] */
11284     long ns;
11285     Qtoss(awd, &ns, &w); /* update w */
11286     V = bdexpand(V, ns);
11287     if (!gequal0(al))
11288     {
11289       GEN adal = gmul(ad, al), sh = gfloor(adal);
11290       al = gsub(adal, sh);
11291       V = RgV_shift(V, sh);
11292     }
11293     A = matid(2);
11294   }
11295   if (params) *params = mkvec3(al, utoipos(w), A);
11296   gerepileall(av,params?2:1,&V,params); return V;
11297 }
11298 
11299 /**************************************************************/
11300 /*         Alternative method for 1/2-integral weight         */
11301 /**************************************************************/
11302 static GEN
mf2basis(long N,long r,GEN CHI,GEN * pCHI1,long space)11303 mf2basis(long N, long r, GEN CHI, GEN *pCHI1, long space)
11304 {
11305   GEN CHI1, CHI2, mf1, mf2, B1, B2, BT, M1, M2, M, M2I, T, Th, v, den;
11306   long sb, N2, o1, o2, k1 = r + 1;
11307 
11308   if (odd(k1))
11309   {
11310     CHI1 = mfcharmul(CHI, get_mfchar(stoi(-4)));
11311     CHI2 = mfcharmul(CHI, get_mfchar(stoi(-8)));
11312   }
11313   else
11314   {
11315     CHI1 = CHI;
11316     CHI2 = mfcharmul(CHI, get_mfchar(utoi(8)));
11317   }
11318   mf1 = mfinit_Nkchi(N, k1, CHI1, space, 1);
11319   if (pCHI1) *pCHI1 = CHI1;
11320   B1 = MF_get_basis(mf1); if (lg(B1) == 1) return cgetg(1,t_VEC);
11321   N2 = ulcm(8, N);
11322   mf2 = mfinit_Nkchi(N2, k1, CHI2, space, 1);
11323   B2 = MF_get_basis(mf2); if (lg(B2) == 1) return cgetg(1,t_VEC);
11324   sb = mfsturmNgk(N2, gaddsg(k1, ghalf));
11325   M1 = mfcoefs_mf(mf1, sb, 1);
11326   M2 = mfcoefs_mf(mf2, sb, 1);
11327   Th = mfTheta(NULL);
11328   BT = mfcoefs_i(Th, sb, 1);
11329   M1 = mfmatsermul(M1, RgV_to_RgX(expandbd(BT,2),0));
11330   M2 = mfmatsermul(M2, RgV_to_RgX(BT,0));
11331   o1= mfcharorder(CHI1);
11332   T = (o1 <= 2)? NULL: mfcharpol(CHI1);
11333   if (o1 > 2) M1 = liftpol_shallow(M1);
11334   o2= mfcharorder(CHI2);
11335   if (T)
11336   {
11337     if (o2 == o1) M2 = liftpol_shallow(M2);
11338     else
11339     {
11340       GEN tr = Qab_trace_init(o2, o1, mfcharpol(CHI2), mfcharpol(CHI1));
11341       M2 = QabM_tracerel(tr, 0, M2);
11342     }
11343   }
11344   /* now everything is defined mod T = mfcharpol(CHI1) */
11345   M2I = QabM_pseudoinv_i(M2, T, o1, &v, &den);
11346   M = RgM_mul(M2I, rowpermute(M1, gel(v,1)));
11347   M = RgM_mul(M2, M);
11348   M1 = RgM_Rg_mul(M1, den);
11349   M = RgM_sub(M1, M); if (T) M = RgXQM_red(M, T);
11350   return vecmflineardiv0(B1, QabM_ker(M, T, o1), Th);
11351 }
11352 
11353 /*******************************************************************/
11354 /*                         Integration                             */
11355 /*******************************************************************/
11356 static GEN
vanembed(GEN F,GEN v,long prec)11357 vanembed(GEN F, GEN v, long prec)
11358 {
11359   GEN CHI = mf_get_CHI(F);
11360   long o = mfcharorder(CHI);
11361   if (o > 2 || degpol(mf_get_field(F)) > 1) v = liftpol_shallow(v);
11362   if (o > 2) v = gsubst(v, varn(mfcharpol(CHI)), rootsof1u_cx(o, prec));
11363   return v;
11364 }
11365 
11366 static long
mfperiod_prelim_double(double t0,long k,long bitprec)11367 mfperiod_prelim_double(double t0, long k, long bitprec)
11368 {
11369   double nlim, c = 2*M_PI*t0;
11370   nlim = ceil(bitprec * M_LN2 / c);
11371   c -= (k - 1)/(2*nlim); if (c < 1) c = 1.;
11372   nlim += ceil((0.7 + (k-1)/2*log(nlim))/c);
11373   return (long)nlim;
11374 }
11375 static long
mfperiod_prelim(GEN t0,long k,long bitprec)11376 mfperiod_prelim(GEN t0, long k, long bitprec)
11377 { return mfperiod_prelim_double(gtodouble(t0), k, bitprec); }
11378 
11379 /* (-X)^(k-2) * P(-1/X) = (-1)^{k-2} P|_{k-2} S */
11380 static GEN
RgX_act_S(GEN P,long k)11381 RgX_act_S(GEN P, long k)
11382 {
11383   P = RgX_unscale(RgX_recipspec_shallow(P+2, lgpol(P), k-1), gen_m1);
11384   setvarn(P,0); return P;
11385 }
11386 static int
RgX_act_typ(GEN P,long k)11387 RgX_act_typ(GEN P, long k)
11388 {
11389   switch(typ(P))
11390   {
11391     case t_RFRAC: return t_RFRAC;
11392     case t_POL:
11393       if (varn(P) == 0)
11394       {
11395         long d = degpol(P);
11396         if (d > k-2) return t_RFRAC;
11397         if (d) return t_POL;
11398       }
11399   }
11400   return 0;
11401 }
11402 static GEN
act_S(GEN P,long k)11403 act_S(GEN P, long k)
11404 {
11405   GEN X;
11406   switch(RgX_act_typ(P, k))
11407   {
11408     case t_RFRAC:
11409       X = gneg(pol_x(0));
11410       return gmul(gsubst(P, 0, ginv(X)), gpowgs(X, k - 2));
11411     case t_POL: return RgX_act_S(P, k);
11412   }
11413   return P;
11414 }
11415 
11416 static GEN
AX_B(GEN M)11417 AX_B(GEN M)
11418 { GEN A = gcoeff(M,1,1), B = gcoeff(M,1,2); return deg1pol_shallow(A,B,0); }
11419 static GEN
CX_D(GEN M)11420 CX_D(GEN M)
11421 { GEN C = gcoeff(M,2,1), D = gcoeff(M,2,2); return deg1pol_shallow(C,D,0); }
11422 
11423 /* P|_{2-k}M = (CX+D)^{k-2}P((AX+B)/(CX+D)) */
11424 static GEN
RgX_act_gen(GEN P,GEN M,long k)11425 RgX_act_gen(GEN P, GEN M, long k)
11426 {
11427   GEN S = gen_0, PCD, PAB;
11428   long i;
11429   PCD = gpowers(CX_D(M), k-2);
11430   PAB = gpowers(AX_B(M), k-2);
11431   for (i = 0; i <= k-2; i++)
11432   {
11433     GEN t = RgX_coeff(P, i);
11434     if (!gequal0(t)) S = gadd(S, gmul(t, gmul(gel(PCD, k-i-1), gel(PAB, i+1))));
11435   }
11436   return S;
11437 }
11438 static GEN
act_GL2(GEN P,GEN M,long k)11439 act_GL2(GEN P, GEN M, long k)
11440 {
11441   switch(RgX_act_typ(P, k))
11442   {
11443     case t_RFRAC:
11444     {
11445       GEN AB = AX_B(M), CD = CX_D(M);
11446       return gmul(gsubst(P, 0, gdiv(AB, CD)), gpowgs(CD, k - 2));
11447     }
11448     case t_POL: return RgX_act_gen(P, M, k);
11449   }
11450   return P;
11451 }
11452 
11453 static GEN
normalizeapprox(GEN R,long bit)11454 normalizeapprox(GEN R, long bit)
11455 {
11456   GEN X = gen_1, Q;
11457   long i, l;
11458   if (is_vec_t(typ(R)))
11459   {
11460     Q = cgetg_copy(R, &l);
11461     for (i = 1; i < l; i++)
11462     {
11463       pari_sp av = avma;
11464       gel(Q,i) = gerepileupto(av, normalizeapprox(gel(R,i), bit));
11465     }
11466     return Q;
11467   }
11468   if (typ(R) == t_RFRAC && varn(gel(R,2)) == 0) { X = gel(R,2); R = gel(R,1); }
11469   if (typ(R) != t_POL || varn(R) != 0) return gdiv(R, X);
11470   Q = cgetg_copy(R, &l); Q[1] = R[1];
11471   for (i = 2; i < l; ++i) gel(Q,i) = Rg_approx(gel(R,i),bit);
11472   Q = normalizepol_lg(Q,l); return gdiv(Q, X);
11473 }
11474 
11475 /* make sure T is a t_POL in variable 0 */
11476 static GEN
toRgX0(GEN T)11477 toRgX0(GEN T)
11478 { return typ(T) == t_POL && varn(T) == 0? T: scalarpol_shallow(T,0); }
11479 
11480 /* integrate by summing  nlim+1 terms of van [may be < lg(van)]
11481  * van can be an expansion with vector coefficients
11482  * \int_A^oo \sum_n van[n] * q^(n/w + al) * P(z-A) dz, q = e(z) */
11483 static GEN
intAoo(GEN van,long nlim,GEN al,long w,GEN P,GEN A,long k,long prec)11484 intAoo(GEN van, long nlim, GEN al, long w, GEN P, GEN A, long k, long prec)
11485 {
11486   GEN alw, P1, piI2A, q, S, van0;
11487   long n, vz = varn(gel(P,2));
11488 
11489   if (nlim < 1) nlim = 1;
11490   alw = gmulsg(w, al);
11491   P1 = RgX_translate(P, gneg(A));
11492   piI2A = gmul(PiI2n(1, prec), A);
11493   q = gexp(gdivgs(piI2A, w), prec);
11494   S = gen_0;
11495   for (n = nlim; n >= 1; n--)
11496   {
11497     GEN t = gsubst(P1, vz, gdivsg(w, gaddsg(n, alw)));
11498     S = gadd(gmul(gel(van, n+1), t), gmul(q, S));
11499   }
11500   S = gmul(q, S);
11501   van0 = gel(van, 1);
11502   if (!gequal0(al))
11503   {
11504     S = gadd(S, gmul(gsubst(P1, vz, ginv(al)), van0));
11505     S = gmul(S, gexp(gmul(piI2A, al), prec));
11506   }
11507   else if (!gequal0(van0))
11508     S = gsub(S, gdivgs(gmul(van0, gpowgs(gsub(pol_x(0), A), k-1)), k-1));
11509   if (is_vec_t(typ(S)))
11510   {
11511     long j, l = lg(S);
11512     for (j = 1; j < l; j++) gel(S,j) = toRgX0(gel(S,j));
11513   }
11514   else
11515     S = toRgX0(S);
11516   return gneg(S);
11517 }
11518 
11519 /* \sum_{j <= k} X^j * (Y / (2I\pi))^{k+1-j} k! / j! */
11520 static GEN
get_P(long k,long v,long prec)11521 get_P(long k, long v, long prec)
11522 {
11523   GEN a, S = cgetg(k + 1, t_POL), u = invr(Pi2n(1, prec+EXTRAPRECWORD));
11524   long j, K = k-2;
11525   S[1] = evalsigne(1)|evalvarn(0); a = u;
11526   gel(S,K+2) = monomial(mulcxpowIs(a,3), 1, v); /* j = K */
11527   for(j = K-1; j >= 0; j--)
11528   {
11529     a = mulrr(mulru(a,j+1), u);
11530     gel(S,j+2) = monomial(mulcxpowIs(a,3*(K+1-j)), K+1-j, v);
11531   }
11532   return S;
11533 }
11534 
11535 static GEN
getw1w2(long N,GEN ga)11536 getw1w2(long N, GEN ga)
11537 { return mkvecsmall2(mfZC_width(N, gel(ga,1)),
11538                      mfZC_width(N, gel(ga,2))); }
11539 
11540 static GEN
intAoowithvanall(GEN mf,GEN vanall,GEN P,GEN cosets,long bitprec)11541 intAoowithvanall(GEN mf, GEN vanall, GEN P, GEN cosets, long bitprec)
11542 {
11543   GEN vvan = gel(vanall,1), vaw = gel(vanall,2), W1W2, resall;
11544   long prec = nbits2prec(bitprec), N, k, lco, j;
11545 
11546   N = MF_get_N(mf); k = MF_get_k(mf);
11547   lco = lg(cosets);
11548   W1W2 = cgetg(lco, t_VEC); resall = cgetg(lco, t_VEC);
11549   for (j = 1; j < lco; j++) gel(W1W2,j) = getw1w2(N, gel(cosets, j));
11550   for (j = 1; j < lco; j++)
11551   {
11552     GEN w1w2j = gel(W1W2,j), alj, M, VAN, RES, AR, Q;
11553     long jq, c, w1, w2, w;
11554     if (!w1w2j) continue;
11555     alj = gel(vaw,j);
11556     w1 = w1w2j[1]; Q = cgetg(lco, t_VECSMALL);
11557     w2 = w1w2j[2]; M = cgetg(lco, t_COL);
11558     for (c = 1, jq = j; jq < lco; jq++)
11559     {
11560       GEN W = gel(W1W2, jq);
11561       if (jq == j || (W && gequal(W, w1w2j) && gequal(gel(vaw, jq), alj)))
11562       {
11563         Q[c] = jq; gel(W1W2, jq) = NULL;
11564         gel(M, c) = gel(vvan, jq); c++;
11565       }
11566     }
11567     setlg(M,c); VAN = shallowmatconcat(M);
11568     AR = mkcomplex(gen_0, sqrtr_abs(divru(utor(w1, prec+EXTRAPREC64), w2)));
11569     w = itos(gel(alj,2));
11570     RES = intAoo(VAN, lg(VAN)-2, gel(alj,1),w, P, AR, k, prec);
11571     for (jq = 1; jq < c; jq++) gel(resall, Q[jq]) = gel(RES, jq);
11572   }
11573   return resall;
11574 }
11575 
11576 GEN
mftobasisES(GEN mf,GEN F)11577 mftobasisES(GEN mf, GEN F)
11578 {
11579   GEN v = mftobasis(mf, F, 0);
11580   long nE = lg(MF_get_E(mf))-1;
11581   return mkvec2(vecslice(v,1,nE), vecslice(v,nE+1,lg(v)-1));
11582 }
11583 
11584 static long
wt1mulcond(GEN F,long D,long space)11585 wt1mulcond(GEN F, long D, long space)
11586 {
11587   GEN E = mfeisenstein_i(1, mfchartrivial(), get_mfchar(stoi(D))), mf;
11588   F = mfmul(F, E);
11589   mf = mfinit_Nkchi(mf_get_N(F), mf_get_k(F), mf_get_CHI(F), space, 0);
11590   return mfconductor(mf, F);
11591 }
11592 static int
wt1newlevel(long N)11593 wt1newlevel(long N)
11594 {
11595   GEN P = gel(myfactoru(N),1);
11596   long l = lg(P), i;
11597   for (i = 1; i < l; i++)
11598     if (!wt1empty(N/P[i])) return 0;
11599   return 1;
11600 }
11601 long
mfconductor(GEN mf,GEN F)11602 mfconductor(GEN mf, GEN F)
11603 {
11604   pari_sp av = avma;
11605   GEN gk;
11606   long space, N, M;
11607 
11608   mf = checkMF(mf);
11609   if (!checkmf_i(F)) pari_err_TYPE("mfconductor",F);
11610   if (mfistrivial(F)) return 1;
11611   space = MF_get_space(mf);
11612   if (space == mf_NEW) return mf_get_N(F);
11613   gk = MF_get_gk(mf);
11614   if (isint1(gk))
11615   {
11616     N = mf_get_N(F);
11617     if (!wt1newlevel(N))
11618     {
11619       long s = space_is_cusp(space)? mf_CUSP: mf_FULL;
11620       N = ugcd(N, wt1mulcond(F,-3,s));
11621       if (!wt1newlevel(N)) N = ugcd(N, wt1mulcond(F,-4,s));
11622     }
11623     return gc_long(av,N);
11624   }
11625   if (typ(gk) != t_INT)
11626   {
11627     F = mfmultheta(F);
11628     mf = obj_checkbuild(mf, MF_MF2INIT, &mf2init); /* mf_FULL */
11629   }
11630   N = 1;
11631   if (space_is_cusp(space))
11632   {
11633     F = mftobasis_i(mf, F);
11634     if (typ(gk) != t_INT) F = vecslice(F, lg(MF_get_E(mf)), lg(F) - 1);
11635   }
11636   else
11637   {
11638     GEN EF = mftobasisES(mf, F), vE = gel(EF,1), B = MF_get_E(mf);
11639     long i, l = lg(B);
11640     for (i = 1; i < l; i++)
11641       if (!gequal0(gel(vE,i))) N = ulcm(N, mf_get_N(gel(B, i)));
11642     F = gel(EF,2);
11643   }
11644   (void)mftonew_i(mf, F, &M); /* M = conductor of cuspidal part */
11645   return gc_long(av, ulcm(M, N));
11646 }
11647 
11648 static GEN
fs_get_MF(GEN fs)11649 fs_get_MF(GEN fs) { return gel(fs,1); }
11650 static GEN
fs_get_vES(GEN fs)11651 fs_get_vES(GEN fs) { return gel(fs,2); }
11652 static GEN
fs_get_pols(GEN fs)11653 fs_get_pols(GEN fs) { return gel(fs,3); }
11654 static GEN
fs_get_cosets(GEN fs)11655 fs_get_cosets(GEN fs) { return gel(fs,4); }
11656 static long
fs_get_bitprec(GEN fs)11657 fs_get_bitprec(GEN fs) { return itou(gel(fs,5)); }
11658 static GEN
fs_get_vE(GEN fs)11659 fs_get_vE(GEN fs) { return gel(fs,6); }
11660 static GEN
fs_get_EF(GEN fs)11661 fs_get_EF(GEN fs) { return gel(fs,7); }
11662 static GEN
fs_get_expan(GEN fs)11663 fs_get_expan(GEN fs) { return gel(fs,8); }
11664 static GEN
fs_set_expan(GEN fs,GEN vanall)11665 fs_set_expan(GEN fs, GEN vanall)
11666 { GEN f = shallowcopy(fs); gel(f,8) = vanall; return f; }
11667 static int
mfs_checkmf(GEN fs,GEN mf)11668 mfs_checkmf(GEN fs, GEN mf)
11669 { GEN mfF = fs_get_MF(fs); return gequal(gel(mfF,1), gel(mf,1)); }
11670 static long
checkfs_i(GEN v)11671 checkfs_i(GEN v)
11672 { return typ(v) == t_VEC && lg(v) == 9 && checkMF_i(fs_get_MF(v))
11673     && typ(fs_get_vES(v)) == t_VEC
11674     && typ(fs_get_pols(v)) == t_VEC
11675     && typ(fs_get_cosets(v)) == t_VEC
11676     && typ(fs_get_vE(v)) == t_VEC
11677     && lg(fs_get_pols(v)) == lg(fs_get_cosets(v))
11678     && typ(fs_get_expan(v)) == t_VEC
11679     && lg(fs_get_expan(v)) == 3
11680     && lg(gel(fs_get_expan(v), 1)) == lg(fs_get_cosets(v))
11681     && typ(gel(v,5)) == t_INT; }
11682 GEN
checkMF_i(GEN mf)11683 checkMF_i(GEN mf)
11684 {
11685   long l = lg(mf);
11686   GEN v;
11687   if (typ(mf) != t_VEC) return NULL;
11688   if (l == 9) return checkMF_i(fs_get_MF(mf));
11689   if (l != 7) return NULL;
11690   v = gel(mf,1);
11691   if (typ(v) != t_VEC || lg(v) != 5) return NULL;
11692   return (typ(gel(v,1)) == t_INT
11693          && typ(gmul2n(gel(v,2), 1)) == t_INT
11694          && typ(gel(v,3)) == t_VEC
11695          && typ(gel(v,4)) == t_INT)? mf: NULL; }
11696 GEN
checkMF(GEN T)11697 checkMF(GEN T)
11698 {
11699   GEN mf = checkMF_i(T);
11700   if (!mf) pari_err_TYPE("checkMF [please use mfinit]", T);
11701   return mf;
11702 }
11703 
11704 /* c,d >= 0; c * Nc = N, find coset whose image in P1(Z/NZ) ~ (c, d + k(N/c)) */
11705 static GEN
coset_complete(long c,long d,long Nc)11706 coset_complete(long c, long d, long Nc)
11707 {
11708   long a, b;
11709   while (ugcd(c, d) > 1) d += Nc;
11710   (void)cbezout(c, d, &b, &a);
11711   return mkmat22s(a, -b, c, d);
11712 }
11713 /* right cosets of $\G_0(N)$: $\G=\bigsqcup_j \G_0(N)\ga_j$. */
11714 /* We choose them with c\mid N and d mod N/c, not the reverse */
11715 GEN
mfcosets(GEN gN)11716 mfcosets(GEN gN)
11717 {
11718   pari_sp av = avma;
11719   GEN V, D, mf;
11720   long l, i, ct, N = 0;
11721   if (typ(gN) == t_INT) N = itos(gN);
11722   else if ((mf = checkMF_i(gN))) N = MF_get_N(mf);
11723   else pari_err_TYPE("mfcosets", gN);
11724   if (N <= 0) pari_err_DOMAIN("mfcosets", "N", "<=", gen_0, stoi(N));
11725   V = cgetg(mypsiu(N) + 1, t_VEC);
11726   D = mydivisorsu(N); l = lg(D);
11727   for (i = ct = 1; i < l; i++)
11728   {
11729     long d, c = D[i], Nc = D[l-i], e = ugcd(Nc, c);
11730     for (d = 0; d < Nc; d++)
11731       if (ugcd(d,e) == 1) gel(V, ct++) = coset_complete(c, d, Nc);
11732   }
11733   return gerepilecopy(av, V);
11734 }
11735 static int
cmp_coset(void * E,GEN A,GEN B)11736 cmp_coset(void *E, GEN A, GEN B)
11737 {
11738   ulong N = (ulong)E, Nc, c = itou(gcoeff(A,2,1));
11739   int r = cmpuu(c, itou(gcoeff(B,2,1)));
11740   if (r) return r;
11741   Nc = N / c;
11742   return cmpuu(umodiu(gcoeff(A,2,2), Nc), umodiu(gcoeff(B,2,2), Nc));
11743 }
11744 /* M in SL_2(Z) */
11745 static long
mftocoset_i(ulong N,GEN M,GEN cosets)11746 mftocoset_i(ulong N, GEN M, GEN cosets)
11747 {
11748   pari_sp av = avma;
11749   long A = itos(gcoeff(M,1,1)), c, u, v, Nc, i;
11750   long C = itos(gcoeff(M,2,1)), D = itos(gcoeff(M,2,2));
11751   GEN ga;
11752   c = cbezout(N*A, C, &u, &v); Nc = N/c;
11753   ga = coset_complete(c, umodsu(v*D, Nc), Nc);
11754   i = gen_search(cosets, ga, 0, (void*)N, &cmp_coset);
11755   if (!i) pari_err_BUG("mftocoset [no coset found]");
11756   return gc_long(av,i);
11757 }
11758 /* (U * V^(-1))[2,2] mod N, assuming V in SL2(Z) */
11759 static long
SL2_div_D(ulong N,GEN U,GEN V)11760 SL2_div_D(ulong N, GEN U, GEN V)
11761 {
11762   long c = umodiu(gcoeff(U,2,1), N), d = umodiu(gcoeff(U,2,2), N);
11763   long a2 = umodiu(gcoeff(V,1,1), N), b2 = umodiu(gcoeff(V,1,2), N);
11764   return (a2*d - b2*c) % (long)N;
11765 }
11766 static long
mftocoset_iD(ulong N,GEN M,GEN cosets,long * D)11767 mftocoset_iD(ulong N, GEN M, GEN cosets, long *D)
11768 {
11769   long i = mftocoset_i(N, M, cosets);
11770   *D = SL2_div_D(N, M, gel(cosets,i)); return i;
11771 }
11772 GEN
mftocoset(ulong N,GEN M,GEN cosets)11773 mftocoset(ulong N, GEN M, GEN cosets)
11774 {
11775   long i;
11776   if (!check_SL2Z(M)) pari_err_TYPE("mftocoset",M);
11777   i = mftocoset_i(N, M, cosets);
11778   retmkvec2(gdiv(M,gel(cosets,i)), utoipos(i));
11779 }
11780 
11781 static long
getnlim2(long N,long w1,long w2,long nlim,long k,long bitprec)11782 getnlim2(long N, long w1, long w2, long nlim, long k, long bitprec)
11783 {
11784   if (w2 == N) return nlim;
11785   return mfperiod_prelim_double(1./sqrt((double)w1*w2), k, bitprec + 32);
11786 }
11787 
11788 /* g * S, g 2x2 */
11789 static GEN
ZM_mulS(GEN g)11790 ZM_mulS(GEN g)
11791 { return mkmat2(gel(g,2), ZC_neg(gel(g,1))); }
11792 /* g * T, g 2x2 */
11793 static GEN
ZM_mulT(GEN g)11794 ZM_mulT(GEN g)
11795 { return mkmat2(gel(g,1), ZC_add(gel(g,2), gel(g,1))); }
11796 /* g * T^(-1), g 2x2 */
11797 static GEN
ZM_mulTi(GEN g)11798 ZM_mulTi(GEN g)
11799 { return mkmat2(gel(g,1), ZC_sub(gel(g,2), gel(g,1))); }
11800 
11801 /* Compute all slashexpansions for all cosets */
11802 static GEN
mfgaexpansionall(GEN mf,GEN FE,GEN cosets,double height,long prec)11803 mfgaexpansionall(GEN mf, GEN FE, GEN cosets, double height, long prec)
11804 {
11805   GEN CHI = MF_get_CHI(mf), vres, vresaw;
11806   long lco, j, k = MF_get_k(mf), N = MF_get_N(mf), bitprec = prec2nbits(prec);
11807 
11808   lco = lg(cosets);
11809   vres = const_vec(lco-1, NULL);
11810   vresaw = cgetg(lco, t_VEC);
11811   for (j = 1; j < lco; j++) if (!gel(vres,j))
11812   {
11813     GEN ga = gel(cosets, j), van, aw, al, z, gai;
11814     long w1 = mfZC_width(N, gel(ga,1));
11815     long w2 = mfZC_width(N, gel(ga,2));
11816     long nlim, nlim2, daw, da, na, i;
11817     double sqNinvdbl = height ? height/w1 : 1./sqrt((double)w1*N);
11818     nlim = mfperiod_prelim_double(sqNinvdbl, k, bitprec + 32);
11819     van = mfslashexpansion(mf, FE, ga, nlim, 0, &aw, prec + EXTRAPREC64);
11820     van = vanembed(gel(FE, 1), van, prec + EXTRAPREC64);
11821     al = gel(aw, 1);
11822     nlim2 = height? nlim: getnlim2(N, w1, w2, nlim, k, bitprec);
11823     gel(vres, j) = vecslice(van, 1, nlim2 + 1);
11824     gel(vresaw, j) = aw;
11825     Qtoss(al, &na, &da); daw = da*w1;
11826     z = rootsof1powinit(1, daw, prec + EXTRAPREC64);
11827     gai = ga;
11828     for (i = 1; i < w1; i++)
11829     {
11830       GEN V, coe;
11831       long Di, n, ind, w2, s = ((i*na) % da) * w1, t = i*da;
11832       gai = ZM_mulT(gai);
11833       ind = mftocoset_iD(N, gai, cosets, &Di);
11834       w2 = mfZC_width(N, gel(gel(cosets,ind), 2));
11835       nlim2 = height? nlim: getnlim2(N, w1, w2, nlim, k, bitprec);
11836       gel(vresaw, ind) = aw;
11837       V = cgetg(nlim2 + 2, t_VEC);
11838       for (n = 0; n <= nlim2; n++, s = Fl_add(s, t, daw))
11839         gel(V, n+1) = gmul(gel(van, n+1), rootsof1pow(z, s));
11840       coe = mfcharcxeval(CHI, Di, prec + EXTRAPREC64);
11841       if (!gequal1(coe)) V = RgV_Rg_mul(V, conj_i(coe));
11842       gel(vres, ind) = V;
11843     }
11844   }
11845   return mkvec2(vres, vresaw);
11846 }
11847 
11848 /* Compute all period pols of F|_k\ga_j, vF = mftobasis(F_S) */
11849 static GEN
mfperiodpols_i(GEN mf,GEN FE,GEN cosets,GEN * pvan,long bit)11850 mfperiodpols_i(GEN mf, GEN FE, GEN cosets, GEN *pvan, long bit)
11851 {
11852   long N, i, prec = nbits2prec(bit), k = MF_get_k(mf);
11853   GEN vP, P, CHI, intall = gen_0;
11854 
11855   *pvan = gen_0;
11856   if (k == 0 && gequal0(gel(FE,2)))
11857     return cosets? const_vec(lg(cosets)-1, pol_0(0)): pol_0(0);
11858   N = MF_get_N(mf);
11859   CHI = MF_get_CHI(mf);
11860   P = get_P(k, fetch_var(), prec);
11861   if (!cosets)
11862   { /* ga = id */
11863     long nlim, PREC = prec + EXTRAPREC64;
11864     GEN F = gel(FE,1), sqNinv = invr(sqrtr_abs(utor(N, PREC))); /* A/w */
11865     GEN AR, v, van, T1, T2;
11866 
11867     nlim = mfperiod_prelim(sqNinv, k, bit + 32);
11868     /* F|id: al = 0, w = 1 */
11869     v = mfcoefs_i(F, nlim, 1);
11870     van = vanembed(F, v, PREC);
11871     AR = mkcomplex(gen_0, sqNinv);
11872     T1 = intAoo(van, nlim, gen_0,1, P, AR, k, prec);
11873     if (N == 1) T2 = T1;
11874     else
11875     { /* F|S: al = 0, w = N */
11876       v = mfgaexpansion(mf, FE, mkS(), nlim, PREC);
11877       van = vanembed(F, gel(v,3), PREC);
11878       AR = mkcomplex(gen_0, mulur(N,sqNinv));
11879       T2 = intAoo(van, nlim, gen_0,N, P, AR, k, prec);
11880     }
11881     T1 = gsub(T1, act_S(T2, k));
11882     T1 = normalizeapprox(T1, bit-20);
11883     vP = gprec_wtrunc(T1, prec);
11884   }
11885   else
11886   {
11887     long lco = lg(cosets);
11888     GEN vanall = mfgaexpansionall(mf, FE, cosets, 0, prec);
11889     *pvan = vanall;
11890     intall = intAoowithvanall(mf, vanall, P, cosets, bit);
11891     vP = const_vec(lco-1, NULL);
11892     for (i = 1; i < lco; i++)
11893     {
11894       GEN P, P1, P2, c, ga = gel(cosets, i);
11895       long iS, DS;
11896       if (gel(vP,i)) continue;
11897       P1 = gel(intall, i);
11898       iS = mftocoset_iD(N, ZM_mulS(ga), cosets, &DS);
11899       c = mfcharcxeval(CHI, DS, prec + EXTRAPREC64);
11900       P2 = gel(intall, iS);
11901 
11902       P = act_S(isint1(c)? P2: gmul(c, P2), k);
11903       P = normalizeapprox(gsub(P1, P), bit-20);
11904       gel(vP,i) = gprec_wtrunc(P, prec);
11905       if (iS == i) continue;
11906 
11907       P = act_S(isint1(c)? P1: gmul(conj_i(c), P1), k);
11908       if (!odd(k)) P = gneg(P);
11909       P = normalizeapprox(gadd(P, P2), bit-20);
11910       gel(vP,iS) = gprec_wtrunc(P, prec);
11911     }
11912   }
11913   delete_var(); return vP;
11914 }
11915 
11916 /* when cosets = NULL, return a "fake" symbol containing only fs(oo->0) */
11917 static GEN
mfsymbol_i(GEN mf,GEN F,GEN cosets,long bit)11918 mfsymbol_i(GEN mf, GEN F, GEN cosets, long bit)
11919 {
11920   GEN FE, van, vP, vE, Mvecj, vES = mftobasisES(mf,F);
11921   long precnew, prec = nbits2prec(bit), k = MF_get_k(mf);
11922   vE = mfgetembed(F, prec);
11923   Mvecj = obj_checkbuild(mf, MF_EISENSPACE, &mfeisensteinspaceinit);
11924   if (lg(Mvecj) >= 5) precnew = prec;
11925   else
11926   {
11927     long N = MF_get_N(mf), n = mfperiod_prelim_double(1/(double)N, k, bit + 32);
11928     precnew = prec + inveis_extraprec(N, mkS(), Mvecj, n);
11929   }
11930   FE = mkcol2(F, mf_eisendec(mf,F,precnew));
11931   vP = mfperiodpols_i(mf, FE, cosets, &van, bit);
11932   return mkvecn(8, mf, vES, vP, cosets, utoi(bit), vE, FE, van);
11933 }
11934 
11935 static GEN
fs2_get_cusps(GEN f)11936 fs2_get_cusps(GEN f) { return gel(f,3); }
11937 static GEN
fs2_get_MF(GEN f)11938 fs2_get_MF(GEN f) { return gel(f,1); }
11939 static GEN
fs2_get_W(GEN f)11940 fs2_get_W(GEN f) { return gel(f,2); }
11941 static GEN
fs2_get_F(GEN f)11942 fs2_get_F(GEN f) { return gel(f,4); }
11943 static long
fs2_get_bitprec(GEN f)11944 fs2_get_bitprec(GEN f) { return itou(gel(f,5)); }
11945 static GEN
fs2_get_al0(GEN f)11946 fs2_get_al0(GEN f) { return gel(f,6); }
11947 static GEN
fs2_get_den(GEN f)11948 fs2_get_den(GEN f) { return gel(f,7); }
11949 static int
checkfs2_i(GEN f)11950 checkfs2_i(GEN f)
11951 {
11952   GEN W, C, F, al0;
11953   long l;
11954   if (typ(f) != t_VEC || lg(f) != 8 || typ(gel(f,5)) != t_INT) return 0;
11955   C = fs2_get_cusps(f); l = lg(C);
11956   W = fs2_get_W(f);
11957   F = fs2_get_F(f);
11958   al0 = fs2_get_al0(f);
11959   return checkMF_i(fs2_get_MF(f))
11960       && typ(W) == t_VEC && typ(F) == t_VEC && typ(al0) == t_VECSMALL
11961       && lg(W) == l && lg(F) == l && lg(al0) == l;
11962 }
11963 static GEN fs2_init(GEN mf, GEN F, long bit);
11964 GEN
mfsymbol(GEN mf,GEN F,long bit)11965 mfsymbol(GEN mf, GEN F, long bit)
11966 {
11967   pari_sp av = avma;
11968   GEN cosets = NULL;
11969   if (!F)
11970   {
11971     F = mf;
11972     if (!checkmf_i(F)) pari_err_TYPE("mfsymbol", F);
11973     mf = mfinit_i(F, mf_FULL);
11974   }
11975   else if (!checkmf_i(F)) pari_err_TYPE("mfsymbol", F);
11976   if (checkfs2_i(mf)) return fs2_init(mf, F, bit);
11977   if (checkfs_i(mf))
11978   {
11979     cosets = fs_get_cosets(mf);
11980     mf = fs_get_MF(mf);
11981   }
11982   else if (checkMF_i(mf))
11983   {
11984     GEN gk = MF_get_gk(mf);
11985     if (typ(gk) != t_INT || equali1(gk)) return fs2_init(mf, F, bit);
11986     if (signe(gk) <= 0) pari_err_TYPE("mfsymbol [k <= 0]", mf);
11987     cosets = mfcosets(MF_get_gN(mf));
11988   }
11989   else pari_err_TYPE("mfsymbol",mf);
11990   return gerepilecopy(av, mfsymbol_i(mf, F, cosets, bit));
11991 }
11992 
11993 static GEN
RgX_by_parity(GEN P,long odd)11994 RgX_by_parity(GEN P, long odd)
11995 {
11996   long i, l = lg(P);
11997   GEN Q;
11998   if (l < 4) return odd ? pol_x(0): P;
11999   Q = cgetg(l, t_POL); Q[1] = P[1];
12000   for (i = odd? 2: 3; i < l; i += 2) gel(Q,i) = gen_0;
12001   for (i = odd? 3: 2; i < l; i += 2) gel(Q,i) = gel(P,i);
12002   return normalizepol_lg(Q, l);
12003 }
12004 /* flag 0: period polynomial of F, >0 or <0 with corresponding parity */
12005 GEN
mfperiodpol(GEN mf0,GEN F,long flag,long bit)12006 mfperiodpol(GEN mf0, GEN F, long flag, long bit)
12007 {
12008   pari_sp av = avma;
12009   GEN pol, mf = checkMF_i(mf0);
12010   if (!mf) pari_err_TYPE("mfperiodpol",mf0);
12011   if (checkfs_i(F))
12012   {
12013     GEN mfpols = fs_get_pols(F);
12014     if (!mfs_checkmf(F, mf)) pari_err_TYPE("mfperiodpol [different mf]",F);
12015     pol = gel(mfpols, lg(mfpols)-1); /* trivial coset is last */
12016   }
12017   else
12018   {
12019     GEN gk = MF_get_gk(mf);
12020     if (typ(gk) != t_INT) pari_err_TYPE("mfperiodpol [half-integral k]", mf);
12021     if (equali1(gk)) pari_err_TYPE("mfperiodpol [k = 1]", mf);
12022     F = mfsymbol_i(mf, F, NULL, bit);
12023     pol = fs_get_pols(F);
12024   }
12025   if (flag) pol = RgX_by_parity(pol, flag < 0);
12026   return gerepilecopy(av, RgX_embedall(pol, 0, fs_get_vE(F)));
12027 }
12028 
12029 static int
mfs_iscusp(GEN mfs)12030 mfs_iscusp(GEN mfs) { return gequal0(gmael(mfs,2,1)); }
12031 /* given cusps s1 and s2 (rationals or oo)
12032  * compute $\int_{s1}^{s2}(X-\tau)^{k-2}F|_k\ga_j(\tau)\,d\tau$ */
12033 /* If flag = 1, do not give an error message if divergent, but
12034    give the rational function as result. */
12035 
12036 static GEN
col2cusp(GEN v)12037 col2cusp(GEN v)
12038 {
12039   GEN A, C;
12040   if (lg(v) != 3 || !RgV_is_ZV(v)) pari_err_TYPE("col2cusp",v);
12041   A = gel(v,1);
12042   C = gel(v,2);
12043   if (gequal0(C))
12044   {
12045     if (gequal0(A)) pari_err_TYPE("mfsymboleval", mkvec2(A, C));
12046     return mkoo();
12047   }
12048   return gdiv(A, C);
12049 }
12050 /* g.oo */
12051 static GEN
mat2cusp(GEN g)12052 mat2cusp(GEN g) { return col2cusp(gel(g,1)); }
12053 
12054 static GEN
pathmattovec(GEN path)12055 pathmattovec(GEN path)
12056 { return mkvec2(col2cusp(gel(path,1)), col2cusp(gel(path,2))); }
12057 
12058 static void
get_mf_F(GEN fs,GEN * mf,GEN * F)12059 get_mf_F(GEN fs, GEN *mf, GEN *F)
12060 {
12061   if (lg(fs) == 3) { *mf = gel(fs,1); *F = gel(fs,2); }
12062   else { *mf = fs_get_MF(fs); *F = NULL; }
12063 }
12064 static GEN
mfgetvan(GEN fs,GEN ga,GEN * pal,long nlim,long prec)12065 mfgetvan(GEN fs, GEN ga, GEN *pal, long nlim, long prec)
12066 {
12067   GEN van, mf, F, W;
12068   long PREC;
12069   get_mf_F(fs, &mf, &F);
12070   if (!F)
12071   {
12072     GEN vanall = fs_get_expan(fs), cosets = fs_get_cosets(fs);
12073     long D, jga = mftocoset_iD(MF_get_N(mf), ga, cosets, &D);
12074     van = gmael(vanall, 1, jga);
12075     W   = gmael(vanall, 2, jga);
12076     if (lg(van) >= nlim + 2)
12077     {
12078       GEN z = mfcharcxeval(MF_get_CHI(mf), D, prec);
12079       if (!gequal1(z)) van = RgV_Rg_mul(van, z);
12080       *pal = gel(W,1); return van;
12081     }
12082     F = gel(fs_get_EF(fs), 1);
12083   }
12084   PREC = prec + EXTRAPREC64;
12085   van = mfslashexpansion(mf, F, ga, nlim, 0, &W, PREC);
12086   van = vanembed(F, van, PREC);
12087   *pal = gel(W,1); return van;
12088 }
12089 /* Computation of int_A^oo (f | ga)(t)(X-t)^{k-2} dt, assuming convergence;
12090  * fs is either a symbol or a triple [mf,F,bitprec]. A != oo and im(A) > 0 */
12091 static GEN
intAoo0(GEN fs,GEN A,GEN ga,GEN P,long bit)12092 intAoo0(GEN fs, GEN A, GEN ga, GEN P, long bit)
12093 {
12094   long nlim, N, k, w, prec = nbits2prec(bit);
12095   GEN van, mf, F, al;
12096   get_mf_F(fs, &mf,&F); N = MF_get_N(mf); k = MF_get_k(mf);
12097   w = mfZC_width(N, gel(ga,1));
12098   nlim = mfperiod_prelim(gdivgs(imag_i(A), w), k, bit + 32);
12099   van = mfgetvan(fs, ga, &al, nlim, prec);
12100   return intAoo(van, nlim, al,w, P, A, k, prec);
12101 }
12102 
12103 /* fs symbol, naive summation, A != oo, im(A) > 0 and B = oo or im(B) > 0 */
12104 static GEN
mfsymboleval_direct(GEN fs,GEN path,GEN ga,GEN P)12105 mfsymboleval_direct(GEN fs, GEN path, GEN ga, GEN P)
12106 {
12107   GEN A, B, van, S, al, mf = fs_get_MF(fs);
12108   long w, nlimA, nlimB = 0, N = MF_get_N(mf), k = MF_get_k(mf);
12109   long bit = fs_get_bitprec(fs), prec = nbits2prec(bit);
12110 
12111   A = gel(path, 1);
12112   B = gel(path, 2); if (typ(B) == t_INFINITY) B = NULL;
12113   w = mfZC_width(N, gel(ga,1));
12114   nlimA = mfperiod_prelim(gdivgs(imag_i(A),w), k, bit + 32);
12115   if (B) nlimB = mfperiod_prelim(gdivgs(imag_i(B),w), k, bit + 32);
12116   van = mfgetvan(fs, ga, &al, maxss(nlimA,nlimB), prec);
12117   S = intAoo(van, nlimA, al,w, P, A, k, prec);
12118   if (B) S = gsub(S, intAoo(van, nlimB, al,w, P, B, k, prec));
12119   return RgX_embedall(S, 0, fs_get_vE(fs));
12120 }
12121 
12122 /* Computation of int_A^oo (f | ga)(t)(X-t)^{k-2} dt, assuming convergence;
12123  * fs is either a symbol or a pair [mf,F]. */
12124 static GEN
mfsymbolevalpartial(GEN fs,GEN A,GEN ga,long bit)12125 mfsymbolevalpartial(GEN fs, GEN A, GEN ga, long bit)
12126 {
12127   GEN Y, F, S, P, mf;
12128   long N, k, w, prec = nbits2prec(bit);
12129 
12130   get_mf_F(fs, &mf, &F);
12131   N = MF_get_N(mf); w = mfZC_width(N, gel(ga,1));
12132   k = MF_get_k(mf);
12133   Y = gdivgs(imag_i(A), w);
12134   P = get_P(k, fetch_var(), prec);
12135   if (lg(fs) != 3 && gtodouble(Y)*(2*N) < 1)
12136   { /* true symbol + low imaginary part: use GL_2 action to improve */
12137     GEN U, ga2, czd, A2 = cxredga0N(N, A, &U, &czd, 1), oo = mkoo();
12138     ga2 = ZM_mul(ga, ZM_inv(U, NULL));
12139     S = intAoo0(fs, A2, ga2, P, bit);
12140     S = gsub(S, mfsymboleval(fs, mkvec2(mat2cusp(U), oo), ga2, bit));
12141     S = act_GL2(S, U, k);
12142   }
12143   else
12144     S = intAoo0(fs, A, ga, P, bit);
12145   S = RgX_embedall(S, 0, F? mfgetembed(F,prec): fs_get_vE(fs));
12146   delete_var(); return normalizeapprox(S, bit-20);
12147 }
12148 
12149 static GEN
actal(GEN x,GEN vabd)12150 actal(GEN x, GEN vabd)
12151 {
12152   if (typ(x) == t_INFINITY) return x;
12153   return gdiv(gadd(gmul(gel(vabd,1), x), gel(vabd,2)), gel(vabd,3));
12154 }
12155 
12156 static GEN
unact(GEN z,GEN vabd,long k,long prec)12157 unact(GEN z, GEN vabd, long k, long prec)
12158 {
12159   GEN res = gsubst(z, 0, actal(pol_x(0), vabd));
12160   GEN CO = gpow(gdiv(gel(vabd,3), gel(vabd,1)), sstoQ(k-2, 2), prec);
12161   return gmul(CO, res);
12162 }
12163 
12164 GEN
mfsymboleval(GEN fs,GEN path,GEN ga,long bitprec)12165 mfsymboleval(GEN fs, GEN path, GEN ga, long bitprec)
12166 {
12167   pari_sp av = avma;
12168   GEN tau, V, LM, S, CHI, mfpols, cosets, al, be, mf, F, vabd = NULL;
12169   long D, B, m, u, v, a, b, c, d, j, k, N, prec, tsc1, tsc2;
12170 
12171   if (checkfs_i(fs))
12172   {
12173     get_mf_F(fs, &mf, &F);
12174     bitprec = minss(bitprec, fs_get_bitprec(fs));
12175   }
12176   else
12177   {
12178     if (checkfs2_i(fs)) pari_err_TYPE("mfsymboleval [need integral k > 1]",fs);
12179     if (typ(fs) != t_VEC || lg(fs) != 3) pari_err_TYPE("mfsymboleval",fs);
12180     get_mf_F(fs, &mf, &F);
12181     mf = checkMF_i(mf);
12182     if (!mf ||!checkmf_i(F)) pari_err_TYPE("mfsymboleval",fs);
12183   }
12184   if (lg(path) != 3) pari_err_TYPE("mfsymboleval",path);
12185   if (typ(path) == t_MAT) path = pathmattovec(path);
12186   if (typ(path) != t_VEC) pari_err_TYPE("mfsymboleval",path);
12187   al = gel(path,1);
12188   be = gel(path,2);
12189   ga = ga? GL2toSL2(ga, &vabd): matid(2);
12190   if (vabd)
12191   {
12192     al = actal(al, vabd);
12193     be = actal(be, vabd); path = mkvec2(al, be);
12194   }
12195   tsc1 = cusp_AC(al, &a, &c);
12196   tsc2 = cusp_AC(be, &b, &d);
12197   prec = nbits2prec(bitprec);
12198   k = MF_get_k(mf);
12199   if (!tsc1)
12200   {
12201     GEN z2, z = mfsymbolevalpartial(fs, al, ga, bitprec);
12202     if (tsc2)
12203       z2 = d? mfsymboleval(fs, mkvec2(be, mkoo()), ga, bitprec): gen_0;
12204     else
12205       z2 = mfsymbolevalpartial(fs, be, ga, bitprec);
12206     z = gsub(z, z2);
12207     if (vabd) z = unact(z, vabd, k, prec);
12208     return gerepileupto(av, normalizeapprox(z, bitprec-20));
12209   }
12210   else if (!tsc2)
12211   {
12212     GEN z = mfsymbolevalpartial(fs, be, ga, bitprec);
12213     if (c) z = gsub(mfsymboleval(fs, mkvec2(al, mkoo()), ga, bitprec), z);
12214     if (vabd) z = unact(z, vabd, k, prec);
12215     return gerepileupto(av, normalizeapprox(z, bitprec-20));
12216   }
12217   if (F) pari_err_TYPE("mfsymboleval", fs);
12218   D = a*d-b*c;
12219   if (!D) { set_avma(av); return RgX_embedall(gen_0, 0, fs_get_vE(fs)); }
12220   mfpols = fs_get_pols(fs);
12221   cosets = fs_get_cosets(fs);
12222   CHI = MF_get_CHI(mf); N = MF_get_N(mf);
12223   cbezout(a, c, &u, &v); B = u*b + v*d; tau = mkmat22s(a, -v, c, u);
12224   V = gcf(sstoQ(B, D));
12225   LM = shallowconcat(mkcol2(gen_1, gen_0), contfracpnqn(V, lg(V)));
12226   S = gen_0; m = lg(LM) - 2;
12227   for (j = 0; j < m; j++)
12228   {
12229     GEN M, P;
12230     long D, iN;
12231     M = mkmat2(gel(LM, j+2), gel(LM, j+1));
12232     if (!odd(j)) gel(M,1) = ZC_neg(gel(M,1));
12233     M = ZM_mul(tau, M);
12234     iN = mftocoset_iD(N, ZM_mul(ga, M), cosets, &D);
12235     P = gmul(gel(mfpols,iN), mfcharcxeval(CHI,D,prec));
12236     S = gadd(S, act_GL2(P, ZM_inv(M, NULL), k));
12237   }
12238   if (typ(S) == t_RFRAC)
12239   {
12240     GEN R, S1, co;
12241     gel(S,2) = primitive_part(gel(S,2), &co);
12242     if (co) gel(S,1) = gdiv(gel(S,1), gtofp(co,prec));
12243     S1 = poldivrem(gel(S,1), gel(S,2), &R);
12244     if (gexpo(R) < -bitprec + 20) S = S1;
12245   }
12246   if (vabd) S = unact(S, vabd, k, prec);
12247   S = RgX_embedall(S, 0, fs_get_vE(fs));
12248   return gerepileupto(av, normalizeapprox(S, bitprec-20));
12249 }
12250 
12251 /* v a scalar or t_POL; set *pw = a if expo(a) > E for some coefficient;
12252  * take the 'a' with largest exponent */
12253 static void
improve(GEN v,GEN * pw,long * E)12254 improve(GEN v, GEN *pw, long *E)
12255 {
12256   if (typ(v) != t_POL)
12257   {
12258     long e = gexpo(v);
12259     if (e > *E) { *E = e; *pw = v; }
12260   }
12261   else
12262   {
12263     long j, l = lg(v);
12264     for (j = 2; j < l; j++) improve(gel(v,j), pw, E);
12265   }
12266 }
12267 static GEN
polabstorel(GEN rnfeq,GEN T)12268 polabstorel(GEN rnfeq, GEN T)
12269 {
12270   long i, l;
12271   GEN U;
12272   if (typ(T) != t_POL) return T;
12273   U = cgetg_copy(T, &l); U[1] = T[1];
12274   for (i = 2; i < l; i++) gel(U,i) = eltabstorel(rnfeq, gel(T,i));
12275   return U;
12276 }
12277 static GEN
bestapprnfrel(GEN x,GEN polabs,GEN roabs,GEN rnfeq,long prec)12278 bestapprnfrel(GEN x, GEN polabs, GEN roabs, GEN rnfeq, long prec)
12279 {
12280   x = bestapprnf(x, polabs, roabs, prec);
12281   if (rnfeq) x = polabstorel(rnfeq, liftpol_shallow(x));
12282   return x;
12283 }
12284 /* v vector of polynomials polynomial in C[X] (possibly scalar).
12285  * Set *w = coeff with largest exponent and return T / *w, rationalized */
12286 static GEN
normal(GEN v,GEN polabs,GEN roabs,GEN rnfeq,GEN * w,long prec)12287 normal(GEN v, GEN polabs, GEN roabs, GEN rnfeq, GEN *w, long prec)
12288 {
12289   long i, l = lg(v), E = -(long)HIGHEXPOBIT;
12290   GEN dv;
12291   for (i = 1; i < l; i++) improve(gel(v,i), w, &E);
12292   v = RgV_Rg_mul(v, ginv(*w));
12293   for (i = 1; i < l; i++)
12294     gel(v,i) = bestapprnfrel(gel(v,i), polabs,roabs,rnfeq,prec);
12295   v = Q_primitive_part(v,&dv);
12296   if (dv) *w = gmul(*w,dv);
12297   return v;
12298 }
12299 
12300 static GEN mfpetersson_i(GEN FS, GEN GS);
12301 
12302 GEN
mfmanin(GEN FS,long bitprec)12303 mfmanin(GEN FS, long bitprec)
12304 {
12305   pari_sp av = avma;
12306   GEN mf, M, vp, vm, cosets, CHI, vpp, vmm, f, T, P, vE, polabs, roabs, rnfeq;
12307   GEN pet;
12308   long N, k, lco, i, prec, lvE;
12309 
12310   if (!checkfs_i(FS))
12311   {
12312     if (checkfs2_i(FS)) pari_err_TYPE("mfmanin [need integral k > 1]",FS);
12313     pari_err_TYPE("mfmanin",FS);
12314   }
12315   if (!mfs_iscusp(FS)) pari_err_TYPE("mfmanin [noncuspidal]",FS);
12316   mf = fs_get_MF(FS);
12317   vp = fs_get_pols(FS);
12318   cosets = fs_get_cosets(FS);
12319   bitprec = fs_get_bitprec(FS);
12320   N = MF_get_N(mf); k = MF_get_k(mf); CHI = MF_get_CHI(mf);
12321   lco = lg(cosets); vm = cgetg(lco, t_VEC);
12322   prec = nbits2prec(bitprec);
12323   for (i = 1; i < lco; i++)
12324   {
12325     GEN g = gel(cosets, i), c;
12326     long A = itos(gcoeff(g,1,1)), B = itos(gcoeff(g,1,2));
12327     long C = itos(gcoeff(g,2,1)), D = itos(gcoeff(g,2,2));
12328     long Dbar, ibar = mftocoset_iD(N, mkmat22s(-B,-A,D,C), cosets, &Dbar);
12329 
12330     c = mfcharcxeval(CHI, Dbar, prec); if (odd(k)) c = gneg(c);
12331     T = RgX_Rg_mul(gel(vp,ibar), c);
12332     if (typ(T) == t_POL && varn(T) == 0) T = RgX_recip(T);
12333     gel(vm,i) = T;
12334   }
12335   vpp = gadd(vp,vm);
12336   vmm = gsub(vp,vm);
12337 
12338   vE = fs_get_vE(FS); lvE = lg(vE);
12339   f = gel(fs_get_EF(FS), 1);
12340   P = mf_get_field(f); if (degpol(P) == 1) P = NULL;
12341   T = mfcharpol(CHI);  if (degpol(T) == 1) T = NULL;
12342   if (T && P)
12343   {
12344     rnfeq = nf_rnfeqsimple(T, P);
12345     polabs = gel(rnfeq,1);
12346     roabs = gel(QX_complex_roots(polabs,prec), 1);
12347   }
12348   else
12349   {
12350     rnfeq = roabs = NULL;
12351     polabs = P? P: T;
12352   }
12353   pet = mfpetersson_i(FS, NULL);
12354   M = cgetg(lvE, t_VEC);
12355   for (i = 1; i < lvE; i++)
12356   {
12357     GEN p, m, wp, wm, petdiag, r, E = gel(vE,i);
12358     p = normal(RgXV_embed(vpp,0,E), polabs, roabs, rnfeq, &wp, prec);
12359     m = normal(RgXV_embed(vmm,0,E), polabs, roabs, rnfeq, &wm, prec);
12360     petdiag = typ(pet)==t_MAT? gcoeff(pet,i,i): pet;
12361     r = gdiv(imag_i(gmul(wp, conj_i(wm))), petdiag);
12362     r = bestapprnfrel(r, polabs, roabs, rnfeq, prec);
12363     gel(M,i) = mkvec2(mkvec2(p,m), mkvec3(wp,wm,r));
12364   }
12365   return gerepilecopy(av, lvE == 2? gel(M,1): M);
12366 }
12367 
12368 /* flag = 0: full, flag = +1 or -1, odd/even */
12369 /* Basis of period polynomials in level 1. */
12370 GEN
mfperiodpolbasis(long k,long flag)12371 mfperiodpolbasis(long k, long flag)
12372 {
12373   pari_sp av = avma;
12374   long i, j, km2 = k - 2;
12375   GEN M, C;
12376   if (k <= 4) return cgetg(1,t_VEC);
12377   M = cgetg(k, t_MAT);
12378   C = matpascal(km2);
12379   if (!flag)
12380     for (j = 0; j <= km2; j++)
12381     {
12382       GEN v = cgetg(k, t_COL);
12383       for (i = 0; i <= j; i++) gel(v, i+1) = gcoeff(C, j+1, i+1);
12384       for (; i <= km2; i++) gel(v, i+1) = gcoeff(C, km2-j+1, i-j+1);
12385       gel(M, j+1) = v;
12386     }
12387   else
12388     for (j = 0; j <= km2; j++)
12389     {
12390       GEN v = cgetg(k, t_COL);
12391       for (i = 0; i <= km2; i++)
12392       {
12393         GEN a = i < j ? gcoeff(C, j+1, i+1) : gen_0;
12394         if (i + j >= km2)
12395         {
12396           GEN b = gcoeff(C, j+1, i+j-km2+1);
12397           a = flag < 0 ? addii(a,b) : subii(a,b);
12398         }
12399         gel(v, i+1) = a;
12400       }
12401       gel(M, j+1) = v;
12402     }
12403   return gerepilecopy(av, RgM_to_RgXV(ZM_ker(M), 0));
12404 }
12405 
12406 static int
zero_at_cusp(GEN mf,GEN F,GEN c)12407 zero_at_cusp(GEN mf, GEN F, GEN c)
12408 {
12409   GEN v = evalcusp(mf, F, c, LOWDEFAULTPREC);
12410   return (gequal0(v) || gexpo(v) <= -62);
12411 }
12412 /* Compute list E of j such that F|_k g_j vanishes at oo: return [E, s(E)] */
12413 static void
mffvanish(GEN mf,GEN F,GEN G,GEN cosets,GEN * pres,GEN * press)12414 mffvanish(GEN mf, GEN F, GEN G, GEN cosets, GEN *pres, GEN *press)
12415 {
12416   long j, lc = lg(cosets), N = MF_get_N(mf);
12417   GEN v, vs;
12418   *pres = v  = zero_zv(lc-1);
12419   *press= vs = zero_zv(lc-1);
12420   for (j = 1; j < lc; j++)
12421   {
12422     GEN ga = gel(cosets,j), c = mat2cusp(ga);
12423     if (zero_at_cusp(mf, F, c))
12424       v[j] = vs[ mftocoset_i(N, ZM_mulS(ga), cosets) ] = 1;
12425     else if (!zero_at_cusp(mf, G, c))
12426       pari_err_IMPL("divergent Petersson product");
12427   }
12428 }
12429 static GEN
Haberland(GEN PF,GEN PG,GEN vEF,GEN vEG,long k)12430 Haberland(GEN PF, GEN PG, GEN vEF, GEN vEG, long k)
12431 {
12432   GEN S = gen_0, vC = vecbinomial(k-2); /* vC[n+1] = (-1)^n binom(k-2,n) */
12433   long n, j, l = lg(PG);
12434   for (n = 2; n < k; n+=2) gel(vC,n) = negi(gel(vC,n));
12435   for (j = 1; j < l; j++)
12436   {
12437     GEN PFj = gel(PF,j), PGj = gel(PG,j);
12438     for (n = 0; n <= k-2; n++)
12439     {
12440       GEN a = RgX_coeff(PGj, k-2-n), b = RgX_coeff(PFj, n);
12441       a = Rg_embedall(a, vEG);
12442       b = Rg_embedall(b, vEF);
12443       a = conj_i(a); if (typ(a) == t_VEC) settyp(a, t_COL);
12444       /* a*b = scalar or t_VEC or t_COL or t_MAT */
12445       S = gadd(S, gdiv(gmul(a,b), gel(vC,n+1)));
12446     }
12447   }
12448   S = mulcxpowIs(gmul2n(S, 1-k), 1+k);
12449   return vEF==vEG? real_i(S): S;
12450 }
12451 /* F1S, F2S both symbols, same mf */
12452 static GEN
mfpeterssonnoncusp(GEN F1S,GEN F2S)12453 mfpeterssonnoncusp(GEN F1S, GEN F2S)
12454 {
12455   pari_sp av = avma;
12456   GEN mf, F1, F2, GF1, GF2, P2, cosets, vE1, vE2, FE1, FE2, P;
12457   GEN I, IP1, RHO, RHOP1, INF, res, ress;
12458   const double height = sqrt(3.)/2;
12459   long k, r, j, bitprec, prec;
12460 
12461   mf = fs_get_MF(F1S);
12462   FE1 = fs_get_EF(F1S); F1 = gel(FE1, 1);
12463   FE2 = fs_get_EF(F2S); F2 = gel(FE2, 1);
12464   cosets = fs_get_cosets(F1S);
12465   bitprec = minuu(fs_get_bitprec(F1S), fs_get_bitprec(F2S));
12466   prec = nbits2prec(bitprec);
12467   F1S = fs_set_expan(F1S, mfgaexpansionall(mf, FE1, cosets, height, prec));
12468   if (F2S != F1S)
12469     F2S = fs_set_expan(F2S, mfgaexpansionall(mf, FE2, cosets, height, prec));
12470   k = MF_get_k(mf); r = lg(cosets) - 1;
12471   vE1 = fs_get_vE(F1S);
12472   vE2 = fs_get_vE(F2S);
12473   I = gen_I();
12474   IP1 = mkcomplex(gen_1,gen_1);
12475   RHO = rootsof1u_cx(3, prec+EXTRAPREC64);
12476   RHOP1 = gaddsg(1, RHO);
12477   INF = mkoo();
12478   mffvanish(mf, F1, F2, cosets, &res, &ress);
12479   P2 = fs_get_pols(F2S);
12480   GF1 = cgetg(r+1, t_VEC);
12481   GF2 = cgetg(r+1, t_VEC); P = get_P(k, fetch_var(), prec);
12482   for (j = 1; j <= r; j++)
12483   {
12484     GEN g = gel(cosets,j);
12485     if (res[j]) {
12486       gel(GF1,j) = mfsymboleval_direct(F1S, mkvec2(RHOP1,INF), g, P);
12487       gel(GF2,j) = mfsymboleval_direct(F2S, mkvec2(I,IP1), g, P);
12488     } else if (ress[j]) {
12489       gel(GF1,j) = mfsymboleval_direct(F1S, mkvec2(RHOP1,RHO), g, P);
12490       gel(GF2,j) = mfsymboleval_direct(F2S, mkvec2(I,INF), g, P);
12491     } else {
12492       gel(GF1,j) = mfsymboleval_direct(F1S, mkvec2(RHO,I), g, P);
12493       gel(GF2,j) = gneg(gel(P2,j)); /* - symboleval(F2S, [0,oo] */
12494     }
12495   }
12496   delete_var();
12497   return gerepileupto(av, gdivgs(Haberland(GF1,GF2, vE1,vE2, k), r));
12498 }
12499 
12500 /* Petersson product of F and G, given by mfsymbol's [k > 1 integral] */
12501 static GEN
mfpetersson_i(GEN FS,GEN GS)12502 mfpetersson_i(GEN FS, GEN GS)
12503 {
12504   pari_sp av = avma;
12505   GEN mf, ESF, ESG, PF, PG, PH, CHI, cosets, vEF, vEG;
12506   long k, r, j, N, bitprec, prec;
12507 
12508   if (!checkfs_i(FS)) pari_err_TYPE("mfpetersson",FS);
12509   mf = fs_get_MF(FS);
12510   ESF = fs_get_vES(FS);
12511   if (!GS) GS = FS;
12512   else
12513   {
12514     if (!checkfs_i(GS)) pari_err_TYPE("mfpetersson",GS);
12515     if (!mfs_checkmf(GS, mf))
12516       pari_err_TYPE("mfpetersson [different mf]", mkvec2(FS,GS));
12517   }
12518   ESG = fs_get_vES(GS);
12519   if (!gequal0(gel(ESF,1)) && !gequal0(gel(ESG,1)))
12520     return mfpeterssonnoncusp(FS, GS);
12521   if (gequal0(gel(ESF,2)) || gequal0(gel(ESG,2))) return gc_const(av, gen_0);
12522   N = MF_get_N(mf);
12523   k = MF_get_k(mf);
12524   CHI = MF_get_CHI(mf);
12525   PF = fs_get_pols(FS); vEF = fs_get_vE(FS);
12526   PG = fs_get_pols(GS); vEG = fs_get_vE(GS);
12527   cosets = fs_get_cosets(FS);
12528   bitprec = minuu(fs_get_bitprec(FS), fs_get_bitprec(GS));
12529   prec = nbits2prec(bitprec);
12530   r = lg(PG)-1;
12531   PH = cgetg(r+1, t_VEC);
12532   for (j = 1; j <= r; j++)
12533   {
12534     GEN ga = gel(cosets,j), PGj1, PGjm1;
12535     long iT, D;
12536     iT = mftocoset_iD(N, ZM_mulTi(ga), cosets, &D);
12537     PGj1 = RgX_translate(gel(PG, iT), gen_1);
12538     PGj1 = RgX_Rg_mul(PGj1, mfcharcxeval(CHI, D, prec));
12539     iT = mftocoset_iD(N, ZM_mulT(ga), cosets, &D);
12540     PGjm1 = RgX_translate(gel(PG,iT), gen_m1);
12541     PGjm1 = RgX_Rg_mul(PGjm1, mfcharcxeval(CHI, D, prec));
12542     gel(PH,j) = gsub(PGj1, PGjm1);
12543   }
12544   return gerepileupto(av, gdivgs(Haberland(PF, PH, vEF, vEG, k), 6*r));
12545 }
12546 
12547 /****************************************************************/
12548 /*           Petersson products using Nelson-Collins            */
12549 /****************************************************************/
12550 
12551 /* Compute W(k,z) = \sum_{m >= 1} (mz)^{k-1}(mzK_{k-2}(mz)-K_{k-1}(mz))
12552  * for z>0 and absolute accuracy < 2^{-B}.
12553  * K_k(x) ~ (\pi/(2x))^{1/2}e^{-x} */
12554 
12555 static void
Wcomputeparams(GEN * ph,long * pN,long k,GEN x,long prec)12556 Wcomputeparams(GEN *ph, long *pN, long k, GEN x, long prec)
12557 {
12558   double B = prec2nbits(prec) + 10;
12559   double dx = gtodouble(x);
12560   double C = B + k*log(dx)/M_LN2 + 1;
12561   double D = C*M_LN2 + 2.065;
12562   double F = 2*((C - 1)*M_LN2 + log(gtodouble(mpfact(k))))/dx;
12563   double T = log(F) * (1 + 2*k/dx/F);
12564   double PI2 = M_PI*M_PI;
12565   *pN = (long)ceil((T/PI2) * (D + log(D/PI2)));
12566   *ph = gprec_w(dbltor(T / *pN), prec);
12567 }
12568 
12569 static void
Wcomputecoshall(GEN * pCOSH,GEN * pCOSHK,GEN * pCOSHKm1,GEN h,long N,long k,long prec)12570 Wcomputecoshall(GEN *pCOSH, GEN *pCOSHK, GEN *pCOSHKm1, GEN h, long N, long k,
12571                 long prec)
12572 {
12573   GEN COSH, COSHK, COSHKm1, z = gexp(h, prec), zkm1 = gpowgs(z, k - 1);
12574   GEN PO = gpowers(z, N), INV = ginv(gel(PO, N + 1));
12575   GEN POKm1 = gpowers(zkm1, N), INVKm1 = ginv(gel(POKm1, N + 1));
12576   long j;
12577   *pCOSH = COSH = cgetg(N+2, t_VEC);
12578   *pCOSHK = COSHK = cgetg(N+2, t_VEC);
12579   *pCOSHKm1 = COSHKm1 = cgetg(N+2, t_VEC);
12580   gel(COSH, 1) = gen_1; gel(COSHK, 1) = gen_1; gel(COSHKm1, 1) = gen_1;
12581   for (j = 1; j <= N; j++)
12582   {
12583     GEN ejh = gel(PO, j+1), emjh = gmul(gel(PO, N-j+1), INV);
12584     GEN ekm1jh = gel(POKm1, j+1), ekm1mjh = gmul(gel(POKm1, N-j+1), INVKm1);
12585     gel(COSH, j+1) = gmul2n(gadd(ejh, emjh), -1);
12586     gel(COSHKm1, j+1) = gmul2n(gadd(ekm1jh, ekm1mjh), -1);
12587     gel(COSHK, j+1) = gmul2n(gadd(gmul(ejh, ekm1jh), gmul(emjh, ekm1mjh)), -1);
12588   }
12589 }
12590 
12591 /* computing W(k,x) via integral */
12592 static GEN
Wint(long k,GEN VP,GEN x,long prec)12593 Wint(long k, GEN VP, GEN x, long prec)
12594 {
12595   GEN Pk, Pkm1, Sm1, S, h, COSH, COSHK, COSHKm1;
12596   long N, j;
12597   Wcomputeparams(&h, &N, k, x, prec);
12598   Pk = gel(VP,k+1);
12599   Pkm1 = gel(VP,k);
12600   Wcomputecoshall(&COSH, &COSHK, &COSHKm1, h, N, k, prec);
12601   Sm1 = gen_0; S = gen_0;
12602   for (j = 0; j <= N; j++)
12603   {
12604     GEN ch = gexp(gmul(x, gel(COSH, j+1)), prec);
12605     GEN chm1 = gsubgs(ch, 1), chm1km1 = gpowgs(chm1, k);
12606     GEN tkm1, tk;
12607     tk = gmul(gdiv(gsubst(Pk, 0, ch), gmul(chm1, chm1km1)), gel(COSHK, j+1));
12608     tkm1 = gmul(gdiv(gsubst(Pkm1, 0, ch), chm1km1), gel(COSHKm1, j+1));
12609     if (!j) { tk = gmul2n(tk, -1); tkm1 = gmul2n(tkm1, -1); }
12610     S = gadd(S, tk); Sm1 = gadd(Sm1, tkm1);
12611   }
12612   return gmul(gmul(h, gpowgs(x, k-1)), gsub(gmul(x, S), gmulsg(2*k-1, Sm1)));
12613 }
12614 
12615 /* P_j given P_{j-1} */
12616 static GEN
nextP(GEN P,long j,GEN Xm1)12617 nextP(GEN P, long j, GEN Xm1)
12618 { return RgX_shift_shallow(gsub(gmulsg(j, P), gmul(Xm1, ZX_deriv(P))), 1); }
12619 static GEN
get_vP(long k)12620 get_vP(long k)
12621 {
12622   GEN v = cgetg(k+2, t_VEC), Xm1 = deg1pol_shallow(gen_1,gen_m1,0);
12623   long j;
12624   gel(v,1) = gen_1;
12625   gel(v,2) = pol_x(0);
12626   for (j = 2; j <= k; j++) gel(v,j+1) = nextP(gel(v,j), j, Xm1);
12627   return v;
12628 }
12629 /* vector of (-1)^j(1/(exp(x)-1))^(j) [x = z] * z^j for 0<=j<=k */
12630 static GEN
VS(long k,GEN z,GEN V,long prec)12631 VS(long k, GEN z, GEN V, long prec)
12632 {
12633   GEN ex = gexp(z, prec), c = ginv(gsubgs(ex,1));
12634   GEN po = gpowers0(gmul(c, z), k, c);
12635   long j;
12636   V = gsubst(V, 0, ex);
12637   for (j = 1; j <= k + 1; j++) gel(V,j) = gmul(gel(V,j), gel(po, j));
12638   return V;
12639 }
12640 
12641 /* U(k,x)=sum_{m >= 1} (mx)^{k+1/2}K_{k+1/2}(mx) */
12642 static GEN
Unelsonhalf(long k,GEN V)12643 Unelsonhalf(long k, GEN V)
12644 {
12645   GEN S = gel(V,k+1), C = gen_1; /* (k+j)! / j! / (k-j)! */
12646   long j;
12647   if (!k) return S;
12648   for (j = 1; j <= k; j++)
12649   {
12650     C = gdivgs(gmulgs(C, (k+j)*(k-j+1)), j);
12651     S = gadd(S, gmul2n(gmul(C, gel(V, k-j+1)), -j));
12652   }
12653   return S;
12654 }
12655 /* W(k+1/2,z) / sqrt(Pi/2) */
12656 static GEN
Whalfint(long k,GEN VP,GEN z,long prec)12657 Whalfint(long k, GEN VP, GEN z, long prec)
12658 {
12659   GEN R, V = VS(k, z, VP, prec);
12660   R = Unelsonhalf(k, V);
12661   if (k) R = gsub(R, gmulsg(2*k, Unelsonhalf(k-1, V)));
12662   return R;
12663 }
12664 static GEN
WfromZ(GEN Z,GEN VP,GEN gkm1,long k2,GEN pi4,long prec)12665 WfromZ(GEN Z, GEN VP, GEN gkm1, long k2, GEN pi4, long prec)
12666 {
12667   GEN Zk = gpow(Z, gkm1, prec), z = gmul(pi4, gsqrt(Z,prec));
12668   z = odd(k2)? Whalfint(k2 >> 1, VP, z, prec)
12669              : Wint(k2 >> 1, VP, z, prec);
12670   return gdiv(z, Zk);
12671 }
12672 static long
mfindex(long N)12673 mfindex(long N)
12674 {
12675   GEN fa;
12676   long P = N, i;
12677   if (N == 1) return 1;
12678   fa = gel(factoru(N), 1);
12679   for (i = 1; i < lg(fa); ++i) P += P/fa[i];
12680   return P;
12681 }
12682 /* mf a true mf or an fs2 */
12683 static GEN
fs2_init(GEN mf,GEN F,long bit)12684 fs2_init(GEN mf, GEN F, long bit)
12685 {
12686   pari_sp av = avma;
12687   long i, l, lim, N, k, k2, prec = nbits2prec(bit);
12688   GEN DEN, cusps, tab, gk, gkm1, W0, vW, vVW, vVF, vP, al0;
12689   GEN vE = mfgetembed(F, prec), pi4 = Pi2n(2, prec);
12690   if (lg(mf) == 7)
12691   {
12692     vW = NULL; /* true mf */
12693     DEN = cusps = NULL; /* -Wall */
12694   }
12695   else
12696   { /* mf already an fs2, reset if its precision is too low */
12697     vW = (fs2_get_bitprec(mf) < bit)? NULL: fs2_get_W(mf);
12698     cusps = fs2_get_cusps(mf);
12699     DEN = fs2_get_den(mf);
12700     mf = fs2_get_MF(mf);
12701   }
12702   N = MF_get_N(mf);
12703   gk = MF_get_gk(mf); gkm1 = gsubgs(gk, 1);
12704   k2 = itos(gmul2n(gk,1));
12705   k = k2 >> 1;
12706   vP = get_vP(k);
12707   if (vW)
12708   {
12709     tab = gel(vW,1); /* attached to cusp 0, width N */
12710     lim = (lg(tab)-1) / N;
12711   }
12712   else
12713   { /* true mf */
12714     double kd = gtodouble(gk), B = (bit + 10)*M_LN2;
12715     double L = (B + kd*log(B) + kd*kd*log(B)/B) / (4*M_PI);
12716     long n, Lw;
12717     lim = ((long)ceil(L*L));
12718     Lw = N*lim;
12719     tab = cgetg(Lw+1,t_VEC);
12720     for (n = 1; n <= Lw; n++)
12721     {
12722       pari_sp av = avma;
12723       gel(tab,n) = gerepileupto(av, WfromZ(sstoQ(n,N),vP, gkm1, k2, pi4, prec));
12724     }
12725     cusps = mfcusps_i(N);
12726     DEN = gmul2n(gmulgs(gpow(Pi2n(3, prec), gkm1, prec), mfindex(N)), -2);
12727     if (odd(k2)) DEN = gdiv(DEN, sqrtr_abs(Pi2n(-1,prec)));
12728   }
12729   l = lg(cusps);
12730   vVF = cgetg(l, t_VEC);
12731   vVW = cgetg(l, t_VEC);
12732   al0 = cgetg(l, t_VECSMALL);
12733   W0 = k2==1? ginv(pi4): gen_0;
12734   for (i = 1; i < l; i++)
12735   {
12736     long A, C, w, wi, Lw, n;
12737     GEN VF, W, paramsf, al;
12738     (void)cusp_AC(gel(cusps,i), &A,&C);
12739     wi = ugcd(N, C*C); w = N / wi; Lw = w*lim;
12740     VF = mfslashexpansion(mf, F, cusp2mat(A,C), Lw, 0, &paramsf, prec);
12741     /* paramsf[2] = w */
12742     av = avma; al = gel(paramsf, 1); if (gequal0(al)) al = NULL;
12743     for (n = 0; n <= Lw; n++)
12744     {
12745       GEN a = gel(VF,n+1);
12746       gel(VF,n+1) = gequal0(a)? gen_0: Rg_embedall(a, vE);
12747     }
12748     if (vW)
12749       W = gel(vW, i);
12750     else
12751     {
12752       W = cgetg(Lw+2, t_VEC);
12753       for (n = 0; n <= Lw; n++)
12754       {
12755         GEN c;
12756         if (!al) c = n? gel(tab, n * wi): W0;
12757         else
12758         {
12759           pari_sp av = avma;
12760           c = gerepileupto(av, WfromZ(gadd(al,sstoQ(n,w)),vP,gkm1,k2,pi4, prec));
12761         }
12762         gel(W,n+1) = c;
12763       }
12764     }
12765     al0[i] = !al;
12766     gel(vVF, i) = VF;
12767     gel(vVW, i) = W;
12768   }
12769   if (k2 <= 1) al0 = zero_zv(l-1); /* no need to test for convergence */
12770   return gerepilecopy(av, mkvecn(7, mf,vVW,cusps,vVF,utoipos(bit),al0,DEN));
12771 }
12772 
12773 static GEN
mfpetersson2(GEN Fs,GEN Gs)12774 mfpetersson2(GEN Fs, GEN Gs)
12775 {
12776   pari_sp av = avma;
12777   GEN VC, RES, vF, vG, vW = fs2_get_W(Fs), al0 = fs2_get_al0(Fs);
12778   long N = MF_get_N(fs2_get_MF(Fs)), j, lC;
12779 
12780   VC = fs2_get_cusps(Fs); lC = lg(VC);
12781   vF = fs2_get_F(Fs);
12782   vG = Gs? fs2_get_F(Gs): vF;
12783   RES = gen_0;
12784   for (j = 1; j < lC; j++)
12785   {
12786     GEN W = gel(vW,j), VF = gel(vF,j), VG = gel(vG,j), T = gen_0;
12787     long A, C, w, n, L = lg(W);
12788     pari_sp av = avma;
12789     (void)cusp_AC(gel(VC,j), &A,&C); w = N/ugcd(N, C*C);
12790     if (al0[j] && !isintzero(gel(VF,1)) && !isintzero(gel(VG,1)))
12791       pari_err_IMPL("divergent Petersson product");
12792     for (n = 1; n < L; n++)
12793     {
12794       GEN b = gel(VF,n), a = gel(VG,n);
12795       if (!isintzero(a) && !isintzero(b))
12796       {
12797         T = gadd(T, gmul(gel(W,n), gmul(conj_i(a),b)));
12798         if (gc_needed(av,2)) T = gerepileupto(av,T);
12799       }
12800     }
12801     if (w != 1) T = gmulgs(T,w);
12802     RES = gerepileupto(av, gadd(RES, T));
12803   }
12804   if (!Gs) RES = real_i(RES);
12805   return gerepileupto(av, gdiv(RES, fs2_get_den(Fs)));
12806 }
12807 
12808 static long
symbol_type(GEN F)12809 symbol_type(GEN F)
12810 {
12811   if (checkfs_i(F)) return 1;
12812   if (checkfs2_i(F)) return 2;
12813   return 0;
12814 }
12815 static int
symbol_same_mf(GEN F,GEN G)12816 symbol_same_mf(GEN F, GEN G) { return gequal(gmael(F,1,1), gmael(G,1,1)); }
12817 GEN
mfpetersson(GEN F,GEN G)12818 mfpetersson(GEN F, GEN G)
12819 {
12820   long tF = symbol_type(F);
12821   if (!tF) pari_err_TYPE("mfpetersson",F);
12822   if (G)
12823   {
12824     long tG = symbol_type(G);
12825     if (!tG) pari_err_TYPE("mfpetersson",F);
12826     if (tF != tG || !symbol_same_mf(F,G))
12827       pari_err_TYPE("mfpetersson [incompatible symbols]", mkvec2(F,G));
12828   }
12829   return (tF == 1)? mfpetersson_i(F, G): mfpetersson2(F, G);
12830 }
12831 
12832 /****************************************************************/
12833 /*         projective Galois representation, weight 1           */
12834 /****************************************************************/
12835 static void
moreorders(long N,GEN CHI,GEN F,GEN * pP,GEN * pO,ulong * bound)12836 moreorders(long N, GEN CHI, GEN F, GEN *pP, GEN *pO, ulong *bound)
12837 {
12838   pari_sp av = avma;
12839   forprime_t iter;
12840   ulong a = *bound+1, b = 2*(*bound), p;
12841   long i = 1;
12842   GEN P, O, V = mfcoefs_i(F, b, 1);
12843   *bound = b;
12844   P = cgetg(b-a+2, t_VECSMALL);
12845   O = cgetg(b-a+2, t_VECSMALL);
12846   u_forprime_init(&iter, a, b);
12847   while((p = u_forprime_next(&iter))) if (N % p)
12848   {
12849     O[i] = mffindrootof1(V, p, CHI);
12850     P[i++] = p;
12851   }
12852   setlg(P, i); *pP = shallowconcat(*pP, P);
12853   setlg(O, i); *pO = shallowconcat(*pO, O);
12854   gerepileall(av, 2, pP, pO);
12855 }
12856 
12857 static GEN
search_abelian(GEN nf,long n,long k,GEN N,GEN CHI,GEN F,GEN * pP,GEN * pO,ulong * bound,long prec)12858 search_abelian(GEN nf, long n, long k, GEN N, GEN CHI, GEN F,
12859                GEN *pP, GEN *pO, ulong *bound, long prec)
12860 {
12861   pari_sp av = avma;
12862   GEN bnr, cond, H, cyc, gn, T, Bquo, P, E;
12863   long sN = itos(N), r1 = nf_get_r1(nf), i, j, d;
12864 
12865   cond = idealfactor(nf, N);
12866   P = gel(cond,1);
12867   E = gel(cond,2);
12868   for (i = j = 1; i < lg(P); i++)
12869   {
12870     GEN pr = gel(P,i), Ej = gen_1;
12871     long p = itos(pr_get_p(pr));
12872     if (p == n)
12873     {
12874       long e = pr_get_e(pr); /* 1 + [e*p/(p-1)] */
12875       Ej = utoipos(1 + (e*p) / (p-1));
12876     }
12877     else
12878     {
12879       long f = pr_get_f(pr);
12880       if (Fl_powu(p % n, f, n) != 1) continue;
12881     }
12882     gel(P,j) = pr;
12883     gel(E,j) = Ej; j++;
12884   }
12885   setlg(P,j);
12886   setlg(E,j);
12887   cond = mkvec2(cond, const_vec(r1, gen_1));
12888   bnr = Buchraymod(Buchall(nf, nf_FORCE, prec), cond, nf_INIT, utoipos(n));
12889   cyc = bnr_get_cyc(bnr);
12890   d = lg(cyc)-1;
12891   H = zv_diagonal(ZV_to_Flv(cyc, n));
12892   gn = utoi(n);
12893   for (i = 1;;)
12894   {
12895     for(j = 2; i < lg(*pO); i++)
12896     {
12897       long o, q = (*pP)[i];
12898       GEN pr = idealprimedec_galois(nf, stoi(q));
12899       o = ((*pO)[i] / pr_get_f(pr)) % n;
12900       if (o)
12901       {
12902         GEN v = ZV_to_Flv(isprincipalray(bnr, pr), n);
12903         H = vec_append(H, Flv_Fl_mul(v, o, n));
12904       }
12905     }
12906     H = Flm_image(H, n); if (lg(cyc)-lg(H) <= k) break;
12907     moreorders(sN, CHI, F, pP, pO, bound);
12908   }
12909   H = hnfmodid(shallowconcat(zm_to_ZM(H), diagonal_shallow(cyc)), gn);
12910 
12911   Bquo = cgetg(k+1, t_MAT);
12912   for (i = j = 1; i <= d; i++)
12913     if (!equali1(gcoeff(H,i,i))) gel(Bquo,j++) = col_ei(d,i);
12914 
12915   for (i = 1, T = NULL; i<=k; i++)
12916   {
12917     GEN Hi = hnfmodid(shallowconcat(H, vecsplice(Bquo,i)), gn);
12918     GEN pol = rnfkummer(bnr, Hi, prec);
12919     T = T? nfcompositum(nf, T, pol, 2): pol;
12920   }
12921   T = rnfequation(nf, T);
12922   gerepileall(av, 3, pP, pO, &T);
12923   return T;
12924 }
12925 
12926 static GEN
search_solvable(GEN LG,GEN mf,GEN F,long prec)12927 search_solvable(GEN LG, GEN mf, GEN F, long prec)
12928 {
12929   GEN N = MF_get_gN(mf), CHI = MF_get_CHI(mf), pol, O, P, nf, Nfa;
12930   long i, l = lg(LG), v = fetch_var();
12931   ulong bound = 1;
12932   O = cgetg(1, t_VECSMALL); /* projective order of rho(Frob_p) */
12933   P = cgetg(1, t_VECSMALL);
12934   Nfa = Z_factor(N);
12935   pol = pol_x(v);
12936   for (i = 1; i < l; i++)
12937   { /* n prime, find a (Z/nZ)^k - extension */
12938     GEN G = gel(LG,i);
12939     long n = G[1], k = G[2];
12940     nf = nfinit0(mkvec2(pol,Nfa), 2, prec);
12941     pol = search_abelian(nf, n, k, N, CHI, F, &P, &O, &bound, prec);
12942     setvarn(pol,v);
12943   }
12944   delete_var(); setvarn(pol,0); return pol;
12945 }
12946 
12947 GEN
mfgaloisprojrep(GEN mf,GEN F,long prec)12948 mfgaloisprojrep(GEN mf, GEN F, long prec)
12949 {
12950   pari_sp av = avma;
12951   GEN LG = NULL;
12952   long mft;
12953   if (!checkMF_i(mf) && !checkmf_i(F)) pari_err_TYPE("mfgaloisrep", F);
12954   mft = itos(mfgaloistype(mf,F));
12955   if (mft == -12 || mft == 0)
12956     LG = mkvec2(mkvecsmall2(3,1), mkvecsmall2(2,2));
12957   else if (mft == -24)
12958     LG = mkvec3(mkvecsmall2(2,1), mkvecsmall2(3,1), mkvecsmall2(2,2));
12959   else pari_err_IMPL("mfgaloisprojrep for types other than A4 and S4");
12960   return gerepilecopy(av, search_solvable(LG, mf, F, prec));
12961 }
12962