Line data Source code
1 : /* Copyright (C) 2014 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 : #include "pari.h"
16 : #include "paripriv.h"
17 :
18 : #define DEBUGLEVEL DEBUGLEVEL_polmodular
19 :
20 : #define dbg_printf(lvl) if (DEBUGLEVEL >= (lvl) + 3) err_printf
21 :
22 : /**
23 : * START Code from AVSs "class_inv.h"
24 : */
25 :
26 : /* actually just returns the square-free part of the level, which is
27 : * all we care about */
28 : long
29 40383 : modinv_level(long inv)
30 : {
31 40383 : switch (inv) {
32 31805 : case INV_J: return 1;
33 1323 : case INV_G2:
34 1323 : case INV_W3W3E2:return 3;
35 1098 : case INV_F:
36 : case INV_F2:
37 : case INV_F4:
38 1098 : case INV_F8: return 6;
39 70 : case INV_F3: return 2;
40 511 : case INV_W3W3: return 6;
41 1596 : case INV_W2W7E2:
42 1596 : case INV_W2W7: return 14;
43 269 : case INV_W3W5: return 15;
44 301 : case INV_W2W3E2:
45 301 : case INV_W2W3: return 6;
46 644 : case INV_W2W5E2:
47 644 : case INV_W2W5: return 30;
48 441 : case INV_W2W13: return 26;
49 1725 : case INV_W3W7: return 42;
50 544 : case INV_W5W7: return 35;
51 56 : case INV_W3W13: return 39;
52 : }
53 : pari_err_BUG("modinv_level"); return 0;/*LCOV_EXCL_LINE*/
54 : }
55 :
56 : /* Where applicable, returns N=p1*p2 (possibly p2=1) s.t. two j's
57 : * related to the same f are N-isogenous, and 0 otherwise. This is
58 : * often (but not necessarily) equal to the level. */
59 : long
60 7243344 : modinv_degree(long *p1, long *p2, long inv)
61 : {
62 7243344 : switch (inv) {
63 297319 : case INV_W3W5: return (*p1 = 3) * (*p2 = 5);
64 427304 : case INV_W2W3E2:
65 427304 : case INV_W2W3: return (*p1 = 2) * (*p2 = 3);
66 1545187 : case INV_W2W5E2:
67 1545187 : case INV_W2W5: return (*p1 = 2) * (*p2 = 5);
68 947791 : case INV_W2W7E2:
69 947791 : case INV_W2W7: return (*p1 = 2) * (*p2 = 7);
70 1470081 : case INV_W2W13: return (*p1 = 2) * (*p2 = 13);
71 510561 : case INV_W3W7: return (*p1 = 3) * (*p2 = 7);
72 782137 : case INV_W3W3E2:
73 782137 : case INV_W3W3: return (*p1 = 3) * (*p2 = 3);
74 349380 : case INV_W5W7: return (*p1 = 5) * (*p2 = 7);
75 195062 : case INV_W3W13: return (*p1 = 3) * (*p2 = 13);
76 : }
77 718522 : *p1 = *p2 = 1; return 0;
78 : }
79 :
80 : /* Certain invariants require that D not have 2 in it's conductor, but
81 : * this doesn't apply to every invariant with even level so we handle
82 : * it separately */
83 : INLINE int
84 528581 : modinv_odd_conductor(long inv)
85 : {
86 528581 : switch (inv) {
87 70942 : case INV_F:
88 : case INV_W3W3:
89 70942 : case INV_W3W7: return 1;
90 : }
91 457639 : return 0;
92 : }
93 :
94 : long
95 22759094 : modinv_height_factor(long inv)
96 : {
97 22759094 : switch (inv) {
98 1880814 : case INV_J: return 1;
99 1700223 : case INV_G2: return 3;
100 3110886 : case INV_F: return 72;
101 28 : case INV_F2: return 36;
102 538020 : case INV_F3: return 24;
103 49 : case INV_F4: return 18;
104 49 : case INV_F8: return 9;
105 63 : case INV_W2W3: return 72;
106 2361072 : case INV_W3W3: return 36;
107 3548202 : case INV_W2W5: return 54;
108 1341537 : case INV_W2W7: return 48;
109 1386 : case INV_W3W5: return 36;
110 3892770 : case INV_W2W13: return 42;
111 1143429 : case INV_W3W7: return 32;
112 1171891 : case INV_W2W3E2:return 36;
113 149184 : case INV_W2W5E2:return 27;
114 1081990 : case INV_W2W7E2:return 24;
115 49 : case INV_W3W3E2:return 18;
116 837438 : case INV_W5W7: return 24;
117 14 : case INV_W3W13: return 28;
118 : default: pari_err_BUG("modinv_height_factor"); return 0;/*LCOV_EXCL_LINE*/
119 : }
120 : }
121 :
122 : long
123 1907423 : disc_best_modinv(long D)
124 : {
125 : long ret;
126 1907423 : ret = INV_F; if (modinv_good_disc(ret, D)) return ret;
127 1534057 : ret = INV_W2W3; if (modinv_good_disc(ret, D)) return ret;
128 1534057 : ret = INV_W2W5; if (modinv_good_disc(ret, D)) return ret;
129 1238755 : ret = INV_W2W7; if (modinv_good_disc(ret, D)) return ret;
130 1139957 : ret = INV_W2W13; if (modinv_good_disc(ret, D)) return ret;
131 838012 : ret = INV_W3W3; if (modinv_good_disc(ret, D)) return ret;
132 651805 : ret = INV_W2W3E2;if (modinv_good_disc(ret, D)) return ret;
133 579453 : ret = INV_W3W5; if (modinv_good_disc(ret, D)) return ret;
134 579299 : ret = INV_W3W7; if (modinv_good_disc(ret, D)) return ret;
135 511091 : ret = INV_W3W13; if (modinv_good_disc(ret, D)) return ret;
136 511091 : ret = INV_W2W5E2;if (modinv_good_disc(ret, D)) return ret;
137 494753 : ret = INV_F3; if (modinv_good_disc(ret, D)) return ret;
138 464485 : ret = INV_W2W7E2;if (modinv_good_disc(ret, D)) return ret;
139 376656 : ret = INV_W5W7; if (modinv_good_disc(ret, D)) return ret;
140 308581 : ret = INV_W3W3E2;if (modinv_good_disc(ret, D)) return ret;
141 308581 : ret = INV_G2; if (modinv_good_disc(ret, D)) return ret;
142 160517 : return INV_J;
143 : }
144 :
145 : INLINE long
146 44676 : modinv_sparse_factor(long inv)
147 : {
148 44676 : switch (inv) {
149 4855 : case INV_G2:
150 : case INV_F8:
151 : case INV_W3W5:
152 : case INV_W2W5E2:
153 : case INV_W3W3E2:
154 4855 : return 3;
155 625 : case INV_F:
156 625 : return 24;
157 357 : case INV_F2:
158 : case INV_W2W3:
159 357 : return 12;
160 112 : case INV_F3:
161 112 : return 8;
162 1645 : case INV_F4:
163 : case INV_W2W3E2:
164 : case INV_W2W5:
165 : case INV_W3W3:
166 1645 : return 6;
167 1046 : case INV_W2W7:
168 1046 : return 4;
169 2950 : case INV_W2W7E2:
170 : case INV_W2W13:
171 : case INV_W3W7:
172 2950 : return 2;
173 : }
174 33086 : return 1;
175 : }
176 :
177 : #define IQ_FILTER_1MOD3 1
178 : #define IQ_FILTER_2MOD3 2
179 : #define IQ_FILTER_1MOD4 4
180 : #define IQ_FILTER_3MOD4 8
181 :
182 : INLINE long
183 14763 : modinv_pfilter(long inv)
184 : {
185 14763 : switch (inv) {
186 2838 : case INV_G2:
187 : case INV_W3W3:
188 : case INV_W3W3E2:
189 : case INV_W3W5:
190 : case INV_W2W5:
191 : case INV_W2W3E2:
192 : case INV_W2W5E2:
193 : case INV_W5W7:
194 : case INV_W3W13:
195 2838 : return IQ_FILTER_1MOD3; /* ensure unique cube roots */
196 529 : case INV_W2W7:
197 : case INV_F3:
198 529 : return IQ_FILTER_1MOD4; /* ensure at most two 4th/8th roots */
199 972 : case INV_F:
200 : case INV_F2:
201 : case INV_F4:
202 : case INV_F8:
203 : case INV_W2W3:
204 : /* Ensure unique cube roots and at most two 4th/8th roots */
205 972 : return IQ_FILTER_1MOD3 | IQ_FILTER_1MOD4;
206 : }
207 10424 : return 0;
208 : }
209 :
210 : int
211 10681154 : modinv_good_prime(long inv, long p)
212 : {
213 10681154 : switch (inv) {
214 412678 : case INV_G2:
215 : case INV_W2W3E2:
216 : case INV_W3W3:
217 : case INV_W3W3E2:
218 : case INV_W3W5:
219 : case INV_W2W5E2:
220 : case INV_W2W5:
221 412678 : return (p % 3) == 2;
222 410256 : case INV_W2W7:
223 : case INV_F3:
224 410256 : return (p & 3) != 1;
225 392888 : case INV_F2:
226 : case INV_F4:
227 : case INV_F8:
228 : case INV_F:
229 : case INV_W2W3:
230 392888 : return ((p % 3) == 2) && (p & 3) != 1;
231 : }
232 9465332 : return 1;
233 : }
234 :
235 : /* Returns true if the prime p does not divide the conductor of D */
236 : INLINE int
237 3257079 : prime_to_conductor(long D, long p)
238 : {
239 : long b;
240 3257079 : if (p > 2) return (D % (p * p));
241 1250577 : b = D & 0xF;
242 1250577 : return (b && b != 4); /* 2 divides the conductor of D <=> D=0,4 mod 16 */
243 : }
244 :
245 : INLINE GEN
246 3257079 : red_primeform(long D, long p)
247 : {
248 3257079 : pari_sp av = avma;
249 : GEN P;
250 3257079 : if (!prime_to_conductor(D, p)) return NULL;
251 3257079 : P = primeform_u(stoi(D), p); /* primitive since p \nmid conductor */
252 3257079 : return gerepileupto(av, qfbred_i(P));
253 : }
254 :
255 : /* Computes product of primeforms over primes appearing in the prime
256 : * factorization of n (including multiplicity) */
257 : GEN
258 135737 : qfb_nform(long D, long n)
259 : {
260 135737 : pari_sp av = avma;
261 135737 : GEN N = NULL, fa = factoru(n), P = gel(fa,1), E = gel(fa,2);
262 135737 : long i, l = lg(P);
263 :
264 407127 : for (i = 1; i < l; ++i)
265 : {
266 : long j, e;
267 271390 : GEN Q = red_primeform(D, P[i]);
268 271390 : if (!Q) return gc_NULL(av);
269 271390 : e = E[i];
270 271390 : if (i == 1) { N = Q; j = 1; } else j = 0;
271 407127 : for (; j < e; ++j) N = qfbcomp_i(Q, N);
272 : }
273 135737 : return gerepileupto(av, N);
274 : }
275 :
276 : INLINE int
277 1688036 : qfb_is_two_torsion(GEN x)
278 : {
279 3376072 : return equali1(gel(x,1)) || !signe(gel(x,2))
280 3376072 : || equalii(gel(x,1), gel(x,2)) || equalii(gel(x,1), gel(x,3));
281 : }
282 :
283 : /* Returns true iff the products p1*p2, p1*p2^-1, p1^-1*p2, and
284 : * p1^-1*p2^-1 are all distinct in cl(D) */
285 : INLINE int
286 232590 : qfb_distinct_prods(long D, long p1, long p2)
287 : {
288 : GEN P1, P2;
289 :
290 232590 : P1 = red_primeform(D, p1);
291 232590 : if (!P1) return 0;
292 232590 : P1 = qfbsqr_i(P1);
293 :
294 232590 : P2 = red_primeform(D, p2);
295 232590 : if (!P2) return 0;
296 232590 : P2 = qfbsqr_i(P2);
297 :
298 232590 : return !(equalii(gel(P1,1), gel(P2,1)) && absequalii(gel(P1,2), gel(P2,2)));
299 : }
300 :
301 : /* By Corollary 3.1 of Enge-Schertz Constructing elliptic curves over finite
302 : * fields using double eta-quotients, we need p1 != p2 to both be noninert
303 : * and prime to the conductor, and if p1=p2=p we want p split and prime to the
304 : * conductor. We exclude the case that p1=p2 divides the conductor, even
305 : * though this does yield class invariants */
306 : INLINE int
307 5315161 : modinv_double_eta_good_disc(long D, long inv)
308 : {
309 5315161 : pari_sp av = avma;
310 : GEN P;
311 : long i1, i2, p1, p2, N;
312 :
313 5315161 : N = modinv_degree(&p1, &p2, inv);
314 5315161 : if (! N) return 0;
315 5315161 : i1 = kross(D, p1);
316 5315161 : if (i1 < 0) return 0;
317 : /* Exclude ramified case for w_{p,p} */
318 2407366 : if (p1 == p2 && !i1) return 0;
319 2407366 : i2 = kross(D, p2);
320 2407366 : if (i2 < 0) return 0;
321 : /* this also verifies that p1 is prime to the conductor */
322 1371341 : P = red_primeform(D, p1);
323 1371341 : if (!P || gequal1(gel(P,1)) /* don't allow p1 to be principal */
324 : /* if p1 is unramified, require it to have order > 2 */
325 1371341 : || (i1 && qfb_is_two_torsion(P))) return gc_bool(av,0);
326 1369717 : if (p1 == p2) /* if p1=p2 we need p1*p1 to be distinct from its inverse */
327 220549 : return gc_bool(av, !qfb_is_two_torsion(qfbsqr_i(P)));
328 :
329 : /* this also verifies that p2 is prime to the conductor */
330 1149168 : P = red_primeform(D, p2);
331 1149168 : if (!P || gequal1(gel(P,1)) /* don't allow p2 to be principal */
332 : /* if p2 is unramified, require it to have order > 2 */
333 1149168 : || (i2 && qfb_is_two_torsion(P))) return gc_bool(av,0);
334 1147705 : set_avma(av);
335 :
336 : /* if p1 and p2 are split, we also require p1*p2, p1*p2^-1, p1^-1*p2,
337 : * and p1^-1*p2^-1 to be distinct */
338 1147705 : if (i1>0 && i2>0 && !qfb_distinct_prods(D, p1, p2)) return gc_bool(av,0);
339 1144589 : if (!i1 && !i2) {
340 : /* if both p1 and p2 are ramified, make sure their product is not
341 : * principal */
342 135359 : P = qfb_nform(D, N);
343 135359 : if (equali1(gel(P,1))) return gc_bool(av,0);
344 135107 : set_avma(av);
345 : }
346 1144337 : return 1;
347 : }
348 :
349 : /* Assumes D is a good discriminant for inv, which implies that the
350 : * level is prime to the conductor */
351 : long
352 504 : modinv_ramified(long D, long inv, long *pN)
353 : {
354 504 : long p1, p2; *pN = modinv_degree(&p1, &p2, inv);
355 504 : if (*pN <= 1) return 0;
356 504 : return !(D % p1) && !(D % p2);
357 : }
358 :
359 : int
360 14843104 : modinv_good_disc(long inv, long D)
361 : {
362 14843104 : switch (inv) {
363 880013 : case INV_J:
364 880013 : return 1;
365 463624 : case INV_G2:
366 463624 : return !!(D % 3);
367 502845 : case INV_F3:
368 502845 : return (-D & 7) == 7;
369 2062667 : case INV_F:
370 : case INV_F2:
371 : case INV_F4:
372 : case INV_F8:
373 2062667 : return ((-D & 7) == 7) && (D % 3);
374 622069 : case INV_W3W5:
375 622069 : return (D % 3) && modinv_double_eta_good_disc(D, inv);
376 335664 : case INV_W3W3E2:
377 335664 : return (D % 3) && modinv_double_eta_good_disc(D, inv);
378 897015 : case INV_W3W3:
379 897015 : return (D & 1) && (D % 3) && modinv_double_eta_good_disc(D, inv);
380 667688 : case INV_W2W3E2:
381 667688 : return (D % 3) && modinv_double_eta_good_disc(D, inv);
382 1554721 : case INV_W2W3:
383 1554721 : return ((-D & 7) == 7) && (D % 3) && modinv_double_eta_good_disc(D, inv);
384 1581685 : case INV_W2W5:
385 1581685 : return ((-D % 80) != 20) && (D % 3) && modinv_double_eta_good_disc(D, inv);
386 549171 : case INV_W2W5E2:
387 549171 : return (D % 3) && modinv_double_eta_good_disc(D, inv);
388 566027 : case INV_W2W7E2:
389 566027 : return ((-D % 112) != 84) && modinv_double_eta_good_disc(D, inv);
390 1324607 : case INV_W2W7:
391 1324607 : return ((-D & 7) == 7) && modinv_double_eta_good_disc(D, inv);
392 1196839 : case INV_W2W13:
393 1196839 : return ((-D % 208) != 52) && modinv_double_eta_good_disc(D, inv);
394 666806 : case INV_W3W7:
395 666806 : return (D & 1) && (-D % 21) && modinv_double_eta_good_disc(D, inv);
396 450975 : case INV_W5W7: /* NB: This is a guess; avs doesn't have an entry */
397 450975 : return (D % 3) && modinv_double_eta_good_disc(D, inv);
398 520688 : case INV_W3W13: /* NB: This is a guess; avs doesn't have an entry */
399 520688 : return (D & 1) && (D % 3) && modinv_double_eta_good_disc(D, inv);
400 : }
401 0 : pari_err_BUG("modinv_good_discriminant");
402 : return 0;/*LCOV_EXCL_LINE*/
403 : }
404 :
405 : int
406 784 : modinv_is_Weber(long inv)
407 : {
408 0 : return inv == INV_F || inv == INV_F2 || inv == INV_F3 || inv == INV_F4
409 784 : || inv == INV_F8;
410 : }
411 :
412 : int
413 235965 : modinv_is_double_eta(long inv)
414 : {
415 235965 : switch (inv) {
416 31319 : case INV_W2W3:
417 : case INV_W2W3E2:
418 : case INV_W2W5:
419 : case INV_W2W5E2:
420 : case INV_W2W7:
421 : case INV_W2W7E2:
422 : case INV_W2W13:
423 : case INV_W3W3:
424 : case INV_W3W3E2:
425 : case INV_W3W5:
426 : case INV_W3W7:
427 : case INV_W5W7:
428 : case INV_W3W13:
429 31319 : return 1;
430 : }
431 204646 : return 0;
432 : }
433 :
434 : /* END Code from "class_inv.h" */
435 :
436 : INLINE int
437 9868 : safe_abs_sqrt(ulong *r, ulong x, ulong p, ulong pi, ulong s2)
438 : {
439 9868 : if (krouu(x, p) == -1)
440 : {
441 4621 : if (p%4 == 1) return 0;
442 4621 : x = Fl_neg(x, p);
443 : }
444 9868 : *r = Fl_sqrt_pre_i(x, s2, p, pi);
445 9868 : return 1;
446 : }
447 :
448 : INLINE int
449 5094 : eighth_root(ulong *r, ulong x, ulong p, ulong pi, ulong s2)
450 : {
451 : ulong s;
452 5094 : if (krouu(x, p) == -1) return 0;
453 2710 : s = Fl_sqrt_pre_i(x, s2, p, pi);
454 2710 : return safe_abs_sqrt(&s, s, p, pi, s2) && safe_abs_sqrt(r, s, p, pi, s2);
455 : }
456 :
457 : INLINE ulong
458 2968 : modinv_f_from_j(ulong j, ulong p, ulong pi, ulong s2, long only_residue)
459 : {
460 2968 : pari_sp av = avma;
461 : GEN pol, r;
462 : long i;
463 2968 : ulong g2, f = ULONG_MAX;
464 :
465 : /* f^8 must be a root of X^3 - \gamma_2 X - 16 */
466 2968 : g2 = Fl_sqrtl_pre(j, 3, p, pi);
467 :
468 2968 : pol = mkvecsmall5(0UL, Fl_neg(16 % p, p), Fl_neg(g2, p), 0UL, 1UL);
469 2968 : r = Flx_roots_pre(pol, p, pi);
470 5554 : for (i = 1; i < lg(r); ++i)
471 5554 : if (only_residue)
472 1179 : { if (krouu(r[i], p) != -1) return gc_ulong(av,r[i]); }
473 4375 : else if (eighth_root(&f, r[i], p, pi, s2)) return gc_ulong(av,f);
474 0 : pari_err_BUG("modinv_f_from_j");
475 : return 0;/*LCOV_EXCL_LINE*/
476 : }
477 :
478 : INLINE ulong
479 358 : modinv_f3_from_j(ulong j, ulong p, ulong pi, ulong s2)
480 : {
481 358 : pari_sp av = avma;
482 : GEN pol, r;
483 : long i;
484 358 : ulong f = ULONG_MAX;
485 :
486 358 : pol = mkvecsmall5(0UL,
487 358 : Fl_neg(4096 % p, p), Fl_sub(768 % p, j, p), Fl_neg(48 % p, p), 1UL);
488 358 : r = Flx_roots_pre(pol, p, pi);
489 719 : for (i = 1; i < lg(r); ++i)
490 719 : if (eighth_root(&f, r[i], p, pi, s2)) return gc_ulong(av,f);
491 0 : pari_err_BUG("modinv_f3_from_j");
492 : return 0;/*LCOV_EXCL_LINE*/
493 : }
494 :
495 : /* Return the exponent e for the double-eta "invariant" w such that
496 : * w^e is a class invariant. For example w2w3^12 is a class
497 : * invariant, so double_eta_exponent(INV_W2W3) is 12 and
498 : * double_eta_exponent(INV_W2W3E2) is 6. */
499 : INLINE ulong
500 54036 : double_eta_exponent(long inv)
501 : {
502 54036 : switch (inv) {
503 2451 : case INV_W2W3: return 12;
504 13257 : case INV_W2W3E2:
505 : case INV_W2W5:
506 13257 : case INV_W3W3: return 6;
507 9768 : case INV_W2W7: return 4;
508 5805 : case INV_W3W5:
509 : case INV_W2W5E2:
510 5805 : case INV_W3W3E2: return 3;
511 15553 : case INV_W2W7E2:
512 : case INV_W2W13:
513 15553 : case INV_W3W7: return 2;
514 7202 : default: return 1;
515 : }
516 : }
517 :
518 : INLINE ulong
519 49 : weber_exponent(long inv)
520 : {
521 49 : switch (inv)
522 : {
523 42 : case INV_F: return 24;
524 0 : case INV_F2: return 12;
525 7 : case INV_F3: return 8;
526 0 : case INV_F4: return 6;
527 0 : case INV_F8: return 3;
528 0 : default: return 1;
529 : }
530 : }
531 :
532 : INLINE ulong
533 29409 : double_eta_power(long inv, ulong w, ulong p, ulong pi)
534 : {
535 29409 : return Fl_powu_pre(w, double_eta_exponent(inv), p, pi);
536 : }
537 :
538 : static GEN
539 161 : double_eta_raw_to_Fp(GEN f, GEN p)
540 : {
541 161 : GEN u = FpX_red(RgV_to_RgX(gel(f,1), 0), p);
542 161 : GEN v = FpX_red(RgV_to_RgX(gel(f,2), 0), p);
543 161 : return mkvec3(u, v, gel(f,3));
544 : }
545 :
546 : /* Given a root x of polclass(D, inv) modulo N, returns a root of polclass(D,0)
547 : * modulo N by plugging x to a modular polynomial. For double-eta quotients,
548 : * this is done by plugging x into the modular polynomial Phi(INV_WpWq, j)
549 : * Enge, Morain 2013: Generalised Weber Functions. */
550 : GEN
551 1057 : Fp_modinv_to_j(GEN x, long inv, GEN p)
552 : {
553 1057 : switch(inv)
554 : {
555 392 : case INV_J: return Fp_red(x, p);
556 455 : case INV_G2: return Fp_powu(x, 3, p);
557 49 : case INV_F: case INV_F2: case INV_F3: case INV_F4: case INV_F8:
558 : {
559 49 : GEN xe = Fp_powu(x, weber_exponent(inv), p);
560 49 : return Fp_div(Fp_powu(subiu(xe, 16), 3, p), xe, p);
561 : }
562 161 : default:
563 161 : if (modinv_is_double_eta(inv))
564 : {
565 161 : GEN xe = Fp_powu(x, double_eta_exponent(inv), p);
566 161 : GEN uvk = double_eta_raw_to_Fp(double_eta_raw(inv), p);
567 161 : GEN J0 = FpX_eval(gel(uvk,1), xe, p);
568 161 : GEN J1 = FpX_eval(gel(uvk,2), xe, p);
569 161 : GEN J2 = Fp_pow(xe, gel(uvk,3), p);
570 161 : GEN phi = mkvec3(J0, J1, J2);
571 161 : return FpX_oneroot(RgX_to_FpX(RgV_to_RgX(phi,1), p),p);
572 : }
573 : pari_err_BUG("Fp_modinv_to_j"); return NULL;/* LCOV_EXCL_LINE */
574 : }
575 : }
576 :
577 : /* Assuming p = 2 (mod 3) and p = 3 (mod 4): if the two 12th roots of
578 : * x (mod p) exist, set *r to one of them and return 1, otherwise
579 : * return 0 (without touching *r). */
580 : INLINE int
581 898 : twelth_root(ulong *r, ulong x, ulong p, ulong pi, ulong s2)
582 : {
583 898 : ulong t = Fl_sqrtl_pre(x, 3, p, pi);
584 898 : if (krouu(t, p) == -1) return 0;
585 850 : t = Fl_sqrt_pre_i(t, s2, p, pi);
586 850 : return safe_abs_sqrt(r, t, p, pi, s2);
587 : }
588 :
589 : INLINE int
590 5493 : sixth_root(ulong *r, ulong x, ulong p, ulong pi, ulong s2)
591 : {
592 5493 : ulong t = Fl_sqrtl_pre(x, 3, p, pi);
593 5493 : if (krouu(t, p) == -1) return 0;
594 5311 : *r = Fl_sqrt_pre_i(t, s2, p, pi);
595 5311 : return 1;
596 : }
597 :
598 : INLINE int
599 3964 : fourth_root(ulong *r, ulong x, ulong p, ulong pi, ulong s2)
600 : {
601 : ulong s;
602 3964 : if (krouu(x, p) == -1) return 0;
603 3598 : s = Fl_sqrt_pre_i(x, s2, p, pi);
604 3598 : return safe_abs_sqrt(r, s, p, pi, s2);
605 : }
606 :
607 : INLINE int
608 24466 : double_eta_root(long inv, ulong *r, ulong w, ulong p, ulong pi, ulong s2)
609 : {
610 24466 : switch (double_eta_exponent(inv)) {
611 898 : case 12: return twelth_root(r, w, p, pi, s2);
612 5493 : case 6: return sixth_root(r, w, p, pi, s2);
613 3964 : case 4: return fourth_root(r, w, p, pi, s2);
614 2596 : case 3: *r = Fl_sqrtl_pre(w, 3, p, pi); return 1;
615 8449 : case 2: return krouu(w, p) != -1 && !!(*r = Fl_sqrt_pre_i(w, s2, p, pi));
616 3066 : default: *r = w; return 1; /* case 1 */
617 : }
618 : }
619 :
620 : /* F = double_eta_Fl(inv, p) */
621 : static GEN
622 41309 : Flx_double_eta_xpoly(GEN F, ulong j, ulong p, ulong pi)
623 : {
624 41309 : GEN u = gel(F,1), v = gel(F,2), w;
625 41309 : long i, k = itos(gel(F,3)), lu = lg(u), lv = lg(v), lw = lu + 1;
626 :
627 41309 : w = cgetg(lw, t_VECSMALL); /* lu >= max(lv,k) */
628 41309 : w[1] = 0; /* variable number */
629 1156874 : for (i = 1; i < lv; i++) uel(w, i+1) = Fl_add(uel(u,i), Fl_mul_pre(j, uel(v,i), p, pi), p);
630 82616 : for ( ; i < lu; i++) uel(w, i+1) = uel(u,i);
631 41308 : uel(w, k+2) = Fl_add(uel(w, k+2), Fl_sqr_pre(j, p, pi), p);
632 41308 : return Flx_renormalize(w, lw);
633 : }
634 :
635 : /* F = double_eta_Fl(inv, p) */
636 : static GEN
637 29409 : Flx_double_eta_jpoly(GEN F, ulong x, ulong p, ulong pi)
638 : {
639 29409 : pari_sp av = avma;
640 29409 : GEN u = gel(F,1), v = gel(F,2), xs;
641 29409 : long k = itos(gel(F,3));
642 : ulong a, b, c;
643 :
644 : /* u is always longest and the length is bigger than k */
645 29409 : xs = Fl_powers_pre(x, lg(u) - 1, p, pi);
646 29409 : c = Flv_dotproduct_pre(u, xs, p, pi);
647 29409 : b = Flv_dotproduct_pre(v, xs, p, pi);
648 29409 : a = uel(xs, k + 1);
649 29409 : set_avma(av);
650 29409 : return mkvecsmall4(0, c, b, a);
651 : }
652 :
653 : /* reduce F = double_eta_raw(inv) mod p */
654 : static GEN
655 29662 : double_eta_raw_to_Fl(GEN f, ulong p)
656 : {
657 29662 : GEN u = ZV_to_Flv(gel(f,1), p);
658 29662 : GEN v = ZV_to_Flv(gel(f,2), p);
659 29662 : return mkvec3(u, v, gel(f,3));
660 : }
661 : /* double_eta_raw(inv) mod p */
662 : static GEN
663 23503 : double_eta_Fl(long inv, ulong p)
664 23503 : { return double_eta_raw_to_Fl(double_eta_raw(inv), p); }
665 :
666 : /* Go through roots of Psi(X,j) until one has an double_eta_exponent(inv)-th
667 : * root, and return that root. F = double_eta_Fl(inv,p) */
668 : INLINE ulong
669 5697 : modinv_double_eta_from_j(GEN F, long inv, ulong j, ulong p, ulong pi, ulong s2)
670 : {
671 5697 : pari_sp av = avma;
672 : long i;
673 5697 : ulong f = ULONG_MAX;
674 5697 : GEN a = Flx_double_eta_xpoly(F, j, p, pi);
675 5697 : a = Flx_roots_pre(a, p, pi);
676 6661 : for (i = 1; i < lg(a); ++i)
677 6661 : if (double_eta_root(inv, &f, uel(a, i), p, pi, s2)) break;
678 5697 : if (i == lg(a)) pari_err_BUG("modinv_double_eta_from_j");
679 5697 : return gc_ulong(av,f);
680 : }
681 :
682 : /* assume j1 != j2 */
683 : static long
684 12109 : modinv_double_eta_from_2j(
685 : ulong *r, long inv, ulong j1, ulong j2, ulong p, ulong pi, ulong s2)
686 : {
687 12109 : GEN f, g, d, F = double_eta_Fl(inv, p);
688 12109 : f = Flx_double_eta_xpoly(F, j1, p, pi);
689 12109 : g = Flx_double_eta_xpoly(F, j2, p, pi);
690 12109 : d = Flx_gcd(f, g, p);
691 : /* we should have deg(d) = 1, but because j1 or j2 may not have the correct
692 : * endomorphism ring, we use the less strict conditional underneath */
693 24218 : return (degpol(d) > 2 || (*r = Flx_oneroot_pre(d, p, pi)) == p
694 24218 : || ! double_eta_root(inv, r, *r, p, pi, s2));
695 : }
696 :
697 : long
698 12294 : modfn_unambiguous_root(ulong *r, long inv, ulong j0, norm_eqn_t ne, GEN jdb)
699 : {
700 12294 : pari_sp av = avma;
701 12294 : long p1, p2, v = ne->v, p1_depth;
702 12294 : ulong j1, p = ne->p, pi = ne->pi, s2 = ne->s2;
703 : GEN phi;
704 :
705 12294 : (void) modinv_degree(&p1, &p2, inv);
706 12294 : p1_depth = u_lval(v, p1);
707 :
708 12294 : phi = polmodular_db_getp(jdb, p1, p);
709 12295 : if (!next_surface_nbr(&j1, phi, p1, p1_depth, j0, NULL, p, pi))
710 0 : pari_err_BUG("modfn_unambiguous_root");
711 12294 : if (p2 == p1) {
712 2015 : if (!next_surface_nbr(&j1, phi, p1, p1_depth, j1, &j0, p, pi))
713 0 : pari_err_BUG("modfn_unambiguous_root");
714 : } else {
715 10279 : long p2_depth = u_lval(v, p2);
716 10279 : phi = polmodular_db_getp(jdb, p2, p);
717 10280 : if (!next_surface_nbr(&j1, phi, p2, p2_depth, j1, NULL, p, pi))
718 0 : pari_err_BUG("modfn_unambiguous_root");
719 : }
720 14043 : return gc_long(av, j1 != j0
721 12279 : && !modinv_double_eta_from_2j(r, inv, j0, j1, p, pi, s2));
722 : }
723 :
724 : ulong
725 194131 : modfn_root(ulong j, norm_eqn_t ne, long inv)
726 : {
727 194131 : ulong f, p = ne->p, pi = ne->pi, s2 = ne->s2;
728 194131 : switch (inv) {
729 182740 : case INV_J: return j;
730 8065 : case INV_G2: return Fl_sqrtl_pre(j, 3, p, pi);
731 1603 : case INV_F: return modinv_f_from_j(j, p, pi, s2, 0);
732 196 : case INV_F2:
733 196 : f = modinv_f_from_j(j, p, pi, s2, 0);
734 196 : return Fl_sqr_pre(f, p, pi);
735 358 : case INV_F3: return modinv_f3_from_j(j, p, pi, s2);
736 553 : case INV_F4:
737 553 : f = modinv_f_from_j(j, p, pi, s2, 0);
738 553 : return Fl_sqr_pre(Fl_sqr_pre(f, p, pi), p, pi);
739 616 : case INV_F8: return modinv_f_from_j(j, p, pi, s2, 1);
740 : }
741 0 : if (modinv_is_double_eta(inv))
742 : {
743 0 : pari_sp av = avma;
744 0 : ulong f = modinv_double_eta_from_j(double_eta_Fl(inv,p), inv, j, p, pi, s2);
745 0 : return gc_ulong(av,f);
746 : }
747 : pari_err_BUG("modfn_root"); return ULONG_MAX;/*LCOV_EXCL_LINE*/
748 : }
749 :
750 : /* F = double_eta_raw(inv) */
751 : long
752 6159 : modinv_j_from_2double_eta(
753 : GEN F, long inv, ulong x0, ulong x1, ulong p, ulong pi)
754 : {
755 : GEN f, g, d;
756 :
757 6159 : x0 = double_eta_power(inv, x0, p, pi);
758 6159 : x1 = double_eta_power(inv, x1, p, pi);
759 6159 : F = double_eta_raw_to_Fl(F, p);
760 6159 : f = Flx_double_eta_jpoly(F, x0, p, pi);
761 6159 : g = Flx_double_eta_jpoly(F, x1, p, pi);
762 6159 : d = Flx_gcd(f, g, p); /* >= 1 */
763 6159 : return degpol(d) == 1;
764 : }
765 :
766 : /* x root of (X^24 - 16)^3 - X^24 * j = 0 => j = (x^24 - 16)^3 / x^24 */
767 : INLINE ulong
768 1858 : modinv_j_from_f(ulong x, ulong n, ulong p, ulong pi)
769 : {
770 1858 : ulong x24 = Fl_powu_pre(x, 24 / n, p, pi);
771 1858 : return Fl_div(Fl_powu_pre(Fl_sub(x24, 16 % p, p), 3, p, pi), x24, p);
772 : }
773 : /* should never be called if modinv_double_eta(inv) is true */
774 : INLINE ulong
775 66151 : modfn_preimage(ulong x, ulong p, ulong pi, long inv)
776 : {
777 66151 : switch (inv) {
778 58435 : case INV_J: return x;
779 5858 : case INV_G2: return Fl_powu_pre(x, 3, p, pi);
780 : /* NB: could replace these with a single call modinv_j_from_f(x,inv,p,pi)
781 : * but avoid the dependence on the actual value of inv */
782 654 : case INV_F: return modinv_j_from_f(x, 1, p, pi);
783 196 : case INV_F2: return modinv_j_from_f(x, 2, p, pi);
784 168 : case INV_F3: return modinv_j_from_f(x, 3, p, pi);
785 392 : case INV_F4: return modinv_j_from_f(x, 4, p, pi);
786 448 : case INV_F8: return modinv_j_from_f(x, 8, p, pi);
787 : }
788 : pari_err_BUG("modfn_preimage"); return ULONG_MAX;/*LCOV_EXCL_LINE*/
789 : }
790 :
791 : /* SECTION: class group bb_group. */
792 :
793 : INLINE GEN
794 135735 : mkqfis(GEN a, ulong b, ulong c, GEN D) { retmkqfb(a, utoi(b), utoi(c), D); }
795 :
796 : /* SECTION: dot-product-like functions on Fl's with precomputed inverse. */
797 :
798 : /* Computes x0y1 + y0x1 (mod p); assumes p < 2^63. */
799 : INLINE ulong
800 55928642 : Fl_addmul2(
801 : ulong x0, ulong x1, ulong y0, ulong y1,
802 : ulong p, ulong pi)
803 : {
804 55928642 : return Fl_addmulmul_pre(x0,y1,y0,x1,p,pi);
805 : }
806 :
807 : /* Computes x0y2 + x1y1 + x2y0 (mod p); assumes p < 2^62. */
808 : INLINE ulong
809 9773456 : Fl_addmul3(
810 : ulong x0, ulong x1, ulong x2, ulong y0, ulong y1, ulong y2,
811 : ulong p, ulong pi)
812 : {
813 : ulong l0, l1, h0, h1;
814 : LOCAL_OVERFLOW;
815 : LOCAL_HIREMAINDER;
816 9773456 : l0 = mulll(x0, y2); h0 = hiremainder;
817 9773456 : l1 = mulll(x1, y1); h1 = hiremainder;
818 9773456 : l1 = addll(l0, l1); h1 = addllx(h0, h1);
819 9773456 : l0 = mulll(x2, y0); h0 = hiremainder;
820 9773456 : l1 = addll(l0, l1); h1 = addllx(h0, h1);
821 9773456 : return remll_pre(h1, l1, p, pi);
822 : }
823 :
824 : /* Computes x0y3 + x1y2 + x2y1 + x3y0 (mod p); assumes p < 2^62. */
825 : INLINE ulong
826 5021640 : Fl_addmul4(
827 : ulong x0, ulong x1, ulong x2, ulong x3,
828 : ulong y0, ulong y1, ulong y2, ulong y3,
829 : ulong p, ulong pi)
830 : {
831 : ulong l0, l1, h0, h1;
832 : LOCAL_OVERFLOW;
833 : LOCAL_HIREMAINDER;
834 5021640 : l0 = mulll(x0, y3); h0 = hiremainder;
835 5021640 : l1 = mulll(x1, y2); h1 = hiremainder;
836 5021640 : l1 = addll(l0, l1); h1 = addllx(h0, h1);
837 5021640 : l0 = mulll(x2, y1); h0 = hiremainder;
838 5021640 : l1 = addll(l0, l1); h1 = addllx(h0, h1);
839 5021640 : l0 = mulll(x3, y0); h0 = hiremainder;
840 5021640 : l1 = addll(l0, l1); h1 = addllx(h0, h1);
841 5021640 : return remll_pre(h1, l1, p, pi);
842 : }
843 :
844 : /* Computes x0y4 + x1y3 + x2y2 + x3y1 + x4y0 (mod p); assumes p < 2^62. */
845 : INLINE ulong
846 25000077 : Fl_addmul5(
847 : ulong x0, ulong x1, ulong x2, ulong x3, ulong x4,
848 : ulong y0, ulong y1, ulong y2, ulong y3, ulong y4,
849 : ulong p, ulong pi)
850 : {
851 : ulong l0, l1, h0, h1;
852 : LOCAL_OVERFLOW;
853 : LOCAL_HIREMAINDER;
854 25000077 : l0 = mulll(x0, y4); h0 = hiremainder;
855 25000077 : l1 = mulll(x1, y3); h1 = hiremainder;
856 25000077 : l1 = addll(l0, l1); h1 = addllx(h0, h1);
857 25000077 : l0 = mulll(x2, y2); h0 = hiremainder;
858 25000077 : l1 = addll(l0, l1); h1 = addllx(h0, h1);
859 25000077 : l0 = mulll(x3, y1); h0 = hiremainder;
860 25000077 : l1 = addll(l0, l1); h1 = addllx(h0, h1);
861 25000077 : l0 = mulll(x4, y0); h0 = hiremainder;
862 25000077 : l1 = addll(l0, l1); h1 = addllx(h0, h1);
863 25000077 : return remll_pre(h1, l1, p, pi);
864 : }
865 :
866 : /* A polmodular database for a given class invariant consists of a t_VEC whose
867 : * L-th entry is 0 or a GEN pointing to Phi_L. This function produces a pair
868 : * of databases corresponding to the j-invariant and inv */
869 : GEN
870 21482 : polmodular_db_init(long inv)
871 : {
872 21482 : const long LEN = 32;
873 21482 : GEN res = cgetg_block(3, t_VEC);
874 21482 : gel(res, 1) = zerovec_block(LEN);
875 21482 : gel(res, 2) = (inv == INV_J)? gen_0: zerovec_block(LEN);
876 21482 : return res;
877 : }
878 :
879 : void
880 25103 : polmodular_db_add_level(GEN *DB, long L, long inv)
881 : {
882 25103 : GEN db = gel(*DB, (inv == INV_J)? 1: 2);
883 25103 : long max_L = lg(db) - 1;
884 25103 : if (L > max_L) {
885 : GEN newdb;
886 43 : long i, newlen = 2 * L;
887 :
888 43 : newdb = cgetg_block(newlen + 1, t_VEC);
889 1419 : for (i = 1; i <= max_L; ++i) gel(newdb, i) = gel(db, i);
890 2941 : for ( ; i <= newlen; ++i) gel(newdb, i) = gen_0;
891 43 : killblock(db);
892 43 : gel(*DB, (inv == INV_J)? 1: 2) = db = newdb;
893 : }
894 25103 : if (typ(gel(db, L)) == t_INT) {
895 8268 : pari_sp av = avma;
896 8268 : GEN x = polmodular0_ZM(L, inv, NULL, NULL, 0, DB); /* may set db[L] */
897 8268 : GEN y = gel(db, L);
898 8268 : gel(db, L) = gclone(x);
899 8268 : if (typ(y) != t_INT) gunclone(y);
900 8268 : set_avma(av);
901 : }
902 25103 : }
903 :
904 : void
905 4976 : polmodular_db_add_levels(GEN *db, long *levels, long k, long inv)
906 : {
907 : long i;
908 10494 : for (i = 0; i < k; ++i) polmodular_db_add_level(db, levels[i], inv);
909 4976 : }
910 :
911 : GEN
912 354700 : polmodular_db_for_inv(GEN db, long inv) { return gel(db, (inv==INV_J)? 1: 2); }
913 :
914 : /* TODO: Also cache modpoly mod p for most recent p (avoid repeated
915 : * reductions in, for example, polclass.c:oneroot_of_classpoly(). */
916 : GEN
917 516619 : polmodular_db_getp(GEN db, long L, ulong p)
918 : {
919 516619 : GEN f = gel(db, L);
920 516619 : if (isintzero(f)) pari_err_BUG("polmodular_db_getp");
921 516616 : return ZM_to_Flm(f, p);
922 : }
923 :
924 : /* SECTION: Table of discriminants to use. */
925 : typedef struct {
926 : long GENcode0; /* used when serializing the struct to a t_VECSMALL */
927 : long inv; /* invariant */
928 : long L; /* modpoly level */
929 : long D0; /* fundamental discriminant */
930 : long D1; /* chosen discriminant */
931 : long L0; /* first generator norm */
932 : long L1; /* second generator norm */
933 : long n1; /* order of L0 in cl(D1) */
934 : long n2; /* order of L0 in cl(D2) where D2 = L^2 D1 */
935 : long dl1; /* m such that L0^m = L in cl(D1) */
936 : long dl2_0; /* These two are (m, n) such that L0^m L1^n = form of norm L^2 in D2 */
937 : long dl2_1; /* This n is always 1 or 0. */
938 : /* this part is not serialized */
939 : long nprimes; /* number of primes needed for D1 */
940 : long cost; /* cost to enumerate subgroup of cl(L^2D): subgroup size is n2 if L1=0, 2*n2 o.w. */
941 : long bits;
942 : ulong *primes;
943 : ulong *traces;
944 : } disc_info;
945 :
946 : #define MODPOLY_MAX_DCNT 64
947 :
948 : /* Flag for last parameter of discriminant_with_classno_at_least.
949 : * Warning: ignoring the sparse factor makes everything slower by
950 : * something like (sparse factor)^3. */
951 : #define USE_SPARSE_FACTOR 0
952 : #define IGNORE_SPARSE_FACTOR 1
953 :
954 : static long
955 : discriminant_with_classno_at_least(disc_info Ds[MODPOLY_MAX_DCNT], long L,
956 : long inv, GEN Q, long ignore_sparse);
957 :
958 : /* SECTION: evaluation functions for modular polynomials of small level. */
959 :
960 : /* Based on phi2_eval_ff() in Sutherland's classpoly programme.
961 : * Calculates Phi_2(X, j) (mod p) with 6M+7A (4 reductions, not
962 : * counting those for Phi_2) */
963 : INLINE GEN
964 26400506 : Flm_Fl_phi2_evalx(GEN phi2, ulong j, ulong p, ulong pi)
965 : {
966 26400506 : GEN res = cgetg(6, t_VECSMALL);
967 : ulong j2, t1;
968 :
969 26361114 : res[1] = 0; /* variable name */
970 :
971 26361114 : j2 = Fl_sqr_pre(j, p, pi);
972 26401684 : t1 = Fl_add(j, coeff(phi2, 3, 1), p);
973 26398548 : t1 = Fl_addmul2(j, j2, t1, coeff(phi2, 2, 1), p, pi);
974 26460248 : res[2] = Fl_add(t1, coeff(phi2, 1, 1), p);
975 :
976 26431735 : t1 = Fl_addmul2(j, j2, coeff(phi2, 3, 2), coeff(phi2, 2, 2), p, pi);
977 26478881 : res[3] = Fl_add(t1, coeff(phi2, 2, 1), p);
978 :
979 26451330 : t1 = Fl_mul_pre(j, coeff(phi2, 3, 2), p, pi);
980 26442338 : t1 = Fl_add(t1, coeff(phi2, 3, 1), p);
981 26422503 : res[4] = Fl_sub(t1, j2, p);
982 :
983 26398114 : res[5] = 1;
984 26398114 : return res;
985 : }
986 :
987 : /* Based on phi3_eval_ff() in Sutherland's classpoly programme.
988 : * Calculates Phi_3(X, j) (mod p) with 13M+13A (6 reductions, not
989 : * counting those for Phi_3) */
990 : INLINE GEN
991 3259741 : Flm_Fl_phi3_evalx(GEN phi3, ulong j, ulong p, ulong pi)
992 : {
993 3259741 : GEN res = cgetg(7, t_VECSMALL);
994 : ulong j2, j3, t1;
995 :
996 3258167 : res[1] = 0; /* variable name */
997 :
998 3258167 : j2 = Fl_sqr_pre(j, p, pi);
999 3260881 : j3 = Fl_mul_pre(j, j2, p, pi);
1000 :
1001 3261953 : t1 = Fl_add(j, coeff(phi3, 4, 1), p);
1002 6527218 : res[2] = Fl_addmul3(j, j2, j3, t1,
1003 3261776 : coeff(phi3, 3, 1), coeff(phi3, 2, 1), p, pi);
1004 :
1005 3265442 : t1 = Fl_addmul3(j, j2, j3, coeff(phi3, 4, 2),
1006 3265442 : coeff(phi3, 3, 2), coeff(phi3, 2, 2), p, pi);
1007 3264957 : res[3] = Fl_add(t1, coeff(phi3, 2, 1), p);
1008 :
1009 3263834 : t1 = Fl_addmul3(j, j2, j3, coeff(phi3, 4, 3),
1010 3263834 : coeff(phi3, 3, 3), coeff(phi3, 3, 2), p, pi);
1011 3265883 : res[4] = Fl_add(t1, coeff(phi3, 3, 1), p);
1012 :
1013 3264793 : t1 = Fl_addmul2(j, j2, coeff(phi3, 4, 3), coeff(phi3, 4, 2), p, pi);
1014 3265596 : t1 = Fl_add(t1, coeff(phi3, 4, 1), p);
1015 3264237 : res[5] = Fl_sub(t1, j3, p);
1016 :
1017 3263208 : res[6] = 1;
1018 3263208 : return res;
1019 : }
1020 :
1021 : /* Based on phi5_eval_ff() in Sutherland's classpoly programme.
1022 : * Calculates Phi_5(X, j) (mod p) with 33M+31A (10 reductions, not
1023 : * counting those for Phi_5) */
1024 : INLINE GEN
1025 5013695 : Flm_Fl_phi5_evalx(GEN phi5, ulong j, ulong p, ulong pi)
1026 : {
1027 5013695 : GEN res = cgetg(9, t_VECSMALL);
1028 : ulong j2, j3, j4, j5, t1;
1029 :
1030 5009695 : res[1] = 0; /* variable name */
1031 :
1032 5009695 : j2 = Fl_sqr_pre(j, p, pi);
1033 5014046 : j3 = Fl_mul_pre(j, j2, p, pi);
1034 5015849 : j4 = Fl_sqr_pre(j2, p, pi);
1035 5015819 : j5 = Fl_mul_pre(j, j4, p, pi);
1036 :
1037 5018396 : t1 = Fl_add(j, coeff(phi5, 6, 1), p);
1038 5017596 : t1 = Fl_addmul5(j, j2, j3, j4, j5, t1,
1039 5017596 : coeff(phi5, 5, 1), coeff(phi5, 4, 1),
1040 5017596 : coeff(phi5, 3, 1), coeff(phi5, 2, 1),
1041 : p, pi);
1042 5022954 : res[2] = Fl_add(t1, coeff(phi5, 1, 1), p);
1043 :
1044 5020555 : t1 = Fl_addmul5(j, j2, j3, j4, j5,
1045 5020555 : coeff(phi5, 6, 2), coeff(phi5, 5, 2),
1046 5020555 : coeff(phi5, 4, 2), coeff(phi5, 3, 2), coeff(phi5, 2, 2),
1047 : p, pi);
1048 5023388 : res[3] = Fl_add(t1, coeff(phi5, 2, 1), p);
1049 :
1050 5020431 : t1 = Fl_addmul5(j, j2, j3, j4, j5,
1051 5020431 : coeff(phi5, 6, 3), coeff(phi5, 5, 3),
1052 5020431 : coeff(phi5, 4, 3), coeff(phi5, 3, 3), coeff(phi5, 3, 2),
1053 : p, pi);
1054 5024036 : res[4] = Fl_add(t1, coeff(phi5, 3, 1), p);
1055 :
1056 5021154 : t1 = Fl_addmul5(j, j2, j3, j4, j5,
1057 5021154 : coeff(phi5, 6, 4), coeff(phi5, 5, 4),
1058 5021154 : coeff(phi5, 4, 4), coeff(phi5, 4, 3), coeff(phi5, 4, 2),
1059 : p, pi);
1060 5024437 : res[5] = Fl_add(t1, coeff(phi5, 4, 1), p);
1061 :
1062 5021752 : t1 = Fl_addmul5(j, j2, j3, j4, j5,
1063 5021752 : coeff(phi5, 6, 5), coeff(phi5, 5, 5),
1064 5021752 : coeff(phi5, 5, 4), coeff(phi5, 5, 3), coeff(phi5, 5, 2),
1065 : p, pi);
1066 5024985 : res[6] = Fl_add(t1, coeff(phi5, 5, 1), p);
1067 :
1068 5022364 : t1 = Fl_addmul4(j, j2, j3, j4,
1069 5022364 : coeff(phi5, 6, 5), coeff(phi5, 6, 4),
1070 5022364 : coeff(phi5, 6, 3), coeff(phi5, 6, 2),
1071 : p, pi);
1072 5026066 : t1 = Fl_add(t1, coeff(phi5, 6, 1), p);
1073 5022901 : res[7] = Fl_sub(t1, j5, p);
1074 :
1075 5020524 : res[8] = 1;
1076 5020524 : return res;
1077 : }
1078 :
1079 : GEN
1080 41825103 : Flm_Fl_polmodular_evalx(GEN phi, long L, ulong j, ulong p, ulong pi)
1081 : {
1082 41825103 : switch (L) {
1083 26401778 : case 2: return Flm_Fl_phi2_evalx(phi, j, p, pi);
1084 3259146 : case 3: return Flm_Fl_phi3_evalx(phi, j, p, pi);
1085 5012786 : case 5: return Flm_Fl_phi5_evalx(phi, j, p, pi);
1086 7151393 : default: { /* not GC clean, but gerepileupto-safe */
1087 7151393 : GEN j_powers = Fl_powers_pre(j, L + 1, p, pi);
1088 7208703 : return Flm_Flc_mul_pre_Flx(phi, j_powers, p, pi, 0);
1089 : }
1090 : }
1091 : }
1092 :
1093 : /* SECTION: Velu's formula for the codmain curve (Fl case). */
1094 :
1095 : INLINE ulong
1096 1691129 : Fl_mul4(ulong x, ulong p)
1097 1691129 : { return Fl_double(Fl_double(x, p), p); }
1098 :
1099 : INLINE ulong
1100 92170 : Fl_mul5(ulong x, ulong p)
1101 92170 : { return Fl_add(x, Fl_mul4(x, p), p); }
1102 :
1103 : INLINE ulong
1104 845634 : Fl_mul8(ulong x, ulong p)
1105 845634 : { return Fl_double(Fl_mul4(x, p), p); }
1106 :
1107 : INLINE ulong
1108 753482 : Fl_mul6(ulong x, ulong p)
1109 753482 : { return Fl_sub(Fl_mul8(x, p), Fl_double(x, p), p); }
1110 :
1111 : INLINE ulong
1112 92169 : Fl_mul7(ulong x, ulong p)
1113 92169 : { return Fl_sub(Fl_mul8(x, p), x, p); }
1114 :
1115 : /* Given an elliptic curve E = [a4, a6] over F_p and a nonzero point
1116 : * pt on E, return the quotient E' = E/<P> = [a4_img, a6_img] */
1117 : static void
1118 92170 : Fle_quotient_from_kernel_generator(
1119 : ulong *a4_img, ulong *a6_img, ulong a4, ulong a6, GEN pt, ulong p, ulong pi)
1120 : {
1121 92170 : pari_sp av = avma;
1122 92170 : ulong t = 0, w = 0;
1123 : GEN Q;
1124 : ulong xQ, yQ, tQ, uQ;
1125 :
1126 92170 : Q = gcopy(pt);
1127 : /* Note that, as L is odd, say L = 2n + 1, we necessarily have
1128 : * [(L - 1)/2]P = [n]P = [n - L]P = -[n + 1]P = -[(L + 1)/2]P. This is
1129 : * what the condition Q[1] != xQ tests, so the loop will execute n times. */
1130 : do {
1131 753430 : xQ = uel(Q, 1);
1132 753430 : yQ = uel(Q, 2);
1133 : /* tQ = 6 xQ^2 + b2 xQ + b4
1134 : * = 6 xQ^2 + 2 a4 (since b2 = 0 and b4 = 2 a4) */
1135 753430 : tQ = Fl_add(Fl_mul6(Fl_sqr_pre(xQ, p, pi), p), Fl_double(a4, p), p);
1136 753429 : uQ = Fl_add(Fl_mul4(Fl_sqr_pre(yQ, p, pi), p),
1137 : Fl_mul_pre(tQ, xQ, p, pi), p);
1138 :
1139 753432 : t = Fl_add(t, tQ, p);
1140 753399 : w = Fl_add(w, uQ, p);
1141 753379 : Q = gerepileupto(av, Fle_add(pt, Q, a4, p));
1142 753430 : } while (uel(Q, 1) != xQ);
1143 :
1144 92170 : set_avma(av);
1145 : /* a4_img = a4 - 5 * t */
1146 92170 : *a4_img = Fl_sub(a4, Fl_mul5(t, p), p);
1147 : /* a6_img = a6 - b2 * t - 7 * w = a6 - 7 * w (since a1 = a2 = 0 ==> b2 = 0) */
1148 92169 : *a6_img = Fl_sub(a6, Fl_mul7(w, p), p);
1149 92169 : }
1150 :
1151 : /* SECTION: Calculation of modular polynomials. */
1152 :
1153 : /* Given an elliptic curve [a4, a6] over FF_p, try to find a
1154 : * nontrivial L-torsion point on the curve by considering n times a
1155 : * random point; val controls the maximum L-valuation expected of n
1156 : * times a random point */
1157 : static GEN
1158 134278 : find_L_tors_point(
1159 : ulong *ival,
1160 : ulong a4, ulong a6, ulong p, ulong pi,
1161 : ulong n, ulong L, ulong val)
1162 : {
1163 134278 : pari_sp av = avma;
1164 : ulong i;
1165 : GEN P, Q;
1166 : do {
1167 135604 : Q = random_Flj_pre(a4, a6, p, pi);
1168 135593 : P = Flj_mulu_pre(Q, n, a4, p, pi);
1169 135603 : } while (P[3] == 0);
1170 :
1171 259714 : for (i = 0; i < val; ++i) {
1172 217606 : Q = Flj_mulu_pre(P, L, a4, p, pi);
1173 217607 : if (Q[3] == 0) break;
1174 125437 : P = Q;
1175 : }
1176 134278 : if (ival) *ival = i;
1177 134278 : return gerepilecopy(av, P);
1178 : }
1179 :
1180 : static GEN
1181 83244 : select_curve_with_L_tors_point(
1182 : ulong *a4, ulong *a6,
1183 : ulong L, ulong j, ulong n, ulong card, ulong val,
1184 : norm_eqn_t ne)
1185 : {
1186 83244 : pari_sp av = avma;
1187 : ulong A4, A4t, A6, A6t;
1188 83244 : ulong p = ne->p, pi = ne->pi;
1189 : GEN P;
1190 83244 : if (card % L != 0) {
1191 0 : pari_err_BUG("select_curve_with_L_tors_point: "
1192 : "Cardinality not divisible by L");
1193 : }
1194 :
1195 83244 : Fl_ellj_to_a4a6(j, p, &A4, &A6);
1196 83242 : Fl_elltwist_disc(A4, A6, ne->T, p, &A4t, &A6t);
1197 :
1198 : /* Either E = [a4, a6] or its twist has cardinality divisible by L
1199 : * because of the choice of p and t earlier on. We find out which
1200 : * by attempting to find a point of order L on each. See bot p16 of
1201 : * Sutherland 2012. */
1202 42105 : while (1) {
1203 : ulong i;
1204 125347 : P = find_L_tors_point(&i, A4, A6, p, pi, n, L, val);
1205 125346 : if (i < val)
1206 83241 : break;
1207 42105 : set_avma(av);
1208 42105 : lswap(A4, A4t);
1209 42105 : lswap(A6, A6t);
1210 : }
1211 83241 : *a4 = A4;
1212 83241 : *a6 = A6; return gerepilecopy(av, P);
1213 : }
1214 :
1215 : /* Return 1 if the L-Sylow subgroup of the curve [a4, a6] (mod p) is
1216 : * cyclic, return 0 if it is not cyclic with "high" probability (I
1217 : * guess around 1/L^3 chance it is still cyclic when we return 0).
1218 : *
1219 : * Based on Sutherland's velu.c:velu_verify_Sylow_cyclic() in classpoly-1.0.1 */
1220 : INLINE long
1221 47703 : verify_L_sylow_is_cyclic(long e, ulong a4, ulong a6, ulong p, ulong pi)
1222 : {
1223 : /* Number of times to try to find a point with maximal order in the
1224 : * L-Sylow subgroup. */
1225 : enum { N_RETRIES = 3 };
1226 47703 : pari_sp av = avma;
1227 47703 : long i, res = 0;
1228 : GEN P;
1229 78825 : for (i = 0; i < N_RETRIES; ++i) {
1230 69895 : P = random_Flj_pre(a4, a6, p, pi);
1231 69892 : P = Flj_mulu_pre(P, e, a4, p, pi);
1232 69896 : if (P[3] != 0) { res = 1; break; }
1233 : }
1234 47704 : return gc_long(av,res);
1235 : }
1236 :
1237 : static ulong
1238 83239 : find_noniso_L_isogenous_curve(
1239 : ulong L, ulong n,
1240 : norm_eqn_t ne, long e, ulong val, ulong a4, ulong a6, GEN init_pt, long verify)
1241 : {
1242 : pari_sp ltop, av;
1243 83239 : ulong p = ne->p, pi = ne->pi, j_res = 0;
1244 83239 : GEN pt = init_pt;
1245 83239 : ltop = av = avma;
1246 8930 : while (1) {
1247 : /* c. Use Velu to calculate L-isogenous curve E' = E/<P> */
1248 : ulong a4_img, a6_img;
1249 92169 : ulong z2 = Fl_sqr_pre(pt[3], p, pi);
1250 92172 : pt = mkvecsmall2(Fl_div(pt[1], z2, p),
1251 92174 : Fl_div(pt[2], Fl_mul_pre(z2, pt[3], p, pi), p));
1252 92170 : Fle_quotient_from_kernel_generator(&a4_img, &a6_img,
1253 : a4, a6, pt, p, pi);
1254 :
1255 : /* d. If j(E') = j_res has a different endo ring to j(E), then
1256 : * return j(E'). Otherwise, go to b. */
1257 92169 : if (!verify || verify_L_sylow_is_cyclic(e, a4_img, a6_img, p, pi)) {
1258 83240 : j_res = Fl_ellj_pre(a4_img, a6_img, p, pi);
1259 83244 : break;
1260 : }
1261 :
1262 : /* b. Generate random point P on E of order L */
1263 8930 : set_avma(av);
1264 8930 : pt = find_L_tors_point(NULL, a4, a6, p, pi, n, L, val);
1265 : }
1266 83244 : return gc_ulong(ltop, j_res);
1267 : }
1268 :
1269 : /* Given a prime L and a j-invariant j (mod p), return the j-invariant
1270 : * of a curve which has a different endomorphism ring to j and is
1271 : * L-isogenous to j */
1272 : INLINE ulong
1273 83244 : compute_L_isogenous_curve(
1274 : ulong L, ulong n, norm_eqn_t ne,
1275 : ulong j, ulong card, ulong val, long verify)
1276 : {
1277 : ulong a4, a6;
1278 : long e;
1279 : GEN pt;
1280 :
1281 83244 : if (ne->p < 5 || j == 0 || j == 1728 % ne->p)
1282 0 : pari_err_BUG("compute_L_isogenous_curve");
1283 83244 : pt = select_curve_with_L_tors_point(&a4, &a6, L, j, n, card, val, ne);
1284 83239 : e = card / L;
1285 83239 : if (e * L != card) pari_err_BUG("compute_L_isogenous_curve");
1286 :
1287 83239 : return find_noniso_L_isogenous_curve(L, n, ne, e, val, a4, a6, pt, verify);
1288 : }
1289 :
1290 : INLINE GEN
1291 38773 : get_Lsqr_cycle(const disc_info *dinfo)
1292 : {
1293 38773 : long i, n1 = dinfo->n1, L = dinfo->L;
1294 38773 : GEN cyc = cgetg(L, t_VECSMALL);
1295 38774 : cyc[1] = 0;
1296 317281 : for (i = 2; i <= L / 2; ++i) cyc[i] = cyc[i - 1] + n1;
1297 38774 : if ( ! dinfo->L1) {
1298 124743 : for ( ; i < L; ++i) cyc[i] = cyc[i - 1] + n1;
1299 : } else {
1300 24164 : cyc[L - 1] = 2 * dinfo->n2 - n1 / 2;
1301 207148 : for (i = L - 2; i > L / 2; --i) cyc[i] = cyc[i + 1] - n1;
1302 : }
1303 38774 : return cyc;
1304 : }
1305 :
1306 : INLINE void
1307 533804 : update_Lsqr_cycle(GEN cyc, const disc_info *dinfo)
1308 : {
1309 533804 : long i, L = dinfo->L;
1310 15555857 : for (i = 1; i < L; ++i) ++cyc[i];
1311 533804 : if (dinfo->L1 && cyc[L - 1] == 2 * dinfo->n2) {
1312 22438 : long n1 = dinfo->n1;
1313 199286 : for (i = L / 2 + 1; i < L; ++i) cyc[i] -= n1;
1314 : }
1315 533804 : }
1316 :
1317 : static ulong
1318 38769 : oneroot_of_classpoly(GEN hilb, GEN factu, norm_eqn_t ne, GEN jdb)
1319 : {
1320 38769 : pari_sp av = avma;
1321 38769 : ulong j0, p = ne->p, pi = ne->pi;
1322 38769 : long i, nfactors = lg(gel(factu, 1)) - 1;
1323 38769 : GEN hilbp = ZX_to_Flx(hilb, p);
1324 :
1325 : /* TODO: Work out how to use hilb with better invariant */
1326 38770 : j0 = Flx_oneroot_split_pre(hilbp, p, pi);
1327 38773 : if (j0 == p) {
1328 0 : pari_err_BUG("oneroot_of_classpoly: "
1329 : "Didn't find a root of the class polynomial");
1330 : }
1331 40439 : for (i = 1; i <= nfactors; ++i) {
1332 1666 : long L = gel(factu, 1)[i];
1333 1666 : long val = gel(factu, 2)[i];
1334 1666 : GEN phi = polmodular_db_getp(jdb, L, p);
1335 1666 : val += z_lval(ne->v, L);
1336 1666 : j0 = descend_volcano(phi, j0, p, pi, 0, L, val, val);
1337 1666 : set_avma(av);
1338 : }
1339 38773 : return gc_ulong(av, j0);
1340 : }
1341 :
1342 : /* TODO: Precompute the GEN structs and link them to dinfo */
1343 : INLINE GEN
1344 2901 : make_pcp_surface(const disc_info *dinfo)
1345 : {
1346 2901 : GEN L = mkvecsmall(dinfo->L0);
1347 2901 : GEN n = mkvecsmall(dinfo->n1);
1348 2901 : GEN o = mkvecsmall(dinfo->n1);
1349 2901 : return mkvec2(mkvec3(L, n, o), mkvecsmall3(0, 1, dinfo->n1));
1350 : }
1351 :
1352 : INLINE GEN
1353 2901 : make_pcp_floor(const disc_info *dinfo)
1354 : {
1355 2901 : long k = dinfo->L1 ? 2 : 1;
1356 : GEN L, n, o;
1357 2901 : if (k==1)
1358 : {
1359 1432 : L = mkvecsmall(dinfo->L0);
1360 1432 : n = mkvecsmall(dinfo->n2);
1361 1432 : o = mkvecsmall(dinfo->n2);
1362 : } else
1363 : {
1364 1469 : L = mkvecsmall2(dinfo->L0, dinfo->L1);
1365 1469 : n = mkvecsmall2(dinfo->n2, 2);
1366 1469 : o = mkvecsmall2(dinfo->n2, 2);
1367 : }
1368 2901 : return mkvec2(mkvec3(L, n, o), mkvecsmall3(0, k, dinfo->n2*k));
1369 : }
1370 :
1371 : INLINE GEN
1372 38774 : enum_volcano_surface(norm_eqn_t ne, ulong j0, GEN fdb, GEN G)
1373 : {
1374 38774 : pari_sp av = avma;
1375 38774 : return gerepileupto(av, enum_roots(j0, ne, fdb, G, NULL));
1376 : }
1377 :
1378 : INLINE GEN
1379 38773 : enum_volcano_floor(long L, norm_eqn_t ne, ulong j0_pr, GEN fdb, GEN G)
1380 : {
1381 38773 : pari_sp av = avma;
1382 : /* L^2 D is the discriminant for the order R = Z + L OO. */
1383 38773 : long DR = L * L * ne->D;
1384 38773 : long R_cond = L * ne->u; /* conductor(DR); */
1385 38773 : long w = R_cond * ne->v;
1386 : /* TODO: Calculate these once and for all in polmodular0_ZM(). */
1387 : norm_eqn_t eqn;
1388 38773 : memcpy(eqn, ne, sizeof *ne);
1389 38773 : eqn->D = DR;
1390 38773 : eqn->u = R_cond;
1391 38773 : eqn->v = w;
1392 38773 : return gerepileupto(av, enum_roots(j0_pr, eqn, fdb, G, NULL));
1393 : }
1394 :
1395 : INLINE void
1396 18699 : carray_reverse_inplace(long *arr, long n)
1397 : {
1398 18699 : long lim = n>>1, i;
1399 18699 : --n;
1400 186624 : for (i = 0; i < lim; i++) lswap(arr[i], arr[n - i]);
1401 18699 : }
1402 :
1403 : INLINE void
1404 572584 : append_neighbours(GEN rts, GEN surface_js, long njs, long L, long m, long i)
1405 : {
1406 572584 : long r_idx = (((i - 1) + m) % njs) + 1; /* (i + m) % njs */
1407 572584 : long l_idx = umodsu((i - 1) - m, njs) + 1; /* (i - m) % njs */
1408 572578 : rts[L] = surface_js[l_idx];
1409 572578 : rts[L + 1] = surface_js[r_idx];
1410 572578 : }
1411 :
1412 : INLINE GEN
1413 40945 : roots_to_coeffs(GEN rts, ulong p, long L)
1414 : {
1415 40945 : long i, k, lrts= lg(rts);
1416 40945 : GEN M = cgetg(L+2+1, t_MAT);
1417 877599 : for (i = 1; i <= L+2; ++i)
1418 836658 : gel(M, i) = cgetg(lrts, t_VECSMALL);
1419 637193 : for (i = 1; i < lrts; ++i) {
1420 596302 : pari_sp av = avma;
1421 596302 : GEN modpol = Flv_roots_to_pol(gel(rts, i), p, 0);
1422 19410731 : for (k = 1; k <= L + 2; ++k) mael(M, k, i) = modpol[k + 1];
1423 596172 : set_avma(av);
1424 : }
1425 40891 : return M;
1426 : }
1427 :
1428 : /* NB: Assumes indices are offset at 0, not at 1 like in GENs;
1429 : * i.e. indices[i] will pick out v[indices[i] + 1] from v. */
1430 : INLINE void
1431 572573 : vecsmall_pick(GEN res, GEN v, GEN indices)
1432 : {
1433 : long i;
1434 16229181 : for (i = 1; i < lg(indices); ++i) res[i] = v[indices[i] + 1];
1435 572573 : }
1436 :
1437 : /* First element of surface_js must lie above the first element of floor_js.
1438 : * Reverse surface_js if it is not oriented in the same direction as floor_js */
1439 : INLINE GEN
1440 38774 : root_matrix(long L, const disc_info *dinfo, long njinvs, GEN surface_js,
1441 : GEN floor_js, ulong n, ulong card, ulong val, norm_eqn_t ne)
1442 : {
1443 : pari_sp av;
1444 38774 : long i, m = dinfo->dl1, njs = lg(surface_js) - 1, inv = dinfo->inv, rev;
1445 38774 : GEN rt_mat = zero_Flm_copy(L + 1, njinvs), rts, cyc;
1446 38773 : ulong p = ne->p, pi = ne->pi, j;
1447 38773 : av = avma;
1448 :
1449 38773 : i = 1;
1450 38773 : cyc = get_Lsqr_cycle(dinfo);
1451 38774 : rts = gel(rt_mat, i);
1452 38774 : vecsmall_pick(rts, floor_js, cyc);
1453 38774 : append_neighbours(rts, surface_js, njs, L, m, i);
1454 :
1455 38774 : i = 2;
1456 38774 : update_Lsqr_cycle(cyc, dinfo);
1457 38774 : rts = gel(rt_mat, i);
1458 38774 : vecsmall_pick(rts, floor_js, cyc);
1459 :
1460 : /* Fix orientation if necessary */
1461 38774 : if (modinv_is_double_eta(inv)) {
1462 : /* TODO: There is potential for refactoring between this,
1463 : * double_eta_initial_js and modfn_preimage. */
1464 5697 : pari_sp av0 = avma;
1465 5697 : GEN F = double_eta_Fl(inv, p);
1466 5697 : pari_sp av = avma;
1467 5697 : ulong r1 = double_eta_power(inv, uel(rts, 1), p, pi);
1468 5697 : GEN r, f = Flx_double_eta_jpoly(F, r1, p, pi);
1469 5697 : if ((j = Flx_oneroot_pre(f, p, pi)) == p) pari_err_BUG("root_matrix");
1470 5697 : j = compute_L_isogenous_curve(L, n, ne, j, card, val, 0);
1471 5697 : set_avma(av);
1472 5697 : r1 = double_eta_power(inv, uel(surface_js, i), p, pi);
1473 5697 : f = Flx_double_eta_jpoly(F, r1, p, pi);
1474 5697 : r = Flx_roots_pre(f, p, pi);
1475 5697 : if (lg(r) != 3) pari_err_BUG("root_matrix");
1476 5697 : rev = (j != uel(r, 1)) && (j != uel(r, 2));
1477 5697 : set_avma(av0);
1478 : } else {
1479 : ulong j1pr, j1;
1480 33077 : j1pr = modfn_preimage(uel(rts, 1), p, pi, dinfo->inv);
1481 33077 : j1 = compute_L_isogenous_curve(L, n, ne, j1pr, card, val, 0);
1482 33074 : rev = j1 != modfn_preimage(uel(surface_js, i), p, pi, dinfo->inv);
1483 : }
1484 38770 : if (rev)
1485 18699 : carray_reverse_inplace(surface_js + 2, njs - 1);
1486 38770 : append_neighbours(rts, surface_js, njs, L, m, i);
1487 :
1488 533811 : for (i = 3; i <= njinvs; ++i) {
1489 495038 : update_Lsqr_cycle(cyc, dinfo);
1490 495036 : rts = gel(rt_mat, i);
1491 495036 : vecsmall_pick(rts, floor_js, cyc);
1492 495048 : append_neighbours(rts, surface_js, njs, L, m, i);
1493 : }
1494 38773 : set_avma(av); return rt_mat;
1495 : }
1496 :
1497 : INLINE void
1498 41296 : interpolate_coeffs(GEN phi_modp, ulong p, GEN j_invs, GEN coeff_mat)
1499 : {
1500 41296 : pari_sp av = avma;
1501 : long i;
1502 41296 : GEN pols = Flv_Flm_polint(j_invs, coeff_mat, p, 0);
1503 880360 : for (i = 1; i < lg(pols); ++i) {
1504 839065 : GEN pol = gel(pols, i);
1505 839065 : long k, maxk = lg(pol);
1506 18400457 : for (k = 2; k < maxk; ++k) coeff(phi_modp, k - 1, i) = pol[k];
1507 : }
1508 41295 : set_avma(av);
1509 41296 : }
1510 :
1511 : INLINE long
1512 350729 : Flv_lastnonzero(GEN v)
1513 : {
1514 : long i;
1515 27403438 : for (i = lg(v) - 1; i > 0; --i)
1516 27402736 : if (v[i]) break;
1517 350729 : return i;
1518 : }
1519 :
1520 : /* Assuming the matrix of coefficients in phi corresponds to polynomials
1521 : * phi_k^* satisfying Y^c phi_k^*(Y^s) for c in {0, 1, ..., s} satisfying
1522 : * c + Lk = L + 1 (mod s), change phi so that the coefficients are for the
1523 : * polynomials Y^c phi_k^*(Y^s) (s is the sparsity factor) */
1524 : INLINE void
1525 10851 : inflate_polys(GEN phi, long L, long s)
1526 : {
1527 10851 : long k, deg = L + 1;
1528 : long maxr;
1529 10851 : maxr = nbrows(phi);
1530 361596 : for (k = 0; k <= deg; ) {
1531 350745 : long i, c = umodsu(L * (1 - k) + 1, s);
1532 : /* TODO: We actually know that the last nonzero element of gel(phi, k)
1533 : * can't be later than index n+1, where n is about (L + 1)/s. */
1534 350743 : ++k;
1535 5563283 : for (i = Flv_lastnonzero(gel(phi, k)); i > 0; --i) {
1536 5212540 : long r = c + (i - 1) * s + 1;
1537 5212540 : if (r > maxr) { coeff(phi, i, k) = 0; continue; }
1538 5141048 : if (r != i) {
1539 5034572 : coeff(phi, r, k) = coeff(phi, i, k);
1540 5034572 : coeff(phi, i, k) = 0;
1541 : }
1542 : }
1543 : }
1544 10851 : }
1545 :
1546 : INLINE void
1547 42148 : Flv_powu_inplace_pre(GEN v, ulong n, ulong p, ulong pi)
1548 : {
1549 : long i;
1550 349954 : for (i = 1; i < lg(v); ++i) v[i] = Fl_powu_pre(v[i], n, p, pi);
1551 42150 : }
1552 :
1553 : INLINE void
1554 10851 : normalise_coeffs(GEN coeffs, GEN js, long L, long s, ulong p, ulong pi)
1555 : {
1556 10851 : pari_sp av = avma;
1557 : long k;
1558 : GEN pows, modinv_js;
1559 :
1560 : /* NB: In fact it would be correct to return the coefficients "as is" when
1561 : * s = 1, but we make that an error anyway since this function should never
1562 : * be called with s = 1. */
1563 10851 : if (s <= 1) pari_err_BUG("normalise_coeffs");
1564 :
1565 : /* pows[i + 1] contains 1 / js[i + 1]^i for i = 0, ..., s - 1. */
1566 10851 : pows = cgetg(s + 1, t_VEC);
1567 10851 : gel(pows, 1) = const_vecsmall(lg(js) - 1, 1);
1568 10851 : modinv_js = Flv_inv_pre(js, p, pi);
1569 10851 : gel(pows, 2) = modinv_js;
1570 39782 : for (k = 3; k <= s; ++k) {
1571 28931 : gel(pows, k) = gcopy(modinv_js);
1572 28931 : Flv_powu_inplace_pre(gel(pows, k), k - 1, p, pi);
1573 : }
1574 :
1575 : /* For each column of coefficients coeffs[k] = [a0 .. an],
1576 : * replace ai by ai / js[i]^c.
1577 : * Said in another way, normalise each row i of coeffs by
1578 : * dividing through by js[i - 1]^c (where c depends on i). */
1579 361669 : for (k = 1; k < lg(coeffs); ++k) {
1580 350747 : long i, c = umodsu(L * (1 - (k - 1)) + 1, s);
1581 350746 : GEN col = gel(coeffs, k), C = gel(pows, c + 1);
1582 5948730 : for (i = 1; i < lg(col); ++i)
1583 5597912 : col[i] = Fl_mul_pre(col[i], C[i], p, pi);
1584 : }
1585 10922 : set_avma(av);
1586 10851 : }
1587 :
1588 : INLINE void
1589 5697 : double_eta_initial_js(
1590 : ulong *x0, ulong *x0pr, ulong j0, ulong j0pr, norm_eqn_t ne,
1591 : long inv, ulong L, ulong n, ulong card, ulong val)
1592 : {
1593 5697 : pari_sp av0 = avma;
1594 5697 : ulong p = ne->p, pi = ne->pi, s2 = ne->s2;
1595 5697 : GEN F = double_eta_Fl(inv, p);
1596 5697 : pari_sp av = avma;
1597 : ulong j1pr, j1, r, t;
1598 : GEN f, g;
1599 :
1600 5697 : *x0pr = modinv_double_eta_from_j(F, inv, j0pr, p, pi, s2);
1601 5697 : t = double_eta_power(inv, *x0pr, p, pi);
1602 5697 : f = Flx_div_by_X_x(Flx_double_eta_jpoly(F, t, p, pi), j0pr, p, &r);
1603 5697 : if (r) pari_err_BUG("double_eta_initial_js");
1604 5697 : j1pr = Flx_deg1_root(f, p);
1605 5697 : set_avma(av);
1606 :
1607 5697 : j1 = compute_L_isogenous_curve(L, n, ne, j1pr, card, val, 0);
1608 5697 : f = Flx_double_eta_xpoly(F, j0, p, pi);
1609 5697 : g = Flx_double_eta_xpoly(F, j1, p, pi);
1610 : /* x0 is the unique common root of f and g */
1611 5697 : *x0 = Flx_deg1_root(Flx_gcd(f, g, p), p);
1612 5697 : set_avma(av0);
1613 :
1614 5697 : if ( ! double_eta_root(inv, x0, *x0, p, pi, s2))
1615 0 : pari_err_BUG("double_eta_initial_js");
1616 5697 : }
1617 :
1618 : /* This is Sutherland 2012, Algorithm 2.1, p16. */
1619 : static GEN
1620 38770 : polmodular_split_p_Flm(ulong L, GEN hilb, GEN factu, norm_eqn_t ne, GEN db,
1621 : GEN G_surface, GEN G_floor, const disc_info *dinfo)
1622 : {
1623 : ulong j0, j0_rt, j0pr, j0pr_rt;
1624 38770 : ulong n, card, val, p = ne->p, pi = ne->pi;
1625 38770 : long inv = dinfo->inv, s = modinv_sparse_factor(inv);
1626 38770 : long nj_selected = ceil((L + 1)/(double)s) + 1;
1627 : GEN surface_js, floor_js, rts, phi_modp, jdb, fdb;
1628 38770 : long switched_signs = 0;
1629 :
1630 38770 : jdb = polmodular_db_for_inv(db, INV_J);
1631 38768 : fdb = polmodular_db_for_inv(db, inv);
1632 :
1633 : /* Precomputation */
1634 38769 : card = p + 1 - ne->t;
1635 38769 : val = u_lvalrem(card, L, &n); /* n = card / L^{v_L(card)} */
1636 :
1637 38769 : j0 = oneroot_of_classpoly(hilb, factu, ne, jdb);
1638 38773 : j0pr = compute_L_isogenous_curve(L, n, ne, j0, card, val, 1);
1639 38774 : if (modinv_is_double_eta(inv)) {
1640 5697 : double_eta_initial_js(&j0_rt, &j0pr_rt, j0, j0pr, ne, inv, L, n, card, val);
1641 : } else {
1642 33077 : j0_rt = modfn_root(j0, ne, inv);
1643 33075 : j0pr_rt = modfn_root(j0pr, ne, inv);
1644 : }
1645 38774 : surface_js = enum_volcano_surface(ne, j0_rt, fdb, G_surface);
1646 38773 : floor_js = enum_volcano_floor(L, ne, j0pr_rt, fdb, G_floor);
1647 38774 : rts = root_matrix(L, dinfo, nj_selected, surface_js, floor_js,
1648 : n, card, val, ne);
1649 2173 : do {
1650 40946 : pari_sp btop = avma;
1651 : long i;
1652 : GEN coeffs, surf;
1653 :
1654 40946 : coeffs = roots_to_coeffs(rts, p, L);
1655 40943 : surf = vecsmall_shorten(surface_js, nj_selected);
1656 40941 : if (s > 1) {
1657 10851 : normalise_coeffs(coeffs, surf, L, s, p, pi);
1658 10851 : Flv_powu_inplace_pre(surf, s, p, pi);
1659 : }
1660 40941 : phi_modp = zero_Flm_copy(L + 2, L + 2);
1661 40946 : interpolate_coeffs(phi_modp, p, surf, coeffs);
1662 40946 : if (s > 1) inflate_polys(phi_modp, L, s);
1663 :
1664 : /* TODO: Calculate just this coefficient of X^L Y^L, so we can do this
1665 : * test, then calculate the other coefficients; at the moment we are
1666 : * sometimes doing all the roots-to-coeffs, normalisation and interpolation
1667 : * work twice. */
1668 40946 : if (ucoeff(phi_modp, L + 1, L + 1) == p - 1) break;
1669 :
1670 2173 : if (switched_signs) pari_err_BUG("polmodular_split_p_Flm");
1671 :
1672 2173 : set_avma(btop);
1673 26104 : for (i = 1; i < lg(rts); ++i) {
1674 23931 : surface_js[i] = Fl_neg(surface_js[i], p);
1675 23931 : coeff(rts, L, i) = Fl_neg(coeff(rts, L, i), p);
1676 23931 : coeff(rts, L + 1, i) = Fl_neg(coeff(rts, L + 1, i), p);
1677 : }
1678 2173 : switched_signs = 1;
1679 : } while (1);
1680 38773 : dbg_printf(4)(" Phi_%lu(X, Y) (mod %lu) = %Ps\n", L, p, phi_modp);
1681 :
1682 38773 : return phi_modp;
1683 : }
1684 :
1685 : INLINE void
1686 2464 : Flv_deriv_pre_inplace(GEN v, long deg, ulong p, ulong pi)
1687 : {
1688 2464 : long i, ln = lg(v), d = deg % p;
1689 57232 : for (i = ln - 1; i > 1; --i, --d) v[i] = Fl_mul_pre(v[i - 1], d, p, pi);
1690 2464 : v[1] = 0;
1691 2464 : }
1692 :
1693 : INLINE GEN
1694 2674 : eval_modpoly_modp(GEN Tp, GEN j_powers, ulong p, ulong pi, int compute_derivs)
1695 : {
1696 2674 : long L = lg(j_powers) - 3;
1697 2674 : GEN j_pows_p = ZV_to_Flv(j_powers, p);
1698 2674 : GEN tmp = cgetg(2 + 2 * compute_derivs, t_VEC);
1699 : /* We wrap the result in this t_VEC Tp to trick the
1700 : * ZM_*_CRT() functions into thinking it's a matrix. */
1701 2674 : gel(tmp, 1) = Flm_Flc_mul_pre(Tp, j_pows_p, p, pi);
1702 2674 : if (compute_derivs) {
1703 1232 : Flv_deriv_pre_inplace(j_pows_p, L + 1, p, pi);
1704 1232 : gel(tmp, 2) = Flm_Flc_mul_pre(Tp, j_pows_p, p, pi);
1705 1232 : Flv_deriv_pre_inplace(j_pows_p, L + 1, p, pi);
1706 1232 : gel(tmp, 3) = Flm_Flc_mul_pre(Tp, j_pows_p, p, pi);
1707 : }
1708 2674 : return tmp;
1709 : }
1710 :
1711 : /* Parallel interface */
1712 : GEN
1713 38768 : polmodular_worker(GEN tp, ulong L, GEN hilb, GEN factu, GEN vne, GEN vinfo,
1714 : long derivs, GEN j_powers, GEN G_surface, GEN G_floor,
1715 : GEN fdb)
1716 : {
1717 38768 : pari_sp av = avma;
1718 : norm_eqn_t ne;
1719 38768 : long D = vne[1], u = vne[2];
1720 38768 : ulong vL, t = tp[1], p = tp[2];
1721 : GEN Tp;
1722 :
1723 38768 : if (! uissquareall((4 * p - t * t) / -D, &vL))
1724 0 : pari_err_BUG("polmodular_worker");
1725 38772 : norm_eqn_set(ne, D, t, u, vL, NULL, p); /* L | vL */
1726 38769 : Tp = polmodular_split_p_Flm(L, hilb, factu, ne, fdb,
1727 : G_surface, G_floor, (const disc_info*)vinfo);
1728 38773 : if (!isintzero(j_powers))
1729 2674 : Tp = eval_modpoly_modp(Tp, j_powers, ne->p, ne->pi, derivs);
1730 38772 : return gerepileupto(av, Tp);
1731 : }
1732 :
1733 : static GEN
1734 24691 : sympol_to_ZM(GEN phi, long L)
1735 : {
1736 24691 : pari_sp av = avma;
1737 24691 : GEN res = zeromatcopy(L + 2, L + 2);
1738 24691 : long i, j, c = 1;
1739 108043 : for (i = 1; i <= L + 1; ++i)
1740 276319 : for (j = 1; j <= i; ++j, ++c)
1741 192967 : gcoeff(res, i, j) = gcoeff(res, j, i) = gel(phi, c);
1742 24691 : gcoeff(res, L + 2, 1) = gcoeff(res, 1, L + 2) = gen_1;
1743 24691 : return gerepilecopy(av, res);
1744 : }
1745 :
1746 : static GEN polmodular_small_ZM(long L, long inv, GEN *db);
1747 :
1748 : INLINE long
1749 27846 : modinv_max_internal_level(long inv)
1750 : {
1751 27846 : switch (inv) {
1752 25225 : case INV_J: return 5;
1753 364 : case INV_G2: return 2;
1754 443 : case INV_F:
1755 : case INV_F2:
1756 : case INV_F4:
1757 443 : case INV_F8: return 5;
1758 252 : case INV_W2W5:
1759 252 : case INV_W2W5E2: return 7;
1760 462 : case INV_W2W3:
1761 : case INV_W2W3E2:
1762 : case INV_W3W3:
1763 462 : case INV_W3W7: return 5;
1764 63 : case INV_W3W3E2:return 2;
1765 729 : case INV_F3:
1766 : case INV_W2W7:
1767 : case INV_W2W7E2:
1768 729 : case INV_W2W13: return 3;
1769 308 : case INV_W3W5:
1770 : case INV_W5W7:
1771 308 : case INV_W3W13: return 2;
1772 : }
1773 : pari_err_BUG("modinv_max_internal_level"); return LONG_MAX;/*LCOV_EXCL_LINE*/
1774 : }
1775 : static void
1776 45 : db_add_levels(GEN *db, GEN P, long inv)
1777 45 : { polmodular_db_add_levels(db, zv_to_longptr(P), lg(P)-1, inv); }
1778 :
1779 : GEN
1780 27727 : polmodular0_ZM(long L, long inv, GEN J, GEN Q, int compute_derivs, GEN *db)
1781 : {
1782 27727 : pari_sp ltop = avma;
1783 27727 : long k, d, Dcnt, nprimes = 0;
1784 : GEN modpoly, plist, tp, j_powers;
1785 : disc_info Ds[MODPOLY_MAX_DCNT];
1786 27727 : long lvl = modinv_level(inv);
1787 27727 : if (ugcd(L, lvl) != 1)
1788 7 : pari_err_DOMAIN("polmodular0_ZM", "invariant",
1789 : "incompatible with", stoi(L), stoi(lvl));
1790 :
1791 27720 : dbg_printf(1)("Calculating modular polynomial of level %lu for invariant %d\n", L, inv);
1792 27720 : if (L <= modinv_max_internal_level(inv)) return polmodular_small_ZM(L,inv,db);
1793 :
1794 2882 : Dcnt = discriminant_with_classno_at_least(Ds, L, inv, Q, USE_SPARSE_FACTOR);
1795 5783 : for (d = 0; d < Dcnt; d++) nprimes += Ds[d].nprimes;
1796 2882 : modpoly = cgetg(nprimes+1, t_VEC);
1797 2882 : plist = cgetg(nprimes+1, t_VECSMALL);
1798 2882 : tp = mkvec(mkvecsmall2(0,0));
1799 2882 : j_powers = gen_0;
1800 2882 : if (J) {
1801 63 : compute_derivs = !!compute_derivs;
1802 63 : j_powers = Fp_powers(J, L+1, Q);
1803 : }
1804 5783 : for (d = 0, k = 1; d < Dcnt; d++)
1805 : {
1806 2901 : disc_info *dinfo = &Ds[d];
1807 : struct pari_mt pt;
1808 2901 : const long D = dinfo->D1, DK = dinfo->D0;
1809 2901 : const ulong cond = usqrt(D / DK);
1810 2901 : long i, pending = 0;
1811 2901 : GEN worker, hilb, factu = factoru(cond);
1812 :
1813 2901 : polmodular_db_add_level(db, dinfo->L0, inv);
1814 2901 : if (dinfo->L1) polmodular_db_add_level(db, dinfo->L1, inv);
1815 2901 : dbg_printf(1)("Selected discriminant D = %ld = %ld^2 * %ld.\n", D,cond,DK);
1816 2901 : hilb = polclass0(DK, INV_J, 0, db);
1817 2901 : if (cond > 1) db_add_levels(db, gel(factu,1), INV_J);
1818 2901 : dbg_printf(1)("D = %ld, L0 = %lu, L1 = %lu, ", dinfo->D1, dinfo->L0, dinfo->L1);
1819 2901 : dbg_printf(1)("n1 = %lu, n2 = %lu, dl1 = %lu, dl2_0 = %lu, dl2_1 = %lu\n",
1820 : dinfo->n1, dinfo->n2, dinfo->dl1, dinfo->dl2_0, dinfo->dl2_1);
1821 2901 : dbg_printf(0)("Calculating modular polynomial of level %lu:", L);
1822 :
1823 2901 : worker = snm_closure(is_entry("_polmodular_worker"),
1824 : mkvecn(10, utoi(L), hilb, factu, mkvecsmall2(D, cond),
1825 : (GEN)dinfo, stoi(compute_derivs), j_powers,
1826 : make_pcp_surface(dinfo),
1827 : make_pcp_floor(dinfo), *db));
1828 2901 : mt_queue_start_lim(&pt, worker, dinfo->nprimes);
1829 45702 : for (i = 0; i < dinfo->nprimes || pending; i++)
1830 : {
1831 : long workid;
1832 : GEN done;
1833 42801 : if (i < dinfo->nprimes)
1834 : {
1835 38774 : mael(tp, 1, 1) = dinfo->traces[i];
1836 38774 : mael(tp, 1, 2) = dinfo->primes[i];
1837 : }
1838 42801 : mt_queue_submit(&pt, i, i < dinfo->nprimes? tp: NULL);
1839 42801 : done = mt_queue_get(&pt, &workid, &pending);
1840 42801 : if (done)
1841 : {
1842 38774 : plist[k] = dinfo->primes[workid];
1843 38774 : gel(modpoly, k) = done; k++;
1844 38774 : dbg_printf(0)(" %ld%%", k*100/nprimes);
1845 : }
1846 : }
1847 2901 : dbg_printf(0)(" done\n");
1848 2901 : mt_queue_end(&pt);
1849 2901 : killblock((GEN)dinfo->primes);
1850 : }
1851 2882 : modpoly = nmV_chinese_center(modpoly, plist, NULL);
1852 2882 : if (J) modpoly = FpM_red(modpoly, Q);
1853 2882 : return gerepileupto(ltop, modpoly);
1854 : }
1855 :
1856 : GEN
1857 19263 : polmodular_ZM(long L, long inv)
1858 : {
1859 : GEN db, Phi;
1860 :
1861 19263 : if (L < 2)
1862 7 : pari_err_DOMAIN("polmodular_ZM", "L", "<", gen_2, stoi(L));
1863 :
1864 : /* TODO: Handle nonprime L. Algorithm 1.1 and Corollary 3.4 in Sutherland,
1865 : * "Class polynomials for nonholomorphic modular functions" */
1866 19256 : if (! uisprime(L)) pari_err_IMPL("composite level");
1867 :
1868 19249 : db = polmodular_db_init(inv);
1869 19249 : Phi = polmodular0_ZM(L, inv, NULL, NULL, 0, &db);
1870 19242 : gunclone_deep(db); return Phi;
1871 : }
1872 :
1873 : GEN
1874 19179 : polmodular_ZXX(long L, long inv, long vx, long vy)
1875 : {
1876 19179 : pari_sp av = avma;
1877 19179 : GEN phi = polmodular_ZM(L, inv);
1878 :
1879 19158 : if (vx < 0) vx = 0;
1880 19158 : if (vy < 0) vy = 1;
1881 19158 : if (varncmp(vx, vy) >= 0)
1882 14 : pari_err_PRIORITY("polmodular_ZXX", pol_x(vx), "<=", vy);
1883 19144 : return gerepilecopy(av, RgM_to_RgXX(phi, vx, vy));
1884 : }
1885 :
1886 : INLINE GEN
1887 56 : FpV_deriv(GEN v, long deg, GEN P)
1888 : {
1889 56 : long i, ln = lg(v);
1890 56 : GEN dv = cgetg(ln, t_VEC);
1891 392 : for (i = ln-1; i > 1; i--, deg--) gel(dv, i) = Fp_mulu(gel(v, i-1), deg, P);
1892 56 : gel(dv, 1) = gen_0; return dv;
1893 : }
1894 :
1895 : GEN
1896 126 : Fp_polmodular_evalx(long L, long inv, GEN J, GEN P, long v, int compute_derivs)
1897 : {
1898 126 : pari_sp av = avma;
1899 : GEN db, phi;
1900 :
1901 126 : if (L <= modinv_max_internal_level(inv)) {
1902 : GEN tmp;
1903 63 : GEN phi = RgM_to_FpM(polmodular_ZM(L, inv), P);
1904 63 : GEN j_powers = Fp_powers(J, L + 1, P);
1905 63 : GEN modpol = RgV_to_RgX(FpM_FpC_mul(phi, j_powers, P), v);
1906 63 : if (compute_derivs) {
1907 28 : tmp = cgetg(4, t_VEC);
1908 28 : gel(tmp, 1) = modpol;
1909 28 : j_powers = FpV_deriv(j_powers, L + 1, P);
1910 28 : gel(tmp, 2) = RgV_to_RgX(FpM_FpC_mul(phi, j_powers, P), v);
1911 28 : j_powers = FpV_deriv(j_powers, L + 1, P);
1912 28 : gel(tmp, 3) = RgV_to_RgX(FpM_FpC_mul(phi, j_powers, P), v);
1913 : } else
1914 35 : tmp = modpol;
1915 63 : return gerepilecopy(av, tmp);
1916 : }
1917 :
1918 63 : db = polmodular_db_init(inv);
1919 63 : phi = polmodular0_ZM(L, inv, J, P, compute_derivs, &db);
1920 63 : phi = RgM_to_RgXV(phi, v);
1921 63 : gunclone_deep(db);
1922 63 : return gerepilecopy(av, compute_derivs? phi: gel(phi, 1));
1923 : }
1924 :
1925 : GEN
1926 630 : polmodular(long L, long inv, GEN x, long v, long compute_derivs)
1927 : {
1928 630 : pari_sp av = avma;
1929 : long tx;
1930 630 : GEN J = NULL, P = NULL, res = NULL, one = NULL;
1931 :
1932 630 : check_modinv(inv);
1933 623 : if (!x || gequalX(x)) {
1934 483 : long xv = 0;
1935 483 : if (x) xv = varn(x);
1936 483 : if (compute_derivs) pari_err_FLAG("polmodular");
1937 476 : return polmodular_ZXX(L, inv, xv, v);
1938 : }
1939 :
1940 140 : tx = typ(x);
1941 140 : if (tx == t_INTMOD) {
1942 63 : J = gel(x, 2);
1943 63 : P = gel(x, 1);
1944 63 : one = mkintmod(gen_1, P);
1945 77 : } else if (tx == t_FFELT) {
1946 70 : J = FF_to_FpXQ_i(x);
1947 70 : if (degpol(J) > 0)
1948 7 : pari_err_DOMAIN("polmodular", "x", "not in prime subfield ", gen_0, x);
1949 63 : J = constant_coeff(J);
1950 63 : P = FF_p_i(x);
1951 63 : one = FF_1(x);
1952 : } else
1953 7 : pari_err_TYPE("polmodular", x);
1954 :
1955 126 : if (v < 0) v = 1;
1956 126 : res = Fp_polmodular_evalx(L, inv, J, P, v, compute_derivs);
1957 126 : return gerepileupto(av, gmul(res, one));
1958 : }
1959 :
1960 : /* SECTION: Modular polynomials of level <= MAX_INTERNAL_MODPOLY_LEVEL. */
1961 :
1962 : /* These functions return a vector of coefficients of classical modular
1963 : * polynomials Phi_L(X,Y) of small level L. The number of such coefficients is
1964 : * (L+1)(L+2)/2 since Phi is symmetric. We omit the common coefficient of
1965 : * X^{L+1} and Y^{L+1} since it is always 1. Use sympol_to_ZM() to get the
1966 : * corresponding desymmetrised matrix of coefficients */
1967 :
1968 : /* Phi2, the modular polynomial of level 2:
1969 : *
1970 : * X^3 + X^2 * (-Y^2 + 1488*Y - 162000)
1971 : * + X * (1488*Y^2 + 40773375*Y + 8748000000)
1972 : * + Y^3 - 162000*Y^2 + 8748000000*Y - 157464000000000
1973 : *
1974 : * [[3, 0, 1],
1975 : * [2, 2, -1],
1976 : * [2, 1, 1488],
1977 : * [2, 0, -162000],
1978 : * [1, 1, 40773375],
1979 : * [1, 0, 8748000000],
1980 : * [0, 0, -157464000000000]], */
1981 : static GEN
1982 20005 : phi2_ZV(void)
1983 : {
1984 20005 : GEN phi2 = cgetg(7, t_VEC);
1985 20005 : gel(phi2, 1) = uu32toi(36662, 1908994048);
1986 20005 : setsigne(gel(phi2, 1), -1);
1987 20005 : gel(phi2, 2) = uu32toi(2, 158065408);
1988 20005 : gel(phi2, 3) = stoi(40773375);
1989 20005 : gel(phi2, 4) = stoi(-162000);
1990 20005 : gel(phi2, 5) = stoi(1488);
1991 20005 : gel(phi2, 6) = gen_m1;
1992 20005 : return phi2;
1993 : }
1994 :
1995 : /* L = 3
1996 : *
1997 : * [4, 0, 1],
1998 : * [3, 3, -1],
1999 : * [3, 2, 2232],
2000 : * [3, 1, -1069956],
2001 : * [3, 0, 36864000],
2002 : * [2, 2, 2587918086],
2003 : * [2, 1, 8900222976000],
2004 : * [2, 0, 452984832000000],
2005 : * [1, 1, -770845966336000000],
2006 : * [1, 0, 1855425871872000000000]
2007 : * [0, 0, 0]
2008 : *
2009 : * 1855425871872000000000 = 2^32 * (100 * 2^32 + 2503270400) */
2010 : static GEN
2011 1882 : phi3_ZV(void)
2012 : {
2013 1882 : GEN phi3 = cgetg(11, t_VEC);
2014 1882 : pari_sp av = avma;
2015 1882 : gel(phi3, 1) = gen_0;
2016 1882 : gel(phi3, 2) = gerepileupto(av, shifti(uu32toi(100, 2503270400UL), 32));
2017 1882 : gel(phi3, 3) = uu32toi(179476562, 2147483648UL);
2018 1882 : setsigne(gel(phi3, 3), -1);
2019 1882 : gel(phi3, 4) = uu32toi(105468, 3221225472UL);
2020 1882 : gel(phi3, 5) = uu32toi(2072, 1050738688);
2021 1882 : gel(phi3, 6) = utoi(2587918086UL);
2022 1882 : gel(phi3, 7) = stoi(36864000);
2023 1882 : gel(phi3, 8) = stoi(-1069956);
2024 1882 : gel(phi3, 9) = stoi(2232);
2025 1882 : gel(phi3, 10) = gen_m1;
2026 1882 : return phi3;
2027 : }
2028 :
2029 : static GEN
2030 1852 : phi5_ZV(void)
2031 : {
2032 1852 : GEN phi5 = cgetg(22, t_VEC);
2033 1852 : gel(phi5, 1) = mkintn(5, 0x18c2cc9cUL, 0x484382b2UL, 0xdc000000UL, 0x0UL, 0x0UL);
2034 1852 : gel(phi5, 2) = mkintn(5, 0x2638fUL, 0x2ff02690UL, 0x68026000UL, 0x0UL, 0x0UL);
2035 1852 : gel(phi5, 3) = mkintn(5, 0x308UL, 0xac9d9a4UL, 0xe0fdab12UL, 0xc0000000UL, 0x0UL);
2036 1852 : setsigne(gel(phi5, 3), -1);
2037 1852 : gel(phi5, 4) = mkintn(5, 0x13UL, 0xaae09f9dUL, 0x1b5ef872UL, 0x30000000UL, 0x0UL);
2038 1852 : gel(phi5, 5) = mkintn(4, 0x1b802fa9UL, 0x77ba0653UL, 0xd2f78000UL, 0x0UL);
2039 1852 : gel(phi5, 6) = mkintn(4, 0xfbfdUL, 0x278e4756UL, 0xdf08a7c4UL, 0x40000000UL);
2040 1852 : gel(phi5, 7) = mkintn(4, 0x35f922UL, 0x62ccea6fUL, 0x153d0000UL, 0x0UL);
2041 1852 : gel(phi5, 8) = mkintn(4, 0x97dUL, 0x29203fafUL, 0xc3036909UL, 0x80000000UL);
2042 1852 : setsigne(gel(phi5, 8), -1);
2043 1852 : gel(phi5, 9) = mkintn(3, 0x56e9e892UL, 0xd7781867UL, 0xf2ea0000UL);
2044 1852 : gel(phi5, 10) = mkintn(3, 0x5d6dUL, 0xe0a58f4eUL, 0x9ee68c14UL);
2045 1852 : setsigne(gel(phi5, 10), -1);
2046 1852 : gel(phi5, 11) = mkintn(3, 0x1100dUL, 0x85cea769UL, 0x40000000UL);
2047 1852 : gel(phi5, 12) = mkintn(3, 0x1b38UL, 0x43cf461fUL, 0x3a900000UL);
2048 1852 : gel(phi5, 13) = mkintn(3, 0x14UL, 0xc45a616eUL, 0x4801680fUL);
2049 1852 : gel(phi5, 14) = uu32toi(0x17f4350UL, 0x493ca3e0UL);
2050 1852 : gel(phi5, 15) = uu32toi(0x183UL, 0xe54ce1f8UL);
2051 1852 : gel(phi5, 16) = uu32toi(0x1c9UL, 0x18860000UL);
2052 1852 : gel(phi5, 17) = uu32toi(0x39UL, 0x6f7a2206UL);
2053 1852 : setsigne(gel(phi5, 17), -1);
2054 1852 : gel(phi5, 18) = stoi(2028551200);
2055 1852 : gel(phi5, 19) = stoi(-4550940);
2056 1852 : gel(phi5, 20) = stoi(3720);
2057 1852 : gel(phi5, 21) = gen_m1;
2058 1852 : return phi5;
2059 : }
2060 :
2061 : static GEN
2062 182 : phi5_f_ZV(void)
2063 : {
2064 182 : GEN phi = zerovec(21);
2065 182 : gel(phi, 3) = stoi(4);
2066 182 : gel(phi, 21) = gen_m1;
2067 182 : return phi;
2068 : }
2069 :
2070 : static GEN
2071 21 : phi3_f3_ZV(void)
2072 : {
2073 21 : GEN phi = zerovec(10);
2074 21 : gel(phi, 3) = stoi(8);
2075 21 : gel(phi, 10) = gen_m1;
2076 21 : return phi;
2077 : }
2078 :
2079 : static GEN
2080 119 : phi2_g2_ZV(void)
2081 : {
2082 119 : GEN phi = zerovec(6);
2083 119 : gel(phi, 1) = stoi(-54000);
2084 119 : gel(phi, 3) = stoi(495);
2085 119 : gel(phi, 6) = gen_m1;
2086 119 : return phi;
2087 : }
2088 :
2089 : static GEN
2090 56 : phi5_w2w3_ZV(void)
2091 : {
2092 56 : GEN phi = zerovec(21);
2093 56 : gel(phi, 3) = gen_m1;
2094 56 : gel(phi, 10) = stoi(5);
2095 56 : gel(phi, 21) = gen_m1;
2096 56 : return phi;
2097 : }
2098 :
2099 : static GEN
2100 112 : phi7_w2w5_ZV(void)
2101 : {
2102 112 : GEN phi = zerovec(36);
2103 112 : gel(phi, 3) = gen_m1;
2104 112 : gel(phi, 15) = stoi(56);
2105 112 : gel(phi, 19) = stoi(42);
2106 112 : gel(phi, 24) = stoi(21);
2107 112 : gel(phi, 30) = stoi(7);
2108 112 : gel(phi, 36) = gen_m1;
2109 112 : return phi;
2110 : }
2111 :
2112 : static GEN
2113 63 : phi5_w3w3_ZV(void)
2114 : {
2115 63 : GEN phi = zerovec(21);
2116 63 : gel(phi, 3) = stoi(9);
2117 63 : gel(phi, 6) = stoi(-15);
2118 63 : gel(phi, 15) = stoi(5);
2119 63 : gel(phi, 21) = gen_m1;
2120 63 : return phi;
2121 : }
2122 :
2123 : static GEN
2124 182 : phi3_w2w7_ZV(void)
2125 : {
2126 182 : GEN phi = zerovec(10);
2127 182 : gel(phi, 3) = gen_m1;
2128 182 : gel(phi, 6) = stoi(3);
2129 182 : gel(phi, 10) = gen_m1;
2130 182 : return phi;
2131 : }
2132 :
2133 : static GEN
2134 35 : phi2_w3w5_ZV(void)
2135 : {
2136 35 : GEN phi = zerovec(6);
2137 35 : gel(phi, 3) = gen_1;
2138 35 : gel(phi, 6) = gen_m1;
2139 35 : return phi;
2140 : }
2141 :
2142 : static GEN
2143 42 : phi5_w3w7_ZV(void)
2144 : {
2145 42 : GEN phi = zerovec(21);
2146 42 : gel(phi, 3) = gen_m1;
2147 42 : gel(phi, 6) = stoi(10);
2148 42 : gel(phi, 8) = stoi(5);
2149 42 : gel(phi, 10) = stoi(35);
2150 42 : gel(phi, 13) = stoi(20);
2151 42 : gel(phi, 15) = stoi(10);
2152 42 : gel(phi, 17) = stoi(5);
2153 42 : gel(phi, 19) = stoi(5);
2154 42 : gel(phi, 21) = gen_m1;
2155 42 : return phi;
2156 : }
2157 :
2158 : static GEN
2159 49 : phi3_w2w13_ZV(void)
2160 : {
2161 49 : GEN phi = zerovec(10);
2162 49 : gel(phi, 3) = gen_m1;
2163 49 : gel(phi, 6) = stoi(3);
2164 49 : gel(phi, 8) = stoi(3);
2165 49 : gel(phi, 10) = gen_m1;
2166 49 : return phi;
2167 : }
2168 :
2169 : static GEN
2170 21 : phi2_w3w3e2_ZV(void)
2171 : {
2172 21 : GEN phi = zerovec(6);
2173 21 : gel(phi, 3) = stoi(3);
2174 21 : gel(phi, 6) = gen_m1;
2175 21 : return phi;
2176 : }
2177 :
2178 : static GEN
2179 56 : phi2_w5w7_ZV(void)
2180 : {
2181 56 : GEN phi = zerovec(6);
2182 56 : gel(phi, 3) = gen_1;
2183 56 : gel(phi, 5) = gen_2;
2184 56 : gel(phi, 6) = gen_m1;
2185 56 : return phi;
2186 : }
2187 :
2188 : static GEN
2189 14 : phi2_w3w13_ZV(void)
2190 : {
2191 14 : GEN phi = zerovec(6);
2192 14 : gel(phi, 3) = gen_m1;
2193 14 : gel(phi, 5) = gen_2;
2194 14 : gel(phi, 6) = gen_m1;
2195 14 : return phi;
2196 : }
2197 :
2198 : INLINE long
2199 147 : modinv_parent(long inv)
2200 : {
2201 147 : switch (inv) {
2202 42 : case INV_F2:
2203 : case INV_F4:
2204 42 : case INV_F8: return INV_F;
2205 14 : case INV_W2W3E2: return INV_W2W3;
2206 28 : case INV_W2W5E2: return INV_W2W5;
2207 63 : case INV_W2W7E2: return INV_W2W7;
2208 0 : case INV_W3W3E2: return INV_W3W3;
2209 : default: pari_err_BUG("modinv_parent"); return -1;/*LCOV_EXCL_LINE*/
2210 : }
2211 : }
2212 :
2213 : /* TODO: Think of a better name than "parent power"; sheesh. */
2214 : INLINE long
2215 147 : modinv_parent_power(long inv)
2216 : {
2217 147 : switch (inv) {
2218 14 : case INV_F4: return 4;
2219 14 : case INV_F8: return 8;
2220 119 : case INV_F2:
2221 : case INV_W2W3E2:
2222 : case INV_W2W5E2:
2223 : case INV_W2W7E2:
2224 119 : case INV_W3W3E2: return 2;
2225 : default: pari_err_BUG("modinv_parent_power"); return -1;/*LCOV_EXCL_LINE*/
2226 : }
2227 : }
2228 :
2229 : static GEN
2230 147 : polmodular0_powerup_ZM(long L, long inv, GEN *db)
2231 : {
2232 147 : pari_sp ltop = avma, av;
2233 : long s, D, nprimes, N;
2234 : GEN mp, pol, P, H;
2235 147 : long parent = modinv_parent(inv);
2236 147 : long e = modinv_parent_power(inv);
2237 : disc_info Ds[MODPOLY_MAX_DCNT];
2238 : /* FIXME: We throw away the table of fundamental discriminants here. */
2239 147 : long nDs = discriminant_with_classno_at_least(Ds, L, inv, NULL, IGNORE_SPARSE_FACTOR);
2240 147 : if (nDs != 1) pari_err_BUG("polmodular0_powerup_ZM");
2241 147 : D = Ds[0].D1;
2242 147 : nprimes = Ds[0].nprimes + 1;
2243 147 : mp = polmodular0_ZM(L, parent, NULL, NULL, 0, db);
2244 147 : H = polclass0(D, parent, 0, db);
2245 :
2246 147 : N = L + 2;
2247 147 : if (degpol(H) < N) pari_err_BUG("polmodular0_powerup_ZM");
2248 :
2249 147 : av = avma;
2250 147 : pol = ZM_init_CRT(zero_Flm_copy(N, L + 2), 1);
2251 147 : P = gen_1;
2252 497 : for (s = 1; s < nprimes; ++s) {
2253 : pari_sp av1, av2;
2254 350 : ulong p = Ds[0].primes[s-1], pi = get_Fl_red(p);
2255 : long i;
2256 : GEN Hrts, js, Hp, Phip, coeff_mat, phi_modp;
2257 :
2258 350 : phi_modp = zero_Flm_copy(N, L + 2);
2259 350 : av1 = avma;
2260 350 : Hp = ZX_to_Flx(H, p);
2261 350 : Hrts = Flx_roots_pre(Hp, p, pi);
2262 350 : if (lg(Hrts)-1 < N) pari_err_BUG("polmodular0_powerup_ZM");
2263 350 : js = cgetg(N + 1, t_VECSMALL);
2264 2716 : for (i = 1; i <= N; ++i)
2265 2366 : uel(js, i) = Fl_powu_pre(uel(Hrts, i), e, p, pi);
2266 :
2267 350 : Phip = ZM_to_Flm(mp, p);
2268 350 : coeff_mat = zero_Flm_copy(N, L + 2);
2269 350 : av2 = avma;
2270 2716 : for (i = 1; i <= N; ++i) {
2271 : long k;
2272 : GEN phi_at_ji, mprts;
2273 :
2274 2366 : phi_at_ji = Flm_Fl_polmodular_evalx(Phip, L, uel(Hrts, i), p, pi);
2275 2366 : mprts = Flx_roots_pre(phi_at_ji, p, pi);
2276 2366 : if (lg(mprts) != L + 2) pari_err_BUG("polmodular0_powerup_ZM");
2277 :
2278 2366 : Flv_powu_inplace_pre(mprts, e, p, pi);
2279 2366 : phi_at_ji = Flv_roots_to_pol(mprts, p, 0);
2280 :
2281 19180 : for (k = 1; k <= L + 2; ++k)
2282 16814 : ucoeff(coeff_mat, i, k) = uel(phi_at_ji, k + 1);
2283 2366 : set_avma(av2);
2284 : }
2285 :
2286 350 : interpolate_coeffs(phi_modp, p, js, coeff_mat);
2287 350 : set_avma(av1);
2288 :
2289 350 : (void) ZM_incremental_CRT(&pol, phi_modp, &P, p);
2290 350 : if (gc_needed(av, 2)) gerepileall(av, 2, &pol, &P);
2291 : }
2292 147 : killblock((GEN)Ds[0].primes); return gerepileupto(ltop, pol);
2293 : }
2294 :
2295 : /* Returns the modular polynomial with the smallest level for the given
2296 : * invariant, except if inv is INV_J, in which case return the modular
2297 : * polynomial of level L in {2,3,5}. NULL is returned if the modular
2298 : * polynomial can be calculated using polmodular0_powerup_ZM. */
2299 : INLINE GEN
2300 24838 : internal_db(long L, long inv)
2301 : {
2302 24838 : switch (inv) {
2303 23739 : case INV_J: switch (L) {
2304 20005 : case 2: return phi2_ZV();
2305 1882 : case 3: return phi3_ZV();
2306 1852 : case 5: return phi5_ZV();
2307 0 : default: break;
2308 : }
2309 182 : case INV_F: return phi5_f_ZV();
2310 14 : case INV_F2: return NULL;
2311 21 : case INV_F3: return phi3_f3_ZV();
2312 14 : case INV_F4: return NULL;
2313 119 : case INV_G2: return phi2_g2_ZV();
2314 56 : case INV_W2W3: return phi5_w2w3_ZV();
2315 14 : case INV_F8: return NULL;
2316 63 : case INV_W3W3: return phi5_w3w3_ZV();
2317 112 : case INV_W2W5: return phi7_w2w5_ZV();
2318 182 : case INV_W2W7: return phi3_w2w7_ZV();
2319 35 : case INV_W3W5: return phi2_w3w5_ZV();
2320 42 : case INV_W3W7: return phi5_w3w7_ZV();
2321 14 : case INV_W2W3E2: return NULL;
2322 28 : case INV_W2W5E2: return NULL;
2323 49 : case INV_W2W13: return phi3_w2w13_ZV();
2324 63 : case INV_W2W7E2: return NULL;
2325 21 : case INV_W3W3E2: return phi2_w3w3e2_ZV();
2326 56 : case INV_W5W7: return phi2_w5w7_ZV();
2327 14 : case INV_W3W13: return phi2_w3w13_ZV();
2328 : }
2329 0 : pari_err_BUG("internal_db");
2330 : return NULL;/*LCOV_EXCL_LINE*/
2331 : }
2332 :
2333 : /* NB: Should only be called if L <= modinv_max_internal_level(inv) */
2334 : static GEN
2335 24838 : polmodular_small_ZM(long L, long inv, GEN *db)
2336 : {
2337 24838 : GEN f = internal_db(L, inv);
2338 24838 : if (!f) return polmodular0_powerup_ZM(L, inv, db);
2339 24691 : return sympol_to_ZM(f, L);
2340 : }
2341 :
2342 : /* Each function phi_w?w?_j() returns a vector V containing two
2343 : * vectors u and v, and a scalar k, which together represent the
2344 : * bivariate polnomial
2345 : *
2346 : * phi(X, Y) = \sum_i u[i] X^i + Y \sum_i v[i] X^i + Y^2 X^k
2347 : */
2348 : static GEN
2349 1060 : phi_w2w3_j(void)
2350 : {
2351 : GEN phi, phi0, phi1;
2352 1060 : phi = cgetg(4, t_VEC);
2353 :
2354 1060 : phi0 = cgetg(14, t_VEC);
2355 1060 : gel(phi0, 1) = gen_1;
2356 1060 : gel(phi0, 2) = utoineg(0x3cUL);
2357 1060 : gel(phi0, 3) = utoi(0x702UL);
2358 1060 : gel(phi0, 4) = utoineg(0x797cUL);
2359 1060 : gel(phi0, 5) = utoi(0x5046fUL);
2360 1060 : gel(phi0, 6) = utoineg(0x1be0b8UL);
2361 1060 : gel(phi0, 7) = utoi(0x28ef9cUL);
2362 1060 : gel(phi0, 8) = utoi(0x15e2968UL);
2363 1060 : gel(phi0, 9) = utoi(0x1b8136fUL);
2364 1060 : gel(phi0, 10) = utoi(0xa67674UL);
2365 1060 : gel(phi0, 11) = utoi(0x23982UL);
2366 1060 : gel(phi0, 12) = utoi(0x294UL);
2367 1060 : gel(phi0, 13) = gen_1;
2368 :
2369 1060 : phi1 = cgetg(13, t_VEC);
2370 1060 : gel(phi1, 1) = gen_0;
2371 1060 : gel(phi1, 2) = gen_0;
2372 1060 : gel(phi1, 3) = gen_m1;
2373 1060 : gel(phi1, 4) = utoi(0x23UL);
2374 1060 : gel(phi1, 5) = utoineg(0xaeUL);
2375 1060 : gel(phi1, 6) = utoineg(0x5b8UL);
2376 1060 : gel(phi1, 7) = utoi(0x12d7UL);
2377 1060 : gel(phi1, 8) = utoineg(0x7c86UL);
2378 1060 : gel(phi1, 9) = utoi(0x37c8UL);
2379 1060 : gel(phi1, 10) = utoineg(0x69cUL);
2380 1060 : gel(phi1, 11) = utoi(0x48UL);
2381 1060 : gel(phi1, 12) = gen_m1;
2382 :
2383 1060 : gel(phi, 1) = phi0;
2384 1060 : gel(phi, 2) = phi1;
2385 1060 : gel(phi, 3) = utoi(5); return phi;
2386 : }
2387 :
2388 : static GEN
2389 3535 : phi_w3w3_j(void)
2390 : {
2391 : GEN phi, phi0, phi1;
2392 3535 : phi = cgetg(4, t_VEC);
2393 :
2394 3535 : phi0 = cgetg(14, t_VEC);
2395 3535 : gel(phi0, 1) = utoi(0x2d9UL);
2396 3535 : gel(phi0, 2) = utoi(0x4fbcUL);
2397 3535 : gel(phi0, 3) = utoi(0x5828aUL);
2398 3535 : gel(phi0, 4) = utoi(0x3a7a3cUL);
2399 3535 : gel(phi0, 5) = utoi(0x1bd8edfUL);
2400 3535 : gel(phi0, 6) = utoi(0x8348838UL);
2401 3535 : gel(phi0, 7) = utoi(0x1983f8acUL);
2402 3535 : gel(phi0, 8) = utoi(0x14e4e098UL);
2403 3535 : gel(phi0, 9) = utoi(0x69ed1a7UL);
2404 3535 : gel(phi0, 10) = utoi(0xc3828cUL);
2405 3535 : gel(phi0, 11) = utoi(0x2696aUL);
2406 3535 : gel(phi0, 12) = utoi(0x2acUL);
2407 3535 : gel(phi0, 13) = gen_1;
2408 :
2409 3535 : phi1 = cgetg(13, t_VEC);
2410 3535 : gel(phi1, 1) = gen_0;
2411 3535 : gel(phi1, 2) = utoineg(0x1bUL);
2412 3535 : gel(phi1, 3) = utoineg(0x5d6UL);
2413 3535 : gel(phi1, 4) = utoineg(0x1c7bUL);
2414 3535 : gel(phi1, 5) = utoi(0x7980UL);
2415 3535 : gel(phi1, 6) = utoi(0x12168UL);
2416 3535 : gel(phi1, 7) = utoineg(0x3528UL);
2417 3535 : gel(phi1, 8) = utoineg(0x6174UL);
2418 3535 : gel(phi1, 9) = utoi(0x2208UL);
2419 3535 : gel(phi1, 10) = utoineg(0x41dUL);
2420 3535 : gel(phi1, 11) = utoi(0x36UL);
2421 3535 : gel(phi1, 12) = gen_m1;
2422 :
2423 3535 : gel(phi, 1) = phi0;
2424 3535 : gel(phi, 2) = phi1;
2425 3535 : gel(phi, 3) = gen_2; return phi;
2426 : }
2427 :
2428 : static GEN
2429 3242 : phi_w2w5_j(void)
2430 : {
2431 : GEN phi, phi0, phi1;
2432 3242 : phi = cgetg(4, t_VEC);
2433 :
2434 3242 : phi0 = cgetg(20, t_VEC);
2435 3242 : gel(phi0, 1) = gen_1;
2436 3242 : gel(phi0, 2) = utoineg(0x2aUL);
2437 3242 : gel(phi0, 3) = utoi(0x549UL);
2438 3242 : gel(phi0, 4) = utoineg(0x6530UL);
2439 3242 : gel(phi0, 5) = utoi(0x60504UL);
2440 3242 : gel(phi0, 6) = utoineg(0x3cbbc8UL);
2441 3242 : gel(phi0, 7) = utoi(0x1d1ee74UL);
2442 3242 : gel(phi0, 8) = utoineg(0x7ef9ab0UL);
2443 3242 : gel(phi0, 9) = utoi(0x12b888beUL);
2444 3242 : gel(phi0, 10) = utoineg(0x15fa174cUL);
2445 3242 : gel(phi0, 11) = utoi(0x615d9feUL);
2446 3242 : gel(phi0, 12) = utoi(0xbeca070UL);
2447 3242 : gel(phi0, 13) = utoineg(0x88de74cUL);
2448 3242 : gel(phi0, 14) = utoineg(0x2b3a268UL);
2449 3242 : gel(phi0, 15) = utoi(0x24b3244UL);
2450 3242 : gel(phi0, 16) = utoi(0xb56270UL);
2451 3242 : gel(phi0, 17) = utoi(0x25989UL);
2452 3242 : gel(phi0, 18) = utoi(0x2a6UL);
2453 3242 : gel(phi0, 19) = gen_1;
2454 :
2455 3242 : phi1 = cgetg(19, t_VEC);
2456 3242 : gel(phi1, 1) = gen_0;
2457 3242 : gel(phi1, 2) = gen_0;
2458 3242 : gel(phi1, 3) = gen_m1;
2459 3242 : gel(phi1, 4) = utoi(0x1eUL);
2460 3242 : gel(phi1, 5) = utoineg(0xffUL);
2461 3242 : gel(phi1, 6) = utoi(0x243UL);
2462 3242 : gel(phi1, 7) = utoineg(0xf3UL);
2463 3242 : gel(phi1, 8) = utoineg(0x5c4UL);
2464 3242 : gel(phi1, 9) = utoi(0x107bUL);
2465 3242 : gel(phi1, 10) = utoineg(0x11b2fUL);
2466 3242 : gel(phi1, 11) = utoi(0x48fa8UL);
2467 3242 : gel(phi1, 12) = utoineg(0x6ff7cUL);
2468 3242 : gel(phi1, 13) = utoi(0x4bf48UL);
2469 3242 : gel(phi1, 14) = utoineg(0x187efUL);
2470 3242 : gel(phi1, 15) = utoi(0x404cUL);
2471 3242 : gel(phi1, 16) = utoineg(0x582UL);
2472 3242 : gel(phi1, 17) = utoi(0x3cUL);
2473 3242 : gel(phi1, 18) = gen_m1;
2474 :
2475 3242 : gel(phi, 1) = phi0;
2476 3242 : gel(phi, 2) = phi1;
2477 3242 : gel(phi, 3) = utoi(7); return phi;
2478 : }
2479 :
2480 : static GEN
2481 6520 : phi_w2w7_j(void)
2482 : {
2483 : GEN phi, phi0, phi1;
2484 6520 : phi = cgetg(4, t_VEC);
2485 :
2486 6520 : phi0 = cgetg(26, t_VEC);
2487 6520 : gel(phi0, 1) = gen_1;
2488 6520 : gel(phi0, 2) = utoineg(0x24UL);
2489 6520 : gel(phi0, 3) = utoi(0x4ceUL);
2490 6520 : gel(phi0, 4) = utoineg(0x5d60UL);
2491 6520 : gel(phi0, 5) = utoi(0x62b05UL);
2492 6520 : gel(phi0, 6) = utoineg(0x47be78UL);
2493 6520 : gel(phi0, 7) = utoi(0x2a3880aUL);
2494 6520 : gel(phi0, 8) = utoineg(0x114bccf4UL);
2495 6520 : gel(phi0, 9) = utoi(0x4b95e79aUL);
2496 6520 : gel(phi0, 10) = utoineg(0xe2cfee1cUL);
2497 6520 : gel(phi0, 11) = uu32toi(0x1UL, 0xe43d1126UL);
2498 6520 : gel(phi0, 12) = uu32toineg(0x2UL, 0xf04dc6f8UL);
2499 6520 : gel(phi0, 13) = uu32toi(0x3UL, 0x5384987dUL);
2500 6520 : gel(phi0, 14) = uu32toineg(0x2UL, 0xa5ccbe18UL);
2501 6520 : gel(phi0, 15) = uu32toi(0x1UL, 0x4c52c8a6UL);
2502 6520 : gel(phi0, 16) = utoineg(0x2643fdecUL);
2503 6520 : gel(phi0, 17) = utoineg(0x49f5ab66UL);
2504 6520 : gel(phi0, 18) = utoi(0x33074d3cUL);
2505 6520 : gel(phi0, 19) = utoineg(0x6a3e376UL);
2506 6520 : gel(phi0, 20) = utoineg(0x675aa58UL);
2507 6520 : gel(phi0, 21) = utoi(0x2674005UL);
2508 6520 : gel(phi0, 22) = utoi(0xba5be0UL);
2509 6520 : gel(phi0, 23) = utoi(0x2644eUL);
2510 6520 : gel(phi0, 24) = utoi(0x2acUL);
2511 6520 : gel(phi0, 25) = gen_1;
2512 :
2513 6520 : phi1 = cgetg(25, t_VEC);
2514 6520 : gel(phi1, 1) = gen_0;
2515 6520 : gel(phi1, 2) = gen_0;
2516 6520 : gel(phi1, 3) = gen_m1;
2517 6520 : gel(phi1, 4) = utoi(0x1cUL);
2518 6520 : gel(phi1, 5) = utoineg(0x10aUL);
2519 6520 : gel(phi1, 6) = utoi(0x3f0UL);
2520 6520 : gel(phi1, 7) = utoineg(0x5d3UL);
2521 6520 : gel(phi1, 8) = utoi(0x3efUL);
2522 6520 : gel(phi1, 9) = utoineg(0x102UL);
2523 6520 : gel(phi1, 10) = utoineg(0x5c8UL);
2524 6520 : gel(phi1, 11) = utoi(0x102fUL);
2525 6520 : gel(phi1, 12) = utoineg(0x13f8aUL);
2526 6520 : gel(phi1, 13) = utoi(0x86538UL);
2527 6520 : gel(phi1, 14) = utoineg(0x1bbd10UL);
2528 6520 : gel(phi1, 15) = utoi(0x3614e8UL);
2529 6520 : gel(phi1, 16) = utoineg(0x42f793UL);
2530 6520 : gel(phi1, 17) = utoi(0x364698UL);
2531 6520 : gel(phi1, 18) = utoineg(0x1c7a10UL);
2532 6520 : gel(phi1, 19) = utoi(0x97cc8UL);
2533 6520 : gel(phi1, 20) = utoineg(0x1fc8aUL);
2534 6520 : gel(phi1, 21) = utoi(0x4210UL);
2535 6520 : gel(phi1, 22) = utoineg(0x524UL);
2536 6520 : gel(phi1, 23) = utoi(0x38UL);
2537 6520 : gel(phi1, 24) = gen_m1;
2538 :
2539 6520 : gel(phi, 1) = phi0;
2540 6520 : gel(phi, 2) = phi1;
2541 6520 : gel(phi, 3) = utoi(9); return phi;
2542 : }
2543 :
2544 : static GEN
2545 2937 : phi_w2w13_j(void)
2546 : {
2547 : GEN phi, phi0, phi1;
2548 2937 : phi = cgetg(4, t_VEC);
2549 :
2550 2937 : phi0 = cgetg(44, t_VEC);
2551 2937 : gel(phi0, 1) = gen_1;
2552 2937 : gel(phi0, 2) = utoineg(0x1eUL);
2553 2937 : gel(phi0, 3) = utoi(0x45fUL);
2554 2937 : gel(phi0, 4) = utoineg(0x5590UL);
2555 2937 : gel(phi0, 5) = utoi(0x64407UL);
2556 2937 : gel(phi0, 6) = utoineg(0x53a792UL);
2557 2937 : gel(phi0, 7) = utoi(0x3b21af3UL);
2558 2937 : gel(phi0, 8) = utoineg(0x20d056d0UL);
2559 2937 : gel(phi0, 9) = utoi(0xe02db4a6UL);
2560 2937 : gel(phi0, 10) = uu32toineg(0x4UL, 0xb23400b0UL);
2561 2937 : gel(phi0, 11) = uu32toi(0x14UL, 0x57fbb906UL);
2562 2937 : gel(phi0, 12) = uu32toineg(0x49UL, 0xcf80c00UL);
2563 2937 : gel(phi0, 13) = uu32toi(0xdeUL, 0x84ff421UL);
2564 2937 : gel(phi0, 14) = uu32toineg(0x244UL, 0xc500c156UL);
2565 2937 : gel(phi0, 15) = uu32toi(0x52cUL, 0x79162979UL);
2566 2937 : gel(phi0, 16) = uu32toineg(0xa64UL, 0x8edc5650UL);
2567 2937 : gel(phi0, 17) = uu32toi(0x1289UL, 0x4225bb41UL);
2568 2937 : gel(phi0, 18) = uu32toineg(0x1d89UL, 0x2a15229aUL);
2569 2937 : gel(phi0, 19) = uu32toi(0x2a3eUL, 0x4539f1ebUL);
2570 2937 : gel(phi0, 20) = uu32toineg(0x366aUL, 0xa5ea1130UL);
2571 2937 : gel(phi0, 21) = uu32toi(0x3f47UL, 0xa19fecb4UL);
2572 2937 : gel(phi0, 22) = uu32toineg(0x4282UL, 0x91a3c4a0UL);
2573 2937 : gel(phi0, 23) = uu32toi(0x3f30UL, 0xbaa305b4UL);
2574 2937 : gel(phi0, 24) = uu32toineg(0x3635UL, 0xd11c2530UL);
2575 2937 : gel(phi0, 25) = uu32toi(0x29e2UL, 0x89df27ebUL);
2576 2937 : gel(phi0, 26) = uu32toineg(0x1d03UL, 0x6509d48aUL);
2577 2937 : gel(phi0, 27) = uu32toi(0x11e2UL, 0x272cc601UL);
2578 2937 : gel(phi0, 28) = uu32toineg(0x9b0UL, 0xacd58ff0UL);
2579 2937 : gel(phi0, 29) = uu32toi(0x485UL, 0x608d7db9UL);
2580 2937 : gel(phi0, 30) = uu32toineg(0x1bfUL, 0xa941546UL);
2581 2937 : gel(phi0, 31) = uu32toi(0x82UL, 0x56e48b21UL);
2582 2937 : gel(phi0, 32) = uu32toineg(0x13UL, 0xc36b2340UL);
2583 2937 : gel(phi0, 33) = uu32toineg(0x5UL, 0x6637257aUL);
2584 2937 : gel(phi0, 34) = uu32toi(0x5UL, 0x40f70bd0UL);
2585 2937 : gel(phi0, 35) = uu32toineg(0x1UL, 0xf70842daUL);
2586 2937 : gel(phi0, 36) = utoi(0x53eea5f0UL);
2587 2937 : gel(phi0, 37) = utoi(0xda17bf3UL);
2588 2937 : gel(phi0, 38) = utoineg(0xaf246c2UL);
2589 2937 : gel(phi0, 39) = utoi(0x278f847UL);
2590 2937 : gel(phi0, 40) = utoi(0xbf5550UL);
2591 2937 : gel(phi0, 41) = utoi(0x26f1fUL);
2592 2937 : gel(phi0, 42) = utoi(0x2b2UL);
2593 2937 : gel(phi0, 43) = gen_1;
2594 :
2595 2937 : phi1 = cgetg(43, t_VEC);
2596 2937 : gel(phi1, 1) = gen_0;
2597 2937 : gel(phi1, 2) = gen_0;
2598 2937 : gel(phi1, 3) = gen_m1;
2599 2937 : gel(phi1, 4) = utoi(0x1aUL);
2600 2937 : gel(phi1, 5) = utoineg(0x111UL);
2601 2937 : gel(phi1, 6) = utoi(0x5e4UL);
2602 2937 : gel(phi1, 7) = utoineg(0x1318UL);
2603 2937 : gel(phi1, 8) = utoi(0x2804UL);
2604 2937 : gel(phi1, 9) = utoineg(0x3cd6UL);
2605 2937 : gel(phi1, 10) = utoi(0x467cUL);
2606 2937 : gel(phi1, 11) = utoineg(0x3cd6UL);
2607 2937 : gel(phi1, 12) = utoi(0x2804UL);
2608 2937 : gel(phi1, 13) = utoineg(0x1318UL);
2609 2937 : gel(phi1, 14) = utoi(0x5e3UL);
2610 2937 : gel(phi1, 15) = utoineg(0x10dUL);
2611 2937 : gel(phi1, 16) = utoineg(0x5ccUL);
2612 2937 : gel(phi1, 17) = utoi(0x100bUL);
2613 2937 : gel(phi1, 18) = utoineg(0x160e1UL);
2614 2937 : gel(phi1, 19) = utoi(0xd2cb0UL);
2615 2937 : gel(phi1, 20) = utoineg(0x4c85fcUL);
2616 2937 : gel(phi1, 21) = utoi(0x137cb98UL);
2617 2937 : gel(phi1, 22) = utoineg(0x3c75568UL);
2618 2937 : gel(phi1, 23) = utoi(0x95c69c8UL);
2619 2937 : gel(phi1, 24) = utoineg(0x131557bcUL);
2620 2937 : gel(phi1, 25) = utoi(0x20aacfd0UL);
2621 2937 : gel(phi1, 26) = utoineg(0x2f9164e6UL);
2622 2937 : gel(phi1, 27) = utoi(0x3b6a5e40UL);
2623 2937 : gel(phi1, 28) = utoineg(0x3ff54344UL);
2624 2937 : gel(phi1, 29) = utoi(0x3b6a9140UL);
2625 2937 : gel(phi1, 30) = utoineg(0x2f927fa6UL);
2626 2937 : gel(phi1, 31) = utoi(0x20ae6450UL);
2627 2937 : gel(phi1, 32) = utoineg(0x131cd87cUL);
2628 2937 : gel(phi1, 33) = utoi(0x967d1e8UL);
2629 2937 : gel(phi1, 34) = utoineg(0x3d48ca8UL);
2630 2937 : gel(phi1, 35) = utoi(0x14333b8UL);
2631 2937 : gel(phi1, 36) = utoineg(0x5406bcUL);
2632 2937 : gel(phi1, 37) = utoi(0x10c130UL);
2633 2937 : gel(phi1, 38) = utoineg(0x27ba1UL);
2634 2937 : gel(phi1, 39) = utoi(0x433cUL);
2635 2937 : gel(phi1, 40) = utoineg(0x4c6UL);
2636 2937 : gel(phi1, 41) = utoi(0x34UL);
2637 2937 : gel(phi1, 42) = gen_m1;
2638 :
2639 2937 : gel(phi, 1) = phi0;
2640 2937 : gel(phi, 2) = phi1;
2641 2937 : gel(phi, 3) = utoi(15); return phi;
2642 : }
2643 :
2644 : static GEN
2645 1137 : phi_w3w5_j(void)
2646 : {
2647 : GEN phi, phi0, phi1;
2648 1137 : phi = cgetg(4, t_VEC);
2649 :
2650 1137 : phi0 = cgetg(26, t_VEC);
2651 1137 : gel(phi0, 1) = gen_1;
2652 1137 : gel(phi0, 2) = utoi(0x18UL);
2653 1137 : gel(phi0, 3) = utoi(0xb4UL);
2654 1137 : gel(phi0, 4) = utoineg(0x178UL);
2655 1137 : gel(phi0, 5) = utoineg(0x2d7eUL);
2656 1137 : gel(phi0, 6) = utoineg(0x89b8UL);
2657 1137 : gel(phi0, 7) = utoi(0x35c24UL);
2658 1137 : gel(phi0, 8) = utoi(0x128a18UL);
2659 1137 : gel(phi0, 9) = utoineg(0x12a911UL);
2660 1137 : gel(phi0, 10) = utoineg(0xcc0190UL);
2661 1137 : gel(phi0, 11) = utoi(0x94368UL);
2662 1137 : gel(phi0, 12) = utoi(0x1439d0UL);
2663 1137 : gel(phi0, 13) = utoi(0x96f931cUL);
2664 1137 : gel(phi0, 14) = utoineg(0x1f59ff0UL);
2665 1137 : gel(phi0, 15) = utoi(0x20e7e8UL);
2666 1137 : gel(phi0, 16) = utoineg(0x25fdf150UL);
2667 1137 : gel(phi0, 17) = utoineg(0x7091511UL);
2668 1137 : gel(phi0, 18) = utoi(0x1ef52f8UL);
2669 1137 : gel(phi0, 19) = utoi(0x341f2de4UL);
2670 1137 : gel(phi0, 20) = utoi(0x25d72c28UL);
2671 1137 : gel(phi0, 21) = utoi(0x95d2082UL);
2672 1137 : gel(phi0, 22) = utoi(0xd2d828UL);
2673 1137 : gel(phi0, 23) = utoi(0x281f4UL);
2674 1137 : gel(phi0, 24) = utoi(0x2b8UL);
2675 1137 : gel(phi0, 25) = gen_1;
2676 :
2677 1137 : phi1 = cgetg(25, t_VEC);
2678 1137 : gel(phi1, 1) = gen_0;
2679 1137 : gel(phi1, 2) = gen_0;
2680 1137 : gel(phi1, 3) = gen_0;
2681 1137 : gel(phi1, 4) = gen_1;
2682 1137 : gel(phi1, 5) = utoi(0xfUL);
2683 1137 : gel(phi1, 6) = utoi(0x2eUL);
2684 1137 : gel(phi1, 7) = utoineg(0x1fUL);
2685 1137 : gel(phi1, 8) = utoineg(0x2dUL);
2686 1137 : gel(phi1, 9) = utoineg(0x5caUL);
2687 1137 : gel(phi1, 10) = utoineg(0x358UL);
2688 1137 : gel(phi1, 11) = utoi(0x2f1cUL);
2689 1137 : gel(phi1, 12) = utoi(0xd8eaUL);
2690 1137 : gel(phi1, 13) = utoineg(0x38c70UL);
2691 1137 : gel(phi1, 14) = utoineg(0x1a964UL);
2692 1137 : gel(phi1, 15) = utoi(0x93512UL);
2693 1137 : gel(phi1, 16) = utoineg(0x58f2UL);
2694 1137 : gel(phi1, 17) = utoineg(0x5af1eUL);
2695 1137 : gel(phi1, 18) = utoi(0x1afb8UL);
2696 1137 : gel(phi1, 19) = utoi(0xc084UL);
2697 1137 : gel(phi1, 20) = utoineg(0x7fcbUL);
2698 1137 : gel(phi1, 21) = utoi(0x1c89UL);
2699 1137 : gel(phi1, 22) = utoineg(0x32aUL);
2700 1137 : gel(phi1, 23) = utoi(0x2dUL);
2701 1137 : gel(phi1, 24) = gen_m1;
2702 :
2703 1137 : gel(phi, 1) = phi0;
2704 1137 : gel(phi, 2) = phi1;
2705 1137 : gel(phi, 3) = utoi(8); return phi;
2706 : }
2707 :
2708 : static GEN
2709 2412 : phi_w3w7_j(void)
2710 : {
2711 : GEN phi, phi0, phi1;
2712 2412 : phi = cgetg(4, t_VEC);
2713 :
2714 2412 : phi0 = cgetg(34, t_VEC);
2715 2412 : gel(phi0, 1) = gen_1;
2716 2412 : gel(phi0, 2) = utoineg(0x14UL);
2717 2412 : gel(phi0, 3) = utoi(0x82UL);
2718 2412 : gel(phi0, 4) = utoi(0x1f8UL);
2719 2412 : gel(phi0, 5) = utoineg(0x2a45UL);
2720 2412 : gel(phi0, 6) = utoi(0x9300UL);
2721 2412 : gel(phi0, 7) = utoi(0x32abeUL);
2722 2412 : gel(phi0, 8) = utoineg(0x19c91cUL);
2723 2412 : gel(phi0, 9) = utoi(0xc1ba9UL);
2724 2412 : gel(phi0, 10) = utoi(0x1788f68UL);
2725 2412 : gel(phi0, 11) = utoineg(0x2b1989cUL);
2726 2412 : gel(phi0, 12) = utoineg(0x7a92408UL);
2727 2412 : gel(phi0, 13) = utoi(0x1238d56eUL);
2728 2412 : gel(phi0, 14) = utoi(0x13dd66a0UL);
2729 2412 : gel(phi0, 15) = utoineg(0x2dbedca8UL);
2730 2412 : gel(phi0, 16) = utoineg(0x34282eb8UL);
2731 2412 : gel(phi0, 17) = utoi(0x2c2a54d2UL);
2732 2412 : gel(phi0, 18) = utoi(0x98db81a8UL);
2733 2412 : gel(phi0, 19) = utoineg(0x4088be8UL);
2734 2412 : gel(phi0, 20) = utoineg(0xe424a220UL);
2735 2412 : gel(phi0, 21) = utoineg(0x67bbb232UL);
2736 2412 : gel(phi0, 22) = utoi(0x7dd8bb98UL);
2737 2412 : gel(phi0, 23) = uu32toi(0x1UL, 0xcaff744UL);
2738 2412 : gel(phi0, 24) = utoineg(0x1d46a378UL);
2739 2412 : gel(phi0, 25) = utoineg(0x82fa50f7UL);
2740 2412 : gel(phi0, 26) = utoineg(0x700ef38cUL);
2741 2412 : gel(phi0, 27) = utoi(0x20aa202eUL);
2742 2412 : gel(phi0, 28) = utoi(0x299b3440UL);
2743 2412 : gel(phi0, 29) = utoi(0xa476c4bUL);
2744 2412 : gel(phi0, 30) = utoi(0xd80558UL);
2745 2412 : gel(phi0, 31) = utoi(0x28a32UL);
2746 2412 : gel(phi0, 32) = utoi(0x2bcUL);
2747 2412 : gel(phi0, 33) = gen_1;
2748 :
2749 2412 : phi1 = cgetg(33, t_VEC);
2750 2412 : gel(phi1, 1) = gen_0;
2751 2412 : gel(phi1, 2) = gen_0;
2752 2412 : gel(phi1, 3) = gen_0;
2753 2412 : gel(phi1, 4) = gen_m1;
2754 2412 : gel(phi1, 5) = utoi(0xeUL);
2755 2412 : gel(phi1, 6) = utoineg(0x31UL);
2756 2412 : gel(phi1, 7) = utoineg(0xeUL);
2757 2412 : gel(phi1, 8) = utoi(0x99UL);
2758 2412 : gel(phi1, 9) = utoineg(0x8UL);
2759 2412 : gel(phi1, 10) = utoineg(0x2eUL);
2760 2412 : gel(phi1, 11) = utoineg(0x5ccUL);
2761 2412 : gel(phi1, 12) = utoi(0x308UL);
2762 2412 : gel(phi1, 13) = utoi(0x2904UL);
2763 2412 : gel(phi1, 14) = utoineg(0x15700UL);
2764 2412 : gel(phi1, 15) = utoineg(0x2b9ecUL);
2765 2412 : gel(phi1, 16) = utoi(0xf0966UL);
2766 2412 : gel(phi1, 17) = utoi(0xb3cc8UL);
2767 2412 : gel(phi1, 18) = utoineg(0x38241cUL);
2768 2412 : gel(phi1, 19) = utoineg(0x8604cUL);
2769 2412 : gel(phi1, 20) = utoi(0x578a64UL);
2770 2412 : gel(phi1, 21) = utoineg(0x11a798UL);
2771 2412 : gel(phi1, 22) = utoineg(0x39c85eUL);
2772 2412 : gel(phi1, 23) = utoi(0x1a5084UL);
2773 2412 : gel(phi1, 24) = utoi(0xcdeb4UL);
2774 2412 : gel(phi1, 25) = utoineg(0xb0364UL);
2775 2412 : gel(phi1, 26) = utoi(0x129d4UL);
2776 2412 : gel(phi1, 27) = utoi(0x126fcUL);
2777 2412 : gel(phi1, 28) = utoineg(0x8649UL);
2778 2412 : gel(phi1, 29) = utoi(0x1aa2UL);
2779 2412 : gel(phi1, 30) = utoineg(0x2dfUL);
2780 2412 : gel(phi1, 31) = utoi(0x2aUL);
2781 2412 : gel(phi1, 32) = gen_m1;
2782 :
2783 2412 : gel(phi, 1) = phi0;
2784 2412 : gel(phi, 2) = phi1;
2785 2412 : gel(phi, 3) = utoi(10); return phi;
2786 : }
2787 :
2788 : static GEN
2789 210 : phi_w3w13_j(void)
2790 : {
2791 : GEN phi, phi0, phi1;
2792 210 : phi = cgetg(4, t_VEC);
2793 :
2794 210 : phi0 = cgetg(58, t_VEC);
2795 210 : gel(phi0, 1) = gen_1;
2796 210 : gel(phi0, 2) = utoineg(0x10UL);
2797 210 : gel(phi0, 3) = utoi(0x58UL);
2798 210 : gel(phi0, 4) = utoi(0x258UL);
2799 210 : gel(phi0, 5) = utoineg(0x270cUL);
2800 210 : gel(phi0, 6) = utoi(0x9c00UL);
2801 210 : gel(phi0, 7) = utoi(0x2b40cUL);
2802 210 : gel(phi0, 8) = utoineg(0x20e250UL);
2803 210 : gel(phi0, 9) = utoi(0x4f46baUL);
2804 210 : gel(phi0, 10) = utoi(0x1869448UL);
2805 210 : gel(phi0, 11) = utoineg(0xa49ab68UL);
2806 210 : gel(phi0, 12) = utoi(0x96c7630UL);
2807 210 : gel(phi0, 13) = utoi(0x4f7e0af6UL);
2808 210 : gel(phi0, 14) = utoineg(0xea093590UL);
2809 210 : gel(phi0, 15) = utoineg(0x6735bc50UL);
2810 210 : gel(phi0, 16) = uu32toi(0x5UL, 0x971a2e08UL);
2811 210 : gel(phi0, 17) = uu32toineg(0x6UL, 0x29c9d965UL);
2812 210 : gel(phi0, 18) = uu32toineg(0xdUL, 0xeb9aa360UL);
2813 210 : gel(phi0, 19) = uu32toi(0x26UL, 0xe9c0584UL);
2814 210 : gel(phi0, 20) = uu32toineg(0x1UL, 0xb0cadce8UL);
2815 210 : gel(phi0, 21) = uu32toineg(0x62UL, 0x73586014UL);
2816 210 : gel(phi0, 22) = uu32toi(0x66UL, 0xaf672e38UL);
2817 210 : gel(phi0, 23) = uu32toi(0x6bUL, 0x93c28cdcUL);
2818 210 : gel(phi0, 24) = uu32toineg(0x11eUL, 0x4f633080UL);
2819 210 : gel(phi0, 25) = uu32toi(0x3cUL, 0xcc42461bUL);
2820 210 : gel(phi0, 26) = uu32toi(0x17bUL, 0xdec0a78UL);
2821 210 : gel(phi0, 27) = uu32toineg(0x166UL, 0x910d8bd0UL);
2822 210 : gel(phi0, 28) = uu32toineg(0xd4UL, 0x47873030UL);
2823 210 : gel(phi0, 29) = uu32toi(0x204UL, 0x811828baUL);
2824 210 : gel(phi0, 30) = uu32toineg(0x50UL, 0x5d713960UL);
2825 210 : gel(phi0, 31) = uu32toineg(0x198UL, 0xa27e42b0UL);
2826 210 : gel(phi0, 32) = uu32toi(0xe1UL, 0x25685138UL);
2827 210 : gel(phi0, 33) = uu32toi(0xe3UL, 0xaa5774bbUL);
2828 210 : gel(phi0, 34) = uu32toineg(0xcfUL, 0x392a9a00UL);
2829 210 : gel(phi0, 35) = uu32toineg(0x81UL, 0xfb334d04UL);
2830 210 : gel(phi0, 36) = uu32toi(0xabUL, 0x59594a68UL);
2831 210 : gel(phi0, 37) = uu32toi(0x42UL, 0x356993acUL);
2832 210 : gel(phi0, 38) = uu32toineg(0x86UL, 0x307ba678UL);
2833 210 : gel(phi0, 39) = uu32toineg(0xbUL, 0x7a9e59dcUL);
2834 210 : gel(phi0, 40) = uu32toi(0x4cUL, 0x27935f20UL);
2835 210 : gel(phi0, 41) = uu32toineg(0x2UL, 0xe0ac9045UL);
2836 210 : gel(phi0, 42) = uu32toineg(0x24UL, 0x14495758UL);
2837 210 : gel(phi0, 43) = utoi(0x20973410UL);
2838 210 : gel(phi0, 44) = uu32toi(0x13UL, 0x99ff4e00UL);
2839 210 : gel(phi0, 45) = uu32toineg(0x1UL, 0xa710d34aUL);
2840 210 : gel(phi0, 46) = uu32toineg(0x7UL, 0xfe5405c0UL);
2841 210 : gel(phi0, 47) = uu32toi(0x1UL, 0xcdee0f8UL);
2842 210 : gel(phi0, 48) = uu32toi(0x2UL, 0x660c92a8UL);
2843 210 : gel(phi0, 49) = utoi(0x3f13a35aUL);
2844 210 : gel(phi0, 50) = utoineg(0xe4eb4ba0UL);
2845 210 : gel(phi0, 51) = utoineg(0x6420f4UL);
2846 210 : gel(phi0, 52) = utoi(0x2c624370UL);
2847 210 : gel(phi0, 53) = utoi(0xb31b814UL);
2848 210 : gel(phi0, 54) = utoi(0xdd3ad8UL);
2849 210 : gel(phi0, 55) = utoi(0x29278UL);
2850 210 : gel(phi0, 56) = utoi(0x2c0UL);
2851 210 : gel(phi0, 57) = gen_1;
2852 :
2853 210 : phi1 = cgetg(57, t_VEC);
2854 210 : gel(phi1, 1) = gen_0;
2855 210 : gel(phi1, 2) = gen_0;
2856 210 : gel(phi1, 3) = gen_0;
2857 210 : gel(phi1, 4) = gen_m1;
2858 210 : gel(phi1, 5) = utoi(0xdUL);
2859 210 : gel(phi1, 6) = utoineg(0x34UL);
2860 210 : gel(phi1, 7) = utoi(0x1aUL);
2861 210 : gel(phi1, 8) = utoi(0xf7UL);
2862 210 : gel(phi1, 9) = utoineg(0x16cUL);
2863 210 : gel(phi1, 10) = utoineg(0xddUL);
2864 210 : gel(phi1, 11) = utoi(0x28aUL);
2865 210 : gel(phi1, 12) = utoineg(0xddUL);
2866 210 : gel(phi1, 13) = utoineg(0x16cUL);
2867 210 : gel(phi1, 14) = utoi(0xf6UL);
2868 210 : gel(phi1, 15) = utoi(0x1dUL);
2869 210 : gel(phi1, 16) = utoineg(0x31UL);
2870 210 : gel(phi1, 17) = utoineg(0x5ceUL);
2871 210 : gel(phi1, 18) = utoi(0x2e4UL);
2872 210 : gel(phi1, 19) = utoi(0x252cUL);
2873 210 : gel(phi1, 20) = utoineg(0x1b34cUL);
2874 210 : gel(phi1, 21) = utoi(0xaf80UL);
2875 210 : gel(phi1, 22) = utoi(0x1cc5f9UL);
2876 210 : gel(phi1, 23) = utoineg(0x3e1aa5UL);
2877 210 : gel(phi1, 24) = utoineg(0x86d17aUL);
2878 210 : gel(phi1, 25) = utoi(0x2427264UL);
2879 210 : gel(phi1, 26) = utoineg(0x691c1fUL);
2880 210 : gel(phi1, 27) = utoineg(0x862ad4eUL);
2881 210 : gel(phi1, 28) = utoi(0xab21e1fUL);
2882 210 : gel(phi1, 29) = utoi(0xbc19ddcUL);
2883 210 : gel(phi1, 30) = utoineg(0x24331db8UL);
2884 210 : gel(phi1, 31) = utoi(0x972c105UL);
2885 210 : gel(phi1, 32) = utoi(0x363d7107UL);
2886 210 : gel(phi1, 33) = utoineg(0x39696450UL);
2887 210 : gel(phi1, 34) = utoineg(0x1bce7c48UL);
2888 210 : gel(phi1, 35) = utoi(0x552ecba0UL);
2889 210 : gel(phi1, 36) = utoineg(0x1c7771b8UL);
2890 210 : gel(phi1, 37) = utoineg(0x393029b8UL);
2891 210 : gel(phi1, 38) = utoi(0x3755be97UL);
2892 210 : gel(phi1, 39) = utoi(0x83402a9UL);
2893 210 : gel(phi1, 40) = utoineg(0x24d5be62UL);
2894 210 : gel(phi1, 41) = utoi(0xdb6d90aUL);
2895 210 : gel(phi1, 42) = utoi(0xa0ef177UL);
2896 210 : gel(phi1, 43) = utoineg(0x99ff162UL);
2897 210 : gel(phi1, 44) = utoi(0xb09e27UL);
2898 210 : gel(phi1, 45) = utoi(0x26a7adcUL);
2899 210 : gel(phi1, 46) = utoineg(0x116e2fcUL);
2900 210 : gel(phi1, 47) = utoineg(0x1383b5UL);
2901 210 : gel(phi1, 48) = utoi(0x35a9e7UL);
2902 210 : gel(phi1, 49) = utoineg(0x1082a0UL);
2903 210 : gel(phi1, 50) = utoineg(0x4696UL);
2904 210 : gel(phi1, 51) = utoi(0x19f98UL);
2905 210 : gel(phi1, 52) = utoineg(0x8bb3UL);
2906 210 : gel(phi1, 53) = utoi(0x18bbUL);
2907 210 : gel(phi1, 54) = utoineg(0x297UL);
2908 210 : gel(phi1, 55) = utoi(0x27UL);
2909 210 : gel(phi1, 56) = gen_m1;
2910 :
2911 210 : gel(phi, 1) = phi0;
2912 210 : gel(phi, 2) = phi1;
2913 210 : gel(phi, 3) = utoi(16); return phi;
2914 : }
2915 :
2916 : static GEN
2917 2884 : phi_w5w7_j(void)
2918 : {
2919 : GEN phi, phi0, phi1;
2920 2884 : phi = cgetg(4, t_VEC);
2921 :
2922 2884 : phi0 = cgetg(50, t_VEC);
2923 2884 : gel(phi0, 1) = gen_1;
2924 2884 : gel(phi0, 2) = utoi(0xcUL);
2925 2884 : gel(phi0, 3) = utoi(0x2aUL);
2926 2883 : gel(phi0, 4) = utoi(0x10UL);
2927 2883 : gel(phi0, 5) = utoineg(0x69UL);
2928 2883 : gel(phi0, 6) = utoineg(0x318UL);
2929 2883 : gel(phi0, 7) = utoineg(0x148aUL);
2930 2883 : gel(phi0, 8) = utoineg(0x17c4UL);
2931 2883 : gel(phi0, 9) = utoi(0x1a73UL);
2932 2883 : gel(phi0, 10) = gen_0;
2933 2883 : gel(phi0, 11) = utoi(0x338a0UL);
2934 2883 : gel(phi0, 12) = utoi(0x61698UL);
2935 2883 : gel(phi0, 13) = utoineg(0x96e8UL);
2936 2883 : gel(phi0, 14) = utoi(0x140910UL);
2937 2883 : gel(phi0, 15) = utoineg(0x45f6b4UL);
2938 2883 : gel(phi0, 16) = utoineg(0x309f50UL);
2939 2883 : gel(phi0, 17) = utoineg(0xef9f8bUL);
2940 2883 : gel(phi0, 18) = utoineg(0x283167cUL);
2941 2883 : gel(phi0, 19) = utoi(0x625e20aUL);
2942 2883 : gel(phi0, 20) = utoineg(0x16186350UL);
2943 2883 : gel(phi0, 21) = utoi(0x46861281UL);
2944 2883 : gel(phi0, 22) = utoineg(0x754b96a0UL);
2945 2883 : gel(phi0, 23) = uu32toi(0x1UL, 0x421ca02aUL);
2946 2883 : gel(phi0, 24) = uu32toineg(0x2UL, 0xdb76a5cUL);
2947 2884 : gel(phi0, 25) = uu32toi(0x4UL, 0xf6afd8eUL);
2948 2884 : gel(phi0, 26) = uu32toineg(0x6UL, 0xaafd3cb4UL);
2949 2884 : gel(phi0, 27) = uu32toi(0x8UL, 0xda2539caUL);
2950 2884 : gel(phi0, 28) = uu32toineg(0xfUL, 0x84343790UL);
2951 2884 : gel(phi0, 29) = uu32toi(0xfUL, 0x914ff421UL);
2952 2884 : gel(phi0, 30) = uu32toineg(0x19UL, 0x3c123950UL);
2953 2884 : gel(phi0, 31) = uu32toi(0x15UL, 0x381f722aUL);
2954 2883 : gel(phi0, 32) = uu32toineg(0x15UL, 0xe01c0c24UL);
2955 2883 : gel(phi0, 33) = uu32toi(0x19UL, 0x3360b375UL);
2956 2883 : gel(phi0, 34) = utoineg(0x59fda9c0UL);
2957 2883 : gel(phi0, 35) = uu32toi(0x20UL, 0xff55024cUL);
2958 2883 : gel(phi0, 36) = uu32toi(0x16UL, 0xcc600800UL);
2959 2883 : gel(phi0, 37) = uu32toi(0x24UL, 0x1879c898UL);
2960 2883 : gel(phi0, 38) = uu32toi(0x1cUL, 0x37f97498UL);
2961 2883 : gel(phi0, 39) = uu32toi(0x19UL, 0x39ec4b60UL);
2962 2883 : gel(phi0, 40) = uu32toi(0x10UL, 0x52c660d0UL);
2963 2883 : gel(phi0, 41) = uu32toi(0x9UL, 0xcab00333UL);
2964 2883 : gel(phi0, 42) = uu32toi(0x4UL, 0x7fe69be4UL);
2965 2883 : gel(phi0, 43) = uu32toi(0x1UL, 0xa0c6f116UL);
2966 2884 : gel(phi0, 44) = utoi(0x69244638UL);
2967 2884 : gel(phi0, 45) = utoi(0xed560f7UL);
2968 2884 : gel(phi0, 46) = utoi(0xe7b660UL);
2969 2884 : gel(phi0, 47) = utoi(0x29d8aUL);
2970 2884 : gel(phi0, 48) = utoi(0x2c4UL);
2971 2884 : gel(phi0, 49) = gen_1;
2972 :
2973 2884 : phi1 = cgetg(49, t_VEC);
2974 2884 : gel(phi1, 1) = gen_0;
2975 2884 : gel(phi1, 2) = gen_0;
2976 2884 : gel(phi1, 3) = gen_0;
2977 2884 : gel(phi1, 4) = gen_0;
2978 2884 : gel(phi1, 5) = gen_0;
2979 2884 : gel(phi1, 6) = gen_1;
2980 2884 : gel(phi1, 7) = utoi(0x7UL);
2981 2884 : gel(phi1, 8) = utoi(0x8UL);
2982 2884 : gel(phi1, 9) = utoineg(0x9UL);
2983 2884 : gel(phi1, 10) = gen_0;
2984 2884 : gel(phi1, 11) = utoineg(0x13UL);
2985 2884 : gel(phi1, 12) = utoineg(0x7UL);
2986 2884 : gel(phi1, 13) = utoineg(0x5ceUL);
2987 2884 : gel(phi1, 14) = utoineg(0xb0UL);
2988 2884 : gel(phi1, 15) = utoi(0x460UL);
2989 2884 : gel(phi1, 16) = utoineg(0x194bUL);
2990 2884 : gel(phi1, 17) = utoi(0x87c3UL);
2991 2884 : gel(phi1, 18) = utoi(0x3cdeUL);
2992 2883 : gel(phi1, 19) = utoineg(0xd683UL);
2993 2884 : gel(phi1, 20) = utoi(0x6099bUL);
2994 2884 : gel(phi1, 21) = utoineg(0x111ea8UL);
2995 2884 : gel(phi1, 22) = utoi(0xfa113UL);
2996 2884 : gel(phi1, 23) = utoineg(0x1a6561UL);
2997 2884 : gel(phi1, 24) = utoineg(0x1e997UL);
2998 2884 : gel(phi1, 25) = utoi(0x214e54UL);
2999 2884 : gel(phi1, 26) = utoineg(0x29c3f4UL);
3000 2884 : gel(phi1, 27) = utoi(0x67e102UL);
3001 2884 : gel(phi1, 28) = utoineg(0x227eaaUL);
3002 2884 : gel(phi1, 29) = utoi(0x191d10UL);
3003 2884 : gel(phi1, 30) = utoi(0x1a9cd5UL);
3004 2884 : gel(phi1, 31) = utoineg(0x58386fUL);
3005 2884 : gel(phi1, 32) = utoi(0x2e49f6UL);
3006 2884 : gel(phi1, 33) = utoineg(0x31194bUL);
3007 2884 : gel(phi1, 34) = utoi(0x9e07aUL);
3008 2884 : gel(phi1, 35) = utoi(0x260d59UL);
3009 2884 : gel(phi1, 36) = utoineg(0x189921UL);
3010 2884 : gel(phi1, 37) = utoi(0xeca4aUL);
3011 2884 : gel(phi1, 38) = utoineg(0xa3d9cUL);
3012 2883 : gel(phi1, 39) = utoineg(0x426daUL);
3013 2883 : gel(phi1, 40) = utoi(0x91875UL);
3014 2884 : gel(phi1, 41) = utoineg(0x3b55bUL);
3015 2884 : gel(phi1, 42) = utoineg(0x56f4UL);
3016 2883 : gel(phi1, 43) = utoi(0xcd1bUL);
3017 2883 : gel(phi1, 44) = utoineg(0x5159UL);
3018 2883 : gel(phi1, 45) = utoi(0x10f4UL);
3019 2884 : gel(phi1, 46) = utoineg(0x20dUL);
3020 2884 : gel(phi1, 47) = utoi(0x23UL);
3021 2883 : gel(phi1, 48) = gen_m1;
3022 :
3023 2883 : gel(phi, 1) = phi0;
3024 2883 : gel(phi, 2) = phi1;
3025 2883 : gel(phi, 3) = utoi(12); return phi;
3026 : }
3027 :
3028 : GEN
3029 23937 : double_eta_raw(long inv)
3030 : {
3031 23937 : switch (inv) {
3032 1060 : case INV_W2W3:
3033 1060 : case INV_W2W3E2: return phi_w2w3_j();
3034 3535 : case INV_W3W3:
3035 3535 : case INV_W3W3E2: return phi_w3w3_j();
3036 3242 : case INV_W2W5:
3037 3242 : case INV_W2W5E2: return phi_w2w5_j();
3038 6520 : case INV_W2W7:
3039 6520 : case INV_W2W7E2: return phi_w2w7_j();
3040 1137 : case INV_W3W5: return phi_w3w5_j();
3041 2412 : case INV_W3W7: return phi_w3w7_j();
3042 2937 : case INV_W2W13: return phi_w2w13_j();
3043 210 : case INV_W3W13: return phi_w3w13_j();
3044 2884 : case INV_W5W7: return phi_w5w7_j();
3045 : default: pari_err_BUG("double_eta_raw"); return NULL;/*LCOV_EXCL_LINE*/
3046 : }
3047 : }
3048 :
3049 : /* SECTION: Select discriminant for given modpoly level. */
3050 :
3051 : /* require an L1, useful for multi-threading */
3052 : #define MODPOLY_USE_L1 1
3053 : /* no bound on L1 other than the fixed bound MAX_L1 - needed to
3054 : * handle small L for certain invariants (but not for j) */
3055 : #define MODPOLY_NO_MAX_L1 2
3056 : /* don't use any auxilliary primes - needed to handle small L for
3057 : * certain invariants (but not for j) */
3058 : #define MODPOLY_NO_AUX_L 4
3059 : #define MODPOLY_IGNORE_SPARSE_FACTOR 8
3060 :
3061 : INLINE double
3062 3029 : modpoly_height_bound(long L, long inv)
3063 : {
3064 : double nbits, nbits2;
3065 : double c;
3066 : long hf;
3067 :
3068 : /* proven bound (in bits), derived from: 6l*log(l)+16*l+13*sqrt(l)*log(l) */
3069 3029 : nbits = 6.0*L*log2(L)+16/M_LN2*L+8.0*sqrt((double)L)*log2(L);
3070 : /* alternative proven bound (in bits), derived from: 6l*log(l)+17*l */
3071 3029 : nbits2 = 6.0*L*log2(L)+17/M_LN2*L;
3072 3029 : if ( nbits2 < nbits ) nbits = nbits2;
3073 3029 : hf = modinv_height_factor(inv);
3074 3029 : if (hf > 1) {
3075 : /* IMPORTANT: when dividing by the height factor, we only want to reduce
3076 : terms related to the bound on j (the roots of Phi_l(X,y)), not terms arising
3077 : from binomial coefficients. These arise in lemmas 2 and 3 of the height
3078 : bound paper, terms of (log 2)*L and 2.085*(L+1) which we convert here to
3079 : binary logs */
3080 : /* Massive overestimate: if you care about speed, determine a good height
3081 : * bound empirically as done for INV_F below */
3082 1669 : nbits2 = nbits - 4.01*L -3.0;
3083 1669 : nbits = nbits2/hf + 4.01*L + 3.0;
3084 : }
3085 3029 : if (inv == INV_F) {
3086 149 : if (L < 30) c = 45;
3087 35 : else if (L < 100) c = 36;
3088 21 : else if (L < 300) c = 32;
3089 7 : else if (L < 600) c = 26;
3090 0 : else if (L < 1200) c = 24;
3091 0 : else if (L < 2400) c = 22;
3092 0 : else c = 20;
3093 149 : nbits = (6.0*L*log2(L) + c*L)/hf;
3094 : }
3095 3029 : return nbits;
3096 : }
3097 :
3098 : /* small enough to write the factorization of a smooth in a BIL bit integer */
3099 : #define SMOOTH_PRIMES ((BITS_IN_LONG >> 1) - 1)
3100 :
3101 : #define MAX_ATKIN 255
3102 :
3103 : /* Must have primes at least up to MAX_ATKIN */
3104 : static const long PRIMES[] = {
3105 : 0, 2, 3, 5, 7, 11, 13, 17, 19, 23,
3106 : 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
3107 : 71, 73, 79, 83, 89, 97, 101, 103, 107, 109,
3108 : 113, 127, 131, 137, 139, 149, 151, 157, 163, 167,
3109 : 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
3110 : 229, 233, 239, 241, 251, 257, 263, 269, 271, 277
3111 : };
3112 :
3113 : #define MAX_L1 255
3114 :
3115 : typedef struct D_entry_struct {
3116 : ulong m;
3117 : long D, h;
3118 : } D_entry;
3119 :
3120 : /* Returns a form that generates the classes of norm p^2 in cl(p^2D)
3121 : * (i.e. one with order p-1), where p is an odd prime that splits in D
3122 : * and does not divide its conductor (but this is not verified) */
3123 : INLINE GEN
3124 77734 : qform_primeform2(long p, long D)
3125 : {
3126 77734 : GEN a = sqru(p), Dp2 = mulis(a, D), M = Z_factor(utoipos(p - 1));
3127 77734 : pari_sp av = avma;
3128 : long k;
3129 :
3130 157331 : for (k = D & 1; k <= p; k += 2)
3131 : {
3132 157331 : long ord, c = (k * k - D) / 4;
3133 : GEN Q, q;
3134 :
3135 157331 : if (!(c % p)) continue;
3136 135735 : q = mkqfis(a, k * p, c, Dp2); Q = qfbred_i(q);
3137 : /* TODO: How do we know that Q has order dividing p - 1? If we don't, then
3138 : * the call to gen_order should be replaced with a call to something with
3139 : * fastorder semantics (i.e. return 0 if ord(Q) \ndiv M). */
3140 135735 : ord = itos(qfi_order(Q, M));
3141 135735 : if (ord == p - 1) {
3142 : /* TODO: This check that gen_order returned the correct result should be
3143 : * removed when gen_order is replaced with fastorder semantics. */
3144 77734 : if (qfb_equal1(gpowgs(Q, p - 1))) return q;
3145 0 : break;
3146 : }
3147 58001 : set_avma(av);
3148 : }
3149 0 : return NULL;
3150 : }
3151 :
3152 : /* Let n = #cl(D); return x such that [L0]^x = [L] in cl(D), or -1 if x was
3153 : * not found */
3154 : INLINE long
3155 198166 : primeform_discrete_log(long L0, long L, long n, long D)
3156 : {
3157 198166 : pari_sp av = avma;
3158 198166 : GEN X, Q, R, DD = stoi(D);
3159 198166 : Q = primeform_u(DD, L0);
3160 198166 : R = primeform_u(DD, L);
3161 198166 : X = qfi_Shanks(R, Q, n);
3162 198166 : return gc_long(av, X? itos(X): -1);
3163 : }
3164 :
3165 : /* Return the norm of a class group generator appropriate for a discriminant
3166 : * that will be used to calculate the modular polynomial of level L and
3167 : * invariant inv. Don't consider norms less than initial_L0 */
3168 : static long
3169 3029 : select_L0(long L, long inv, long initial_L0)
3170 : {
3171 3029 : long L0, modinv_N = modinv_level(inv);
3172 :
3173 3029 : if (modinv_N % L == 0) pari_err_BUG("select_L0");
3174 :
3175 : /* TODO: Clean up these anomolous L0 choices */
3176 :
3177 : /* I've no idea why the discriminant-finding code fails with L0=5
3178 : * when L=19 and L=29, nor why L0=7 and L0=11 don't work for L=19
3179 : * either, nor why this happens for the otherwise unrelated
3180 : * invariants Weber-f and (2,3) double-eta. */
3181 3029 : if (inv == INV_W3W3E2 && L == 5) return 2;
3182 :
3183 3015 : if (inv == INV_F || inv == INV_F2 || inv == INV_F4 || inv == INV_F8
3184 2754 : || inv == INV_W2W3 || inv == INV_W2W3E2
3185 2691 : || inv == INV_W3W3 /* || inv == INV_W3W3E2 */) {
3186 422 : if (L == 19) return 13;
3187 372 : else if (L == 29 || L == 5) return 7;
3188 309 : return 5;
3189 : }
3190 2593 : if ((inv == INV_W2W5 || inv == INV_W2W5E2)
3191 140 : && (L == 7 || L == 19)) return 13;
3192 2551 : if ((inv == INV_W2W7 || inv == INV_W2W7E2)
3193 358 : && L == 11) return 13;
3194 2523 : if (inv == INV_W3W5) {
3195 63 : if (L == 7) return 13;
3196 56 : else if (L == 17) return 7;
3197 : }
3198 2516 : if (inv == INV_W3W7) {
3199 140 : if (L == 29 || L == 101) return 11;
3200 112 : if (L == 11 || L == 19) return 13;
3201 : }
3202 2460 : if (inv == INV_W5W7 && L == 17) return 3;
3203 :
3204 : /* L0 = smallest small prime different from L that doesn't divide modinv_N */
3205 2439 : for (L0 = unextprime(initial_L0 + 1);
3206 3413 : L0 == L || modinv_N % L0 == 0;
3207 974 : L0 = unextprime(L0 + 1))
3208 : ;
3209 2439 : return L0;
3210 : }
3211 :
3212 : /* Return the order of [L]^n in cl(D), where #cl(D) = ord. */
3213 : INLINE long
3214 1064285 : primeform_exp_order(long L, long n, long D, long ord)
3215 : {
3216 1064285 : pari_sp av = avma;
3217 1064285 : GEN Q = gpowgs(primeform_u(stoi(D), L), n);
3218 1064285 : long m = itos(qfi_order(Q, Z_factor(stoi(ord))));
3219 1064285 : return gc_long(av,m);
3220 : }
3221 :
3222 : /* If an ideal of norm modinv_deg is equivalent to an ideal of norm L0, we
3223 : * have an orientation ambiguity that we need to avoid. Note that we need to
3224 : * check all the possibilities (up to 8), but we can cheaply check inverses
3225 : * (so at most 2) */
3226 : static long
3227 33902 : orientation_ambiguity(long D1, long L0, long modinv_p1, long modinv_p2, long modinv_N)
3228 : {
3229 33902 : pari_sp av = avma;
3230 33902 : long ambiguity = 0;
3231 33902 : GEN D = stoi(D1), Q1 = primeform_u(D, modinv_p1), Q2 = NULL;
3232 :
3233 33902 : if (modinv_p2 > 1)
3234 : {
3235 33902 : if (modinv_p1 == modinv_p2) Q1 = gsqr(Q1);
3236 : else
3237 : {
3238 27792 : GEN P2 = primeform_u(D, modinv_p2);
3239 27792 : GEN Q = gsqr(P2), R = gsqr(Q1);
3240 : /* check that p1^2 != p2^{+/-2}, since this leads to
3241 : * ambiguities when converting j's to f's */
3242 27792 : if (equalii(gel(Q,1), gel(R,1)) && absequalii(gel(Q,2), gel(R,2)))
3243 : {
3244 0 : dbg_printf(3)("Bad D=%ld, a^2=b^2 problem between modinv_p1=%ld and modinv_p2=%ld\n",
3245 : D1, modinv_p1, modinv_p2);
3246 0 : ambiguity = 1;
3247 : }
3248 : else
3249 : { /* generate both p1*p2 and p1*p2^{-1} */
3250 27792 : Q2 = gmul(Q1, P2);
3251 27792 : P2 = ginv(P2);
3252 27792 : Q1 = gmul(Q1, P2);
3253 : }
3254 : }
3255 : }
3256 33902 : if (!ambiguity)
3257 : {
3258 33902 : GEN P = gsqr(primeform_u(D, L0));
3259 33902 : if (equalii(gel(P,1), gel(Q1,1))
3260 32872 : || (modinv_p2 && modinv_p1 != modinv_p2
3261 26776 : && equalii(gel(P,1), gel(Q2,1)))) {
3262 1487 : dbg_printf(3)("Bad D=%ld, a=b^{+/-2} problem between modinv_N=%ld and L0=%ld\n",
3263 : D1, modinv_N, L0);
3264 1487 : ambiguity = 1;
3265 : }
3266 : }
3267 33902 : return gc_long(av, ambiguity);
3268 : }
3269 :
3270 : static long
3271 770583 : check_generators(
3272 : long *n1_, long *m_,
3273 : long D, long h, long n, long subgrp_sz, long L0, long L1)
3274 : {
3275 770583 : long n1, m = primeform_exp_order(L0, n, D, h);
3276 770583 : if (m_) *m_ = m;
3277 770583 : n1 = n * m;
3278 770583 : if (!n1) pari_err_BUG("check_generators");
3279 770583 : *n1_ = n1;
3280 770583 : if (n1 < subgrp_sz/2 || ( ! L1 && n1 < subgrp_sz)) {
3281 27936 : dbg_printf(3)("Bad D1=%ld with n1=%ld, h1=%ld, L1=%ld: "
3282 : "L0 and L1 don't span subgroup of size d in cl(D1)\n",
3283 : D, n, h, L1);
3284 27936 : return 0;
3285 : }
3286 742647 : if (n1 < subgrp_sz && ! (n1 & 1)) {
3287 : int res;
3288 : /* check whether L1 is generated by L0, use the fact that it has order 2 */
3289 18145 : pari_sp av = avma;
3290 18145 : GEN D1 = stoi(D);
3291 18145 : GEN Q = gpowgs(primeform_u(D1, L0), n1 / 2);
3292 18145 : res = gequal(Q, qfbred_i(primeform_u(D1, L1)));
3293 18145 : set_avma(av);
3294 18145 : if (res) {
3295 5328 : dbg_printf(3)("Bad D1=%ld, with n1=%ld, h1=%ld, L1=%ld: "
3296 : "L1 generated by L0 in cl(D1)\n", D, n, h, L1);
3297 5328 : return 0;
3298 : }
3299 : }
3300 737319 : return 1;
3301 : }
3302 :
3303 : /* Calculate solutions (p, t) to the norm equation
3304 : * 4 p = t^2 - v^2 L^2 D (*)
3305 : * corresponding to the descriminant described by Dinfo.
3306 : *
3307 : * INPUT:
3308 : * - max: length of primes and traces
3309 : * - xprimes: p to exclude from primes (if they arise)
3310 : * - xcnt: length of xprimes
3311 : * - minbits: sum of log2(p) must be larger than this
3312 : * - Dinfo: discriminant, invariant and L for which we seek solutions to (*)
3313 : *
3314 : * OUTPUT:
3315 : * - primes: array of p in (*)
3316 : * - traces: array of t in (*)
3317 : * - totbits: sum of log2(p) for p in primes.
3318 : *
3319 : * RETURN:
3320 : * - the number of primes and traces found (these are always the same).
3321 : *
3322 : * NOTE: primes and traces are both NULL or both non-NULL.
3323 : * xprimes can be zero, in which case it is treated as empty. */
3324 : static long
3325 11732 : modpoly_pickD_primes(
3326 : ulong *primes, ulong *traces, long max, ulong *xprimes, long xcnt,
3327 : long *totbits, long minbits, disc_info *Dinfo)
3328 : {
3329 : double bits;
3330 : long D, m, n, vcnt, pfilter, one_prime, inv;
3331 : ulong maxp;
3332 : ulong a1, a2, v, t, p, a1_start, a1_delta, L0, L1, L, absD;
3333 11732 : ulong FF_BITS = BITS_IN_LONG - 2; /* BITS_IN_LONG - NAIL_BITS */
3334 :
3335 11732 : D = Dinfo->D1; absD = -D;
3336 11732 : L0 = Dinfo->L0;
3337 11732 : L1 = Dinfo->L1;
3338 11732 : L = Dinfo->L;
3339 11732 : inv = Dinfo->inv;
3340 :
3341 : /* make sure pfilter and D don't preclude the possibility of p=(t^2-v^2D)/4 being prime */
3342 11732 : pfilter = modinv_pfilter(inv);
3343 11732 : if ((pfilter & IQ_FILTER_1MOD3) && ! (D % 3)) return 0;
3344 11683 : if ((pfilter & IQ_FILTER_1MOD4) && ! (D & 0xF)) return 0;
3345 :
3346 : /* Naively estimate the number of primes satisfying 4p=t^2-L^2D with
3347 : * t=2 mod L and pfilter. This is roughly
3348 : * #{t: t^2 < max p and t=2 mod L} / pi(max p) * filter_density,
3349 : * where filter_density is 1, 2, or 4 depending on pfilter. If this quantity
3350 : * is already more than twice the number of bits we need, assume that,
3351 : * barring some obstruction, we should have no problem getting enough primes.
3352 : * In this case we just verify we can get one prime (which should always be
3353 : * true, assuming we chose D properly). */
3354 11683 : one_prime = 0;
3355 11683 : *totbits = 0;
3356 11683 : if (max <= 1 && ! one_prime) {
3357 8633 : p = ((pfilter & IQ_FILTER_1MOD3) ? 2 : 1) * ((pfilter & IQ_FILTER_1MOD4) ? 2 : 1);
3358 8633 : one_prime = (1UL << ((FF_BITS+1)/2)) * (log2(L*L*(-D))-1)
3359 8633 : > p*L*minbits*FF_BITS*M_LN2;
3360 8633 : if (one_prime) *totbits = minbits+1; /* lie */
3361 : }
3362 :
3363 11683 : m = n = 0;
3364 11683 : bits = 0.0;
3365 11683 : maxp = 0;
3366 29131 : for (v = 1; v < 100 && bits < minbits; v++) {
3367 : /* Don't allow v dividing the conductor. */
3368 26028 : if (ugcd(absD, v) != 1) continue;
3369 : /* Avoid v dividing the level. */
3370 25830 : if (v > 2 && modinv_is_double_eta(inv) && ugcd(modinv_level(inv), v) != 1)
3371 966 : continue;
3372 : /* can't get odd p with D=1 mod 8 unless v is even */
3373 24864 : if ((v & 1) && (D & 7) == 1) continue;
3374 : /* disallow 4 | v for L0=2 (removing this restriction is costly) */
3375 12313 : if (L0 == 2 && !(v & 3)) continue;
3376 : /* can't get p=3mod4 if v^2D is 0 mod 16 */
3377 12063 : if ((pfilter & IQ_FILTER_1MOD4) && !((v*v*D) & 0xF)) continue;
3378 11980 : if ((pfilter & IQ_FILTER_1MOD3) && !(v%3) ) continue;
3379 : /* avoid L0-volcanos with nonzero height */
3380 11922 : if (L0 != 2 && ! (v % L0)) continue;
3381 : /* ditto for L1 */
3382 11901 : if (L1 && !(v % L1)) continue;
3383 11901 : vcnt = 0;
3384 11901 : if ((v*v*absD)/4 > (1L<<FF_BITS)/(L*L)) break;
3385 11819 : if (both_odd(v,D)) {
3386 0 : a1_start = 1;
3387 0 : a1_delta = 2;
3388 : } else {
3389 11819 : a1_start = ((v*v*D) & 7)? 2: 0;
3390 11819 : a1_delta = 4;
3391 : }
3392 567625 : for (a1 = a1_start; bits < minbits; a1 += a1_delta) {
3393 564536 : a2 = (a1*a1 + v*v*absD) >> 2;
3394 564536 : if (!(a2 % L)) continue;
3395 477660 : t = a1*L + 2;
3396 477660 : p = a2*L*L + t - 1;
3397 : /* double check calculation just in case of overflow or other weirdness */
3398 477660 : if (!odd(p) || t*t + v*v*L*L*absD != 4*p)
3399 0 : pari_err_BUG("modpoly_pickD_primes");
3400 477660 : if (p > (1UL<<FF_BITS)) break;
3401 477428 : if (xprimes) {
3402 357646 : while (m < xcnt && xprimes[m] < p) m++;
3403 357218 : if (m < xcnt && p == xprimes[m]) {
3404 0 : dbg_printf(1)("skipping duplicate prime %ld\n", p);
3405 0 : continue;
3406 : }
3407 : }
3408 477428 : if (!modinv_good_prime(inv, p) || !uisprime(p)) continue;
3409 52843 : if (primes) {
3410 39148 : if (n >= max) goto done;
3411 : /* TODO: Implement test to filter primes that lead to
3412 : * L-valuation != 2 */
3413 39148 : primes[n] = p;
3414 39148 : traces[n] = t;
3415 : }
3416 52843 : n++;
3417 52843 : vcnt++;
3418 52843 : bits += log2(p);
3419 52843 : if (p > maxp) maxp = p;
3420 52843 : if (one_prime) goto done;
3421 : }
3422 3321 : if (vcnt)
3423 3318 : dbg_printf(3)("%ld primes with v=%ld, maxp=%ld (%.2f bits)\n",
3424 : vcnt, v, maxp, log2(maxp));
3425 : }
3426 3103 : done:
3427 11683 : if (!n) {
3428 9 : dbg_printf(3)("check_primes failed completely for D=%ld\n", D);
3429 9 : return 0;
3430 : }
3431 11674 : dbg_printf(3)("D=%ld: Found %ld primes totalling %0.2f of %ld bits\n",
3432 : D, n, bits, minbits);
3433 11674 : if (!*totbits) *totbits = (long)bits;
3434 11674 : return n;
3435 : }
3436 :
3437 : #define MAX_VOLCANO_FLOOR_SIZE 100000000
3438 :
3439 : static long
3440 3031 : calc_primes_for_discriminants(disc_info Ds[], long Dcnt, long L, long minbits)
3441 : {
3442 3031 : pari_sp av = avma;
3443 : long i, j, k, m, n, D1, pcnt, totbits;
3444 : ulong *primes, *Dprimes, *Dtraces;
3445 :
3446 : /* D1 is the discriminant with smallest absolute value among those we found */
3447 3031 : D1 = Ds[0].D1;
3448 8624 : for (i = 1; i < Dcnt; i++)
3449 5593 : if (Ds[i].D1 > D1) D1 = Ds[i].D1;
3450 :
3451 : /* n is an upper bound on the number of primes we might get. */
3452 3031 : n = ceil(minbits / (log2(L * L * (-D1)) - 2)) + 1;
3453 3031 : primes = (ulong *) stack_malloc(n * sizeof(*primes));
3454 3031 : Dprimes = (ulong *) stack_malloc(n * sizeof(*Dprimes));
3455 3031 : Dtraces = (ulong *) stack_malloc(n * sizeof(*Dtraces));
3456 3050 : for (i = 0, totbits = 0, pcnt = 0; i < Dcnt && totbits < minbits; i++)
3457 : {
3458 3050 : long np = modpoly_pickD_primes(Dprimes, Dtraces, n, primes, pcnt,
3459 3050 : &Ds[i].bits, minbits - totbits, Ds + i);
3460 3050 : ulong *T = (ulong *)newblock(2*np);
3461 3050 : Ds[i].nprimes = np;
3462 3050 : Ds[i].primes = T; memcpy(T , Dprimes, np * sizeof(*Dprimes));
3463 3050 : Ds[i].traces = T+np; memcpy(T+np, Dtraces, np * sizeof(*Dtraces));
3464 :
3465 3050 : totbits += Ds[i].bits;
3466 3050 : pcnt += np;
3467 :
3468 3050 : if (totbits >= minbits || i == Dcnt - 1) { Dcnt = i + 1; break; }
3469 : /* merge lists */
3470 599 : for (j = pcnt - np - 1, k = np - 1, m = pcnt - 1; m >= 0; m--) {
3471 580 : if (k >= 0) {
3472 555 : if (j >= 0 && primes[j] > Dprimes[k])
3473 301 : primes[m] = primes[j--];
3474 : else
3475 254 : primes[m] = Dprimes[k--];
3476 : } else {
3477 25 : primes[m] = primes[j--];
3478 : }
3479 : }
3480 : }
3481 3031 : if (totbits < minbits) {
3482 2 : dbg_printf(1)("Only obtained %ld of %ld bits using %ld discriminants\n",
3483 : totbits, minbits, Dcnt);
3484 4 : for (i = 0; i < Dcnt; i++) killblock((GEN)Ds[i].primes);
3485 2 : Dcnt = 0;
3486 : }
3487 3031 : return gc_long(av, Dcnt);
3488 : }
3489 :
3490 : /* Select discriminant(s) to use when calculating the modular
3491 : * polynomial of level L and invariant inv.
3492 : *
3493 : * INPUT:
3494 : * - L: level of modular polynomial (must be odd)
3495 : * - inv: invariant of modular polynomial
3496 : * - L0: result of select_L0(L, inv)
3497 : * - minbits: height of modular polynomial
3498 : * - flags: see below
3499 : * - tab: result of scanD0(L0)
3500 : * - tablen: length of tab
3501 : *
3502 : * OUTPUT:
3503 : * - Ds: the selected discriminant(s)
3504 : *
3505 : * RETURN:
3506 : * - the number of Ds found
3507 : *
3508 : * The flags parameter is constructed by ORing zero or more of the
3509 : * following values:
3510 : * - MODPOLY_USE_L1: force use of second class group generator
3511 : * - MODPOLY_NO_AUX_L: don't use auxillary class group elements
3512 : * - MODPOLY_IGNORE_SPARSE_FACTOR: obtain D for which h(D) > L + 1
3513 : * rather than h(D) > (L + 1)/s */
3514 : static long
3515 3031 : modpoly_pickD(disc_info Ds[MODPOLY_MAX_DCNT], long L, long inv,
3516 : long L0, long max_L1, long minbits, long flags, D_entry *tab, long tablen)
3517 : {
3518 3031 : pari_sp ltop = avma, btop;
3519 : disc_info Dinfo;
3520 : pari_timer T;
3521 : long modinv_p1, modinv_p2; /* const after next line */
3522 3031 : const long modinv_deg = modinv_degree(&modinv_p1, &modinv_p2, inv);
3523 3031 : const long pfilter = modinv_pfilter(inv), modinv_N = modinv_level(inv);
3524 : long i, k, use_L1, Dcnt, D0_i, d, cost, enum_cost, best_cost, totbits;
3525 3031 : const double L_bits = log2(L);
3526 :
3527 3031 : if (!odd(L)) pari_err_BUG("modpoly_pickD");
3528 :
3529 3031 : timer_start(&T);
3530 3031 : if (flags & MODPOLY_IGNORE_SPARSE_FACTOR) d = L+2;
3531 2884 : else d = ceildivuu(L+1, modinv_sparse_factor(inv)) + 1;
3532 :
3533 : /* Now set level to 0 unless we will need to compute N-isogenies */
3534 3031 : dbg_printf(1)("Using L0=%ld for L=%ld, d=%ld, modinv_N=%ld, modinv_deg=%ld\n",
3535 : L0, L, d, modinv_N, modinv_deg);
3536 :
3537 : /* We use L1 if (L0|L) == 1 or if we are forced to by flags. */
3538 3031 : use_L1 = (kross(L0,L) > 0 || (flags & MODPOLY_USE_L1));
3539 :
3540 3031 : Dcnt = best_cost = totbits = 0;
3541 3031 : dbg_printf(3)("use_L1=%ld\n", use_L1);
3542 3031 : dbg_printf(3)("minbits = %ld\n", minbits);
3543 :
3544 : /* Iterate over the fundamental discriminants for L0 */
3545 1865923 : for (D0_i = 0; D0_i < tablen; D0_i++)
3546 : {
3547 1862892 : D_entry D0_entry = tab[D0_i];
3548 1862892 : long m, n0, h0, deg, L1, H_cost, twofactor, D0 = D0_entry.D;
3549 : double D0_bits;
3550 2892547 : if (! modinv_good_disc(inv, D0)) continue;
3551 1240748 : dbg_printf(3)("D0=%ld\n", D0);
3552 : /* don't allow either modinv_p1 or modinv_p2 to ramify */
3553 1240748 : if (kross(D0, L) < 1
3554 560811 : || (modinv_p1 > 1 && kross(D0, modinv_p1) < 1)
3555 555902 : || (modinv_p2 > 1 && kross(D0, modinv_p2) < 1)) {
3556 695250 : dbg_printf(3)("Bad D0=%ld due to nonsplit L or ramified level\n", D0);
3557 695250 : continue;
3558 : }
3559 545498 : deg = D0_entry.h; /* class poly degree */
3560 545498 : h0 = ((D0_entry.m & 2) ? 2*deg : deg); /* class number */
3561 : /* (D0_entry.m & 1) is 1 if ord(L0) < h0 (hence = h0/2),
3562 : * is 0 if ord(L0) = h0 */
3563 545498 : n0 = h0 / ((D0_entry.m & 1) + 1); /* = ord(L0) */
3564 :
3565 : /* Look for L1: for each smooth prime p */
3566 545498 : L1 = 0;
3567 13260586 : for (i = 1 ; i <= SMOOTH_PRIMES; i++)
3568 : {
3569 12826386 : long p = PRIMES[i];
3570 12826386 : if (p <= L0) continue;
3571 : /* If 1 + (D0 | p) = 1, i.e. p | D0 */
3572 12100649 : if (((D0_entry.m >> (2*i)) & 3) == 1) {
3573 : /* XXX: Why (p | L) = -1? Presumably so (L^2 v^2 D0 | p) = -1? */
3574 394814 : if (p <= max_L1 && modinv_N % p && kross(p,L) < 0) { L1 = p; break; }
3575 : }
3576 : }
3577 545498 : if (i > SMOOTH_PRIMES && (n0 < h0 || use_L1))
3578 : { /* Didn't find suitable L1 though we need one */
3579 251796 : dbg_printf(3)("Bad D0=%ld because there is no good L1\n", D0);
3580 251796 : continue;
3581 : }
3582 293702 : dbg_printf(3)("Good D0=%ld with L1=%ld, n0=%ld, h0=%ld, d=%ld\n",
3583 : D0, L1, n0, h0, d);
3584 :
3585 : /* We're finished if we have sufficiently many discriminants that satisfy
3586 : * the cost requirement */
3587 293702 : if (totbits > minbits && best_cost && h0*(L-1) > 3*best_cost) break;
3588 :
3589 293702 : D0_bits = log2(-D0);
3590 : /* If L^2 D0 is too big to fit in a BIL bit integer, skip D0. */
3591 293702 : if (D0_bits + 2 * L_bits > (BITS_IN_LONG - 1)) continue;
3592 :
3593 : /* m is the order of L0^n0 in L^2 D0? */
3594 293702 : m = primeform_exp_order(L0, n0, L * L * D0, n0 * (L-1));
3595 293702 : if (m < (L-1)/2) {
3596 82609 : dbg_printf(3)("Bad D0=%ld because %ld is less than (L-1)/2=%ld\n",
3597 0 : D0, m, (L - 1)/2);
3598 82609 : continue;
3599 : }
3600 : /* Heuristic. Doesn't end up contributing much. */
3601 211093 : H_cost = 2 * deg * deg;
3602 :
3603 : /* 0xc = 0b1100, so D0_entry.m & 0xc == 1 + (D0 | 2) */
3604 211093 : if ((D0 & 7) == 5) /* D0 = 5 (mod 8) */
3605 5820 : twofactor = ((D0_entry.m & 0xc) ? 1 : 3);
3606 : else
3607 205273 : twofactor = 0;
3608 :
3609 211093 : btop = avma;
3610 : /* For each small prime... */
3611 725229 : for (i = 0; i <= SMOOTH_PRIMES; i++) {
3612 : long h1, h2, D1, D2, n1, n2, dl1, dl20, dl21, p, q, j;
3613 : double p_bits;
3614 725124 : set_avma(btop);
3615 : /* i = 0 corresponds to 1, which we do not want to skip! (i.e. DK = D) */
3616 725124 : if (i) {
3617 1018138 : if (modinv_odd_conductor(inv) && i == 1) continue;
3618 504535 : p = PRIMES[i];
3619 : /* Don't allow large factors in the conductor. */
3620 621210 : if (p > max_L1) break;
3621 410222 : if (p == L0 || p == L1 || p == L || p == modinv_p1 || p == modinv_p2)
3622 140291 : continue;
3623 269931 : p_bits = log2(p);
3624 : /* h1 is the class number of D1 = q^2 D0, where q = p^j (j defined in the loop below) */
3625 269931 : h1 = h0 * (p - ((D0_entry.m >> (2*i)) & 0x3) + 1);
3626 : /* q is the smallest power of p such that h1 >= d ~ "L + 1". */
3627 272606 : for (j = 1, q = p; h1 < d; j++, q *= p, h1 *= p)
3628 : ;
3629 269931 : D1 = q * q * D0;
3630 : /* can't have D1 = 0 mod 16 and hope to get any primes congruent to 3 mod 4 */
3631 269931 : if ((pfilter & IQ_FILTER_1MOD4) && !(D1 & 0xF)) continue;
3632 : } else {
3633 : /* i = 0, corresponds to "p = 1". */
3634 211093 : h1 = h0;
3635 211093 : D1 = D0;
3636 211093 : p = q = j = 1;
3637 211093 : p_bits = 0;
3638 : }
3639 : /* include a factor of 4 if D1 is 5 mod 8 */
3640 : /* XXX: No idea why he does this. */
3641 480954 : if (twofactor && (q & 1)) {
3642 14550 : if (modinv_odd_conductor(inv)) continue;
3643 518 : D1 *= 4;
3644 518 : h1 *= twofactor;
3645 : }
3646 : /* heuristic early abort; we may miss good D1's, but this saves time */
3647 466922 : if (totbits > minbits && best_cost && h1*(L-1) > 2.2*best_cost) continue;
3648 :
3649 : /* log2(D0 * (p^j)^2 * L^2 * twofactor) > (BIL - 1) -- params too big. */
3650 913988 : if (D0_bits + 2*j*p_bits + 2*L_bits
3651 456148 : + (twofactor && (q & 1) ? 2.0 : 0.0) > (BITS_IN_LONG-1)) continue;
3652 :
3653 454456 : if (! check_generators(&n1, NULL, D1, h1, n0, d, L0, L1)) continue;
3654 :
3655 436711 : if (n1 >= h1) dl1 = -1; /* fill it in later */
3656 195163 : else if ((dl1 = primeform_discrete_log(L0, L, n1, D1)) < 0) continue;
3657 317614 : dbg_printf(3)("Good D0=%ld, D1=%ld with q=%ld, L1=%ld, n1=%ld, h1=%ld\n",
3658 : D0, D1, q, L1, n1, h1);
3659 317614 : if (modinv_deg && orientation_ambiguity(D1, L0, modinv_p1, modinv_p2, modinv_N))
3660 1487 : continue;
3661 :
3662 316127 : D2 = L * L * D1;
3663 316127 : h2 = h1 * (L-1);
3664 : /* m is the order of L0^n1 in cl(D2) */
3665 316127 : if (!check_generators(&n2, &m, D2, h2, n1, d*(L-1), L0, L1)) continue;
3666 :
3667 : /* This restriction on m is not necessary, but simplifies life later */
3668 300608 : if (m < (L-1)/2 || (!L1 && m < L-1)) {
3669 145871 : dbg_printf(3)("Bad D2=%ld for D1=%ld, D0=%ld, with n2=%ld, h2=%ld, L1=%ld, "
3670 : "order of L0^n1 in cl(D2) is too small\n", D2, D1, D0, n2, h2, L1);
3671 145871 : continue;
3672 : }
3673 154737 : dl20 = n1;
3674 154737 : dl21 = 0;
3675 154737 : if (m < L-1) {
3676 77734 : GEN Q1 = qform_primeform2(L, D1), Q2, X;
3677 77734 : if (!Q1) pari_err_BUG("modpoly_pickD");
3678 77734 : Q2 = primeform_u(stoi(D2), L1);
3679 77734 : Q2 = qfbcomp(Q1, Q2); /* we know this element has order L-1 */
3680 77734 : Q1 = primeform_u(stoi(D2), L0);
3681 77734 : k = ((n2 & 1) ? 2*n2 : n2)/(L-1);
3682 77734 : Q1 = gpowgs(Q1, k);
3683 77734 : X = qfi_Shanks(Q2, Q1, L-1);
3684 77734 : if (!X) {
3685 11488 : dbg_printf(3)("Bad D2=%ld for D1=%ld, D0=%ld, with n2=%ld, h2=%ld, L1=%ld, "
3686 : "form of norm L^2 not generated by L0 and L1\n",
3687 : D2, D1, D0, n2, h2, L1);
3688 11488 : continue;
3689 : }
3690 66246 : dl20 = itos(X) * k;
3691 66246 : dl21 = 1;
3692 : }
3693 143249 : if (! (m < L-1 || n2 < d*(L-1)) && n1 >= d && ! use_L1)
3694 76511 : L1 = 0; /* we don't need L1 */
3695 :
3696 143249 : if (!L1 && use_L1) {
3697 0 : dbg_printf(3)("not using D2=%ld for D1=%ld, D0=%ld, with n2=%ld, h2=%ld, L1=%ld, "
3698 : "because we don't need L1 but must use it\n",
3699 : D2, D1, D0, n2, h2, L1);
3700 0 : continue;
3701 : }
3702 : /* don't allow zero dl21 with L1 for the moment, since
3703 : * modpoly doesn't handle it - we may change this in the future */
3704 143249 : if (L1 && ! dl21) continue;
3705 142757 : dbg_printf(3)("Good D0=%ld, D1=%ld, D2=%ld with s=%ld^%ld, L1=%ld, dl2=%ld, n2=%ld, h2=%ld\n",
3706 : D0, D1, D2, p, j, L1, dl20, n2, h2);
3707 :
3708 : /* This estimate is heuristic and fiddling with the
3709 : * parameters 5 and 0.25 can change things quite a bit. */
3710 142757 : enum_cost = n2 * (5 * L0 * L0 + 0.25 * L1 * L1);
3711 142757 : cost = enum_cost + H_cost;
3712 142757 : if (best_cost && cost > 2.2*best_cost) break;
3713 34173 : if (best_cost && cost >= 0.99*best_cost) continue;
3714 :
3715 8682 : Dinfo.GENcode0 = evaltyp(t_VECSMALL)|_evallg(13);
3716 8682 : Dinfo.inv = inv;
3717 8682 : Dinfo.L = L;
3718 8682 : Dinfo.D0 = D0;
3719 8682 : Dinfo.D1 = D1;
3720 8682 : Dinfo.L0 = L0;
3721 8682 : Dinfo.L1 = L1;
3722 8682 : Dinfo.n1 = n1;
3723 8682 : Dinfo.n2 = n2;
3724 8682 : Dinfo.dl1 = dl1;
3725 8682 : Dinfo.dl2_0 = dl20;
3726 8682 : Dinfo.dl2_1 = dl21;
3727 8682 : Dinfo.cost = cost;
3728 :
3729 8682 : if (!modpoly_pickD_primes(NULL, NULL, 0, NULL, 0, &Dinfo.bits, minbits, &Dinfo))
3730 58 : continue;
3731 8624 : dbg_printf(2)("Best D2=%ld, D1=%ld, D0=%ld with s=%ld^%ld, L1=%ld, "
3732 : "n1=%ld, n2=%ld, cost ratio %.2f, bits=%ld\n",
3733 : D2, D1, D0, p, j, L1, n1, n2,
3734 0 : (double)cost/(d*(L-1)), Dinfo.bits);
3735 : /* Insert Dinfo into the Ds array. Ds is sorted by ascending cost. */
3736 45930 : for (j = 0; j < Dcnt; j++)
3737 42888 : if (Dinfo.cost < Ds[j].cost) break;
3738 8624 : if (n2 > MAX_VOLCANO_FLOOR_SIZE && n2*(L1 ? 2 : 1) > 1.2* (d*(L-1)) ) {
3739 0 : dbg_printf(3)("Not using D1=%ld, D2=%ld for space reasons\n", D1, D2);
3740 0 : continue;
3741 : }
3742 8624 : if (j == Dcnt && Dcnt == MODPOLY_MAX_DCNT)
3743 0 : continue;
3744 8624 : totbits += Dinfo.bits;
3745 8624 : if (Dcnt == MODPOLY_MAX_DCNT) totbits -= Ds[Dcnt-1].bits;
3746 8624 : if (Dcnt < MODPOLY_MAX_DCNT) Dcnt++;
3747 8624 : if (n2 > MAX_VOLCANO_FLOOR_SIZE)
3748 0 : dbg_printf(3)("totbits=%ld, minbits=%ld\n", totbits, minbits);
3749 19065 : for (k = Dcnt-1; k > j; k--) Ds[k] = Ds[k-1];
3750 8624 : Ds[k] = Dinfo;
3751 8624 : best_cost = (totbits > minbits)? Ds[Dcnt-1].cost: 0;
3752 : /* if we were able to use D1 with s = 1, there is no point in
3753 : * using any larger D1 for the same D0 */
3754 8624 : if (!i) break;
3755 : } /* END FOR over small primes */
3756 : } /* END WHILE over D0's */
3757 3031 : dbg_printf(2)(" checked %ld of %ld fundamental discriminants to find suitable "
3758 : "discriminant (Dcnt = %ld)\n", D0_i, tablen, Dcnt);
3759 3031 : if ( ! Dcnt) {
3760 0 : dbg_printf(1)("failed completely for L=%ld\n", L);
3761 0 : return 0;
3762 : }
3763 :
3764 3031 : Dcnt = calc_primes_for_discriminants(Ds, Dcnt, L, minbits);
3765 :
3766 : /* fill in any missing dl1's */
3767 6079 : for (i = 0 ; i < Dcnt; i++)
3768 3048 : if (Ds[i].dl1 < 0 &&
3769 3003 : (Ds[i].dl1 = primeform_discrete_log(L0, L, Ds[i].n1, Ds[i].D1)) < 0)
3770 0 : pari_err_BUG("modpoly_pickD");
3771 3031 : if (DEBUGLEVEL > 1+3) {
3772 0 : err_printf("Selected %ld discriminants using %ld msecs\n", Dcnt, timer_delay(&T));
3773 0 : for (i = 0 ; i < Dcnt ; i++)
3774 : {
3775 0 : GEN H = classno(stoi(Ds[i].D0));
3776 0 : long h0 = itos(H);
3777 0 : err_printf (" D0=%ld, h(D0)=%ld, D=%ld, L0=%ld, L1=%ld, "
3778 : "cost ratio=%.2f, enum ratio=%.2f,",
3779 0 : Ds[i].D0, h0, Ds[i].D1, Ds[i].L0, Ds[i].L1,
3780 0 : (double)Ds[i].cost/(d*(L-1)),
3781 0 : (double)(Ds[i].n2*(Ds[i].L1 ? 2 : 1))/(d*(L-1)));
3782 0 : err_printf (" %ld primes, %ld bits\n", Ds[i].nprimes, Ds[i].bits);
3783 : }
3784 : }
3785 3031 : return gc_long(ltop, Dcnt);
3786 : }
3787 :
3788 : static int
3789 14537084 : _qsort_cmp(const void *a, const void *b)
3790 : {
3791 14537084 : D_entry *x = (D_entry *)a, *y = (D_entry *)b;
3792 : long u, v;
3793 :
3794 : /* u and v are the class numbers of x and y */
3795 14537084 : u = x->h * (!!(x->m & 2) + 1);
3796 14537084 : v = y->h * (!!(y->m & 2) + 1);
3797 : /* Sort by class number */
3798 14537084 : if (u < v) return -1;
3799 10114125 : if (u > v) return 1;
3800 : /* Sort by discriminant (which is < 0, hence the sign reversal) */
3801 3036312 : if (x->D > y->D) return -1;
3802 0 : if (x->D < y->D) return 1;
3803 0 : return 0;
3804 : }
3805 :
3806 : /* Build a table containing fundamental D, |D| <= maxD whose class groups
3807 : * - are cyclic generated by an element of norm L0
3808 : * - have class number at most maxh
3809 : * The table is ordered using _qsort_cmp above, which ranks the discriminants
3810 : * by class number, then by absolute discriminant.
3811 : *
3812 : * INPUT:
3813 : * - maxd: largest allowed discriminant
3814 : * - maxh: largest allowed class number
3815 : * - L0: norm of class group generator (2, 3, 5, or 7)
3816 : *
3817 : * OUTPUT:
3818 : * - tablelen: length of return value
3819 : *
3820 : * RETURN:
3821 : * - array of {D, h(D), kronecker symbols for small p} */
3822 : static D_entry *
3823 3031 : scanD0(long *tablelen, long *minD, long maxD, long maxh, long L0)
3824 : {
3825 : pari_sp av;
3826 : D_entry *tab;
3827 : long i, lF, cnt;
3828 : GEN F;
3829 :
3830 : /* NB: As seen in the loop below, the real class number of D can be */
3831 : /* 2*maxh if cl(D) is cyclic. */
3832 3031 : tab = (D_entry *) stack_malloc((maxD/4)*sizeof(*tab)); /* Overestimate */
3833 3031 : F = vecfactorsquarefreeu_coprime(*minD, maxD, mkvecsmall(2));
3834 3031 : lF = lg(F);
3835 30294845 : for (av = avma, cnt = 0, i = 1; i < lF; i++, set_avma(av))
3836 : {
3837 30291814 : GEN DD, ordL, f, q = gel(F,i);
3838 : long j, k, n, h, L1, d, D;
3839 : ulong m;
3840 :
3841 30291814 : if (!q) continue; /* not square-free */
3842 : /* restrict to possibly cyclic class groups */
3843 12284627 : k = lg(q) - 1; if (k > 2) continue;
3844 9571418 : d = i + *minD - 1; /* q = prime divisors of d */
3845 9571418 : if ((d & 3) == 1) continue;
3846 4816005 : D = -d; /* d = 3 (mod 4), D = 1 mod 4 fundamental */
3847 4816005 : if (kross(D, L0) < 1) continue;
3848 :
3849 : /* L1 initially the first factor of d if small enough, otherwise ignored */
3850 2314500 : L1 = (k > 1 && q[1] <= MAX_L1)? q[1]: 0;
3851 :
3852 : /* Check if h(D) is too big */
3853 2314500 : h = hclassno6u(d) / 6;
3854 2314500 : if (h > 2*maxh || (!L1 && h > maxh)) continue;
3855 :
3856 : /* Check if ord(f) is not big enough to generate at least half the
3857 : * class group (where f is the L0-primeform). */
3858 2170137 : DD = stoi(D);
3859 2170137 : f = primeform_u(DD, L0);
3860 2170137 : ordL = qfi_order(qfbred_i(f), stoi(h));
3861 2170137 : n = itos(ordL);
3862 2170137 : if (n < h/2 || (!L1 && n < h)) continue;
3863 :
3864 : /* If f is big enough, great! Otherwise, for each potential L1,
3865 : * do a discrete log to see if it is NOT in the subgroup generated
3866 : * by L0; stop as soon as such is found. */
3867 1862892 : for (j = 1;; j++) {
3868 2106238 : if (n == h || (L1 && !qfi_Shanks(primeform_u(DD, L1), f, n))) {
3869 1767325 : dbg_printf(2)("D0=%ld good with L1=%ld\n", D, L1);
3870 1767325 : break;
3871 : }
3872 338913 : if (!L1) break;
3873 243346 : L1 = (j <= k && k > 1 && q[j] <= MAX_L1 ? q[j] : 0);
3874 : }
3875 : /* The first bit of m is set iff f generates a proper subgroup of cl(D)
3876 : * (hence implying that we need L1). */
3877 1862892 : m = (n < h ? 1 : 0);
3878 : /* bits j and j+1 give the 2-bit number 1 + (D|p) where p = prime(j) */
3879 55426944 : for (j = 1 ; j <= SMOOTH_PRIMES; j++)
3880 : {
3881 53564052 : ulong x = (ulong) (1 + kross(D, PRIMES[j]));
3882 53564052 : m |= x << (2*j);
3883 : }
3884 :
3885 : /* Insert d, h and m into the table */
3886 1862892 : tab[cnt].D = D;
3887 1862892 : tab[cnt].h = h;
3888 1862892 : tab[cnt].m = m; cnt++;
3889 : }
3890 :
3891 : /* Sort the table */
3892 3031 : qsort(tab, cnt, sizeof(*tab), _qsort_cmp);
3893 3031 : *tablelen = cnt;
3894 3031 : *minD = maxD + 3 - (maxD & 3); /* smallest d >= maxD, d = 3 (mod 4) */
3895 3031 : return tab;
3896 : }
3897 :
3898 : /* Populate Ds with discriminants (and attached data) that can be
3899 : * used to calculate the modular polynomial of level L and invariant
3900 : * inv. Return the number of discriminants found. */
3901 : static long
3902 3029 : discriminant_with_classno_at_least(disc_info bestD[MODPOLY_MAX_DCNT],
3903 : long L, long inv, GEN Q, long ignore_sparse)
3904 : {
3905 : enum { SMALL_L_BOUND = 101 };
3906 3029 : long max_max_D = 160000 * (inv ? 2 : 1);
3907 : long minD, maxD, maxh, L0, max_L1, minbits, Dcnt, flags, s, d, i, tablen;
3908 : D_entry *tab;
3909 3029 : double eps, cost, best_eps = -1.0, best_cost = -1.0;
3910 : disc_info Ds[MODPOLY_MAX_DCNT];
3911 3029 : long best_cnt = 0;
3912 : pari_timer T;
3913 3029 : timer_start(&T);
3914 :
3915 3029 : s = modinv_sparse_factor(inv);
3916 3029 : d = ceildivuu(L+1, s) + 1;
3917 :
3918 : /* maxD of 10000 allows us to get a satisfactory discriminant in
3919 : * under 250ms in most cases. */
3920 3029 : maxD = 10000;
3921 : /* Allow the class number to overshoot L by 50%. Must be at least
3922 : * 1.1*L, and higher values don't seem to provide much benefit,
3923 : * except when L is small, in which case it's necessary to get any
3924 : * discriminant at all in some cases. */
3925 3029 : maxh = (L / s < SMALL_L_BOUND) ? 10 * L : 1.5 * L;
3926 :
3927 3029 : flags = ignore_sparse ? MODPOLY_IGNORE_SPARSE_FACTOR : 0;
3928 3029 : L0 = select_L0(L, inv, 0);
3929 3029 : max_L1 = L / 2 + 2; /* for L=11 we need L1=7 for j */
3930 3029 : minbits = modpoly_height_bound(L, inv);
3931 3029 : if (Q) minbits += expi(Q);
3932 3029 : minD = 7;
3933 :
3934 6058 : while ( ! best_cnt) {
3935 3031 : while (maxD <= max_max_D) {
3936 : /* TODO: Find a way to re-use tab when we need multiple modpolys */
3937 3031 : tab = scanD0(&tablen, &minD, maxD, maxh, L0);
3938 3031 : dbg_printf(1)("Found %ld potential fundamental discriminants\n", tablen);
3939 :
3940 3031 : Dcnt = modpoly_pickD(Ds, L, inv, L0, max_L1, minbits, flags, tab, tablen);
3941 3031 : eps = 0.0;
3942 3031 : cost = 0.0;
3943 :
3944 3031 : if (Dcnt) {
3945 3029 : long n1 = 0;
3946 6077 : for (i = 0; i < Dcnt; i++) {
3947 3048 : n1 = maxss(n1, Ds[i].n1);
3948 3048 : cost += Ds[i].cost;
3949 : }
3950 3029 : eps = (n1 * s - L) / (double)L;
3951 :
3952 3029 : if (best_cost < 0.0 || cost < best_cost) {
3953 3029 : if (best_cnt)
3954 0 : for (i = 0; i < best_cnt; i++) killblock((GEN)bestD[i].primes);
3955 3029 : (void) memcpy(bestD, Ds, Dcnt * sizeof(disc_info));
3956 3029 : best_cost = cost;
3957 3029 : best_cnt = Dcnt;
3958 3029 : best_eps = eps;
3959 : /* We're satisfied if n1 is within 5% of L. */
3960 3029 : if (L / s <= SMALL_L_BOUND || eps < 0.05) break;
3961 : } else {
3962 0 : for (i = 0; i < Dcnt; i++) killblock((GEN)Ds[i].primes);
3963 : }
3964 : } else {
3965 2 : if (log2(maxD) > BITS_IN_LONG - 2 * (log2(L) + 2))
3966 : {
3967 0 : char *err = stack_sprintf("modular polynomial of level %ld and invariant %ld",L,inv);
3968 0 : pari_err(e_ARCH, err);
3969 : }
3970 : }
3971 2 : maxD *= 2;
3972 2 : minD += 4;
3973 2 : dbg_printf(0)(" Doubling discriminant search space (closest: %.1f%%, cost ratio: %.1f)...\n", eps*100, cost/(double)(d*(L-1)));
3974 : }
3975 3029 : max_max_D *= 2;
3976 : }
3977 :
3978 3029 : if (DEBUGLEVEL > 3) {
3979 0 : pari_sp av = avma;
3980 0 : err_printf("Found discriminant(s):\n");
3981 0 : for (i = 0; i < best_cnt; ++i) {
3982 0 : long h = itos(classno(stoi(bestD[i].D1)));
3983 0 : set_avma(av);
3984 0 : err_printf(" D = %ld, h = %ld, u = %ld, L0 = %ld, L1 = %ld, n1 = %ld, n2 = %ld, cost = %ld\n",
3985 0 : bestD[i].D1, h, usqrt(bestD[i].D1 / bestD[i].D0), bestD[i].L0,
3986 0 : bestD[i].L1, bestD[i].n1, bestD[i].n2, bestD[i].cost);
3987 : }
3988 0 : err_printf("(off target by %.1f%%, cost ratio: %.1f)\n",
3989 0 : best_eps*100, best_cost/(double)(d*(L-1)));
3990 : }
3991 3029 : return best_cnt;
3992 : }
|