Code coverage tests

This page documents the degree to which the PARI/GP source code is tested by our public test suite, distributed with the source distribution in directory src/test/. This is measured by the gcov utility; we then process gcov output using the lcov frond-end.

We test a few variants depending on Configure flags on the pari.math.u-bordeaux.fr machine (x86_64 architecture), and agregate them in the final report:

The target is to exceed 90% coverage for all mathematical modules (given that branches depending on DEBUGLEVEL or DEBUGMEM are not covered). This script is run to produce the results below.

LCOV - code coverage report
Current view: top level - basemath - polmodular.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.18.1 lcov report (development 30582-6e9af8ee1d) Lines: 2626 2740 95.8 %
Date: 2025-12-20 09:23:49 Functions: 157 161 97.5 %
Legend: Lines: hit not hit

          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       41368 : modinv_level(long inv)
      30             : {
      31       41368 :   switch (inv) {
      32       32189 :     case INV_J:     return 1;
      33         903 :     case INV_G2:
      34         903 :     case INV_W3W3E2:return 3;
      35        1119 :     case INV_F:
      36             :     case INV_F2:
      37             :     case INV_F4:
      38        1119 :     case INV_F8:    return 6;
      39          56 :     case INV_F3:    return 2;
      40         532 :     case INV_W3W3:  return 6;
      41        1603 :     case INV_W2W7E2:
      42        1603 :     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         546 :     case INV_W2W5E2:
      47         546 :     case INV_W2W5:  return 30;
      48         322 :     case INV_W2W13: return 26;
      49        1809 :     case INV_W3W7:  return 42;
      50         655 :     case INV_W5W7:  return 35;
      51          56 :     case INV_W3W13: return 39;
      52        1008 :     case INV_ATKIN3:
      53             :     case INV_ATKIN5:
      54             :     case INV_ATKIN7:
      55             :     case INV_ATKIN11:
      56             :     case INV_ATKIN13:
      57             :     case INV_ATKIN17:
      58             :     case INV_ATKIN19:
      59             :     case INV_ATKIN23:
      60        1008 :     case INV_ATKIN29: return inv-100;
      61             :   }
      62             :   pari_err_BUG("modinv_level"); return 0;/*LCOV_EXCL_LINE*/
      63             : }
      64             : 
      65             : /* Where applicable, returns N=p1*p2 (possibly p2=1) s.t. two j's
      66             :  * related to the same f are N-isogenous, and 0 otherwise.  This is
      67             :  * often (but not necessarily) equal to the level. */
      68             : long
      69     7437562 : modinv_degree(long *p1, long *p2, long inv)
      70             : {
      71     7437562 :   switch (inv) {
      72      297342 :     case INV_W3W5:  return (*p1 = 3) * (*p2 = 5);
      73      427304 :     case INV_W2W3E2:
      74      427304 :     case INV_W2W3:  return (*p1 = 2) * (*p2 = 3);
      75     1533918 :     case INV_W2W5E2:
      76     1533918 :     case INV_W2W5:  return (*p1 = 2) * (*p2 = 5);
      77      947813 :     case INV_W2W7E2:
      78      947813 :     case INV_W2W7:  return (*p1 = 2) * (*p2 = 7);
      79     1454419 :     case INV_W2W13: return (*p1 = 2) * (*p2 = 13);
      80      523917 :     case INV_W3W7:  return (*p1 = 3) * (*p2 = 7);
      81      786066 :     case INV_W3W3E2:
      82      786066 :     case INV_W3W3:  return (*p1 = 3) * (*p2 = 3);
      83      568755 :     case INV_W5W7:  return (*p1 = 5) * (*p2 = 7);
      84      195062 :     case INV_W3W13: return (*p1 = 3) * (*p2 = 13);
      85      291827 :     case INV_ATKIN3:
      86             :     case INV_ATKIN5:
      87             :     case INV_ATKIN7:
      88             :     case INV_ATKIN11:
      89             :     case INV_ATKIN13:
      90             :     case INV_ATKIN17:
      91             :     case INV_ATKIN19:
      92             :     case INV_ATKIN23:
      93      291827 :     case INV_ATKIN29: return (*p1 = inv-100) * (*p2 = 1);
      94             :   }
      95      411139 :   *p1 = *p2 = 1; return 0;
      96             : }
      97             : 
      98             : /* Certain invariants require that D not have 2 in it's conductor, but
      99             :  * this doesn't apply to every invariant with even level so we handle
     100             :  * it separately */
     101             : INLINE int
     102      566569 : modinv_odd_conductor(long inv)
     103             : {
     104      566569 :   switch (inv) {
     105       76633 :     case INV_F:
     106             :     case INV_W3W3:
     107       76633 :     case INV_W3W7: return 1;
     108             :   }
     109      489936 :   return 0;
     110             : }
     111             : 
     112             : long
     113    22917001 : modinv_height_factor(long inv)
     114             : {
     115    22917001 :   switch (inv) {
     116        5536 :     case INV_J:     return 1;
     117        7070 :     case INV_G2:    return 3;
     118     3109724 :     case INV_F:     return 72;
     119          28 :     case INV_F2:    return 36;
     120      536382 :     case INV_F3:    return 24;
     121          49 :     case INV_F4:    return 18;
     122          49 :     case INV_F8:    return 9;
     123          63 :     case INV_W2W3:  return 72;
     124     2353463 :     case INV_W3W3:  return 36;
     125     3610845 :     case INV_W2W5:  return 54;
     126     1340998 :     case INV_W2W7:  return 48;
     127        1386 :     case INV_W3W5:  return 36;
     128     3907638 :     case INV_W2W13: return 42;
     129     1125957 :     case INV_W3W7:  return 32;
     130     1167138 :     case INV_W2W3E2:return 36;
     131      180796 :     case INV_W2W5E2:return 27;
     132     1061844 :     case INV_W2W7E2:return 24;
     133          49 :     case INV_W3W3E2:return 18;
     134     1127910 :     case INV_W5W7:  return 24;
     135          14 :     case INV_W3W13: return 28;
     136     3380062 :     case INV_ATKIN3:
     137             :     case INV_ATKIN5:
     138             :     case INV_ATKIN7:
     139             :     case INV_ATKIN11:
     140             :     case INV_ATKIN13:
     141             :     case INV_ATKIN17:
     142             :     case INV_ATKIN19:
     143             :     case INV_ATKIN23:
     144     3380062 :     case INV_ATKIN29: return (inv-99)/2;
     145             :     default: pari_err_BUG("modinv_height_factor"); return 0;/*LCOV_EXCL_LINE*/
     146             :   }
     147             : }
     148             : 
     149             : long
     150     1907423 : disc_best_modinv(long D)
     151             : {
     152             :   long ret;
     153     1907423 :   ret = INV_F;     if (modinv_good_disc(ret, D)) return ret;
     154     1534057 :   ret = INV_W2W3;  if (modinv_good_disc(ret, D)) return ret;
     155     1534057 :   ret = INV_W2W5;  if (modinv_good_disc(ret, D)) return ret;
     156     1238755 :   ret = INV_W2W7;  if (modinv_good_disc(ret, D)) return ret;
     157     1139957 :   ret = INV_W2W13; if (modinv_good_disc(ret, D)) return ret;
     158      838012 :   ret = INV_W3W3;  if (modinv_good_disc(ret, D)) return ret;
     159      651805 :   ret = INV_W2W3E2;if (modinv_good_disc(ret, D)) return ret;
     160      579453 :   ret = INV_W3W5;  if (modinv_good_disc(ret, D)) return ret;
     161      579299 :   ret = INV_W3W7;  if (modinv_good_disc(ret, D)) return ret;
     162      511091 :   ret = INV_W3W13; if (modinv_good_disc(ret, D)) return ret;
     163      511091 :   ret = INV_W2W5E2;if (modinv_good_disc(ret, D)) return ret;
     164      494753 :   ret = INV_F3;    if (modinv_good_disc(ret, D)) return ret;
     165      464485 :   ret = INV_W2W7E2;if (modinv_good_disc(ret, D)) return ret;
     166      376656 :   ret = INV_W5W7;  if (modinv_good_disc(ret, D)) return ret;
     167      283836 :   ret = INV_W3W3E2;if (modinv_good_disc(ret, D)) return ret;
     168      283836 :   ret = INV_ATKIN29;if (modinv_good_disc(ret, D)) return ret;
     169      134519 :   ret = INV_ATKIN23;if (modinv_good_disc(ret, D)) return ret;
     170       63098 :   ret = INV_ATKIN19;if (modinv_good_disc(ret, D)) return ret;
     171       29897 :   ret = INV_ATKIN17;if (modinv_good_disc(ret, D)) return ret;
     172       14532 :   ret = INV_ATKIN13;if (modinv_good_disc(ret, D)) return ret;
     173        9009 :   ret = INV_ATKIN11;if (modinv_good_disc(ret, D)) return ret;
     174        4697 :   ret = INV_ATKIN7;if (modinv_good_disc(ret, D)) return ret;
     175        3829 :   ret = INV_ATKIN5;if (modinv_good_disc(ret, D)) return ret;
     176        2191 :   ret = INV_G2;    if (modinv_good_disc(ret, D)) return ret;
     177        1064 :   ret = INV_ATKIN3;if (modinv_good_disc(ret, D)) return ret;
     178          77 :   return INV_J;
     179             : }
     180             : 
     181             : INLINE long
     182       48096 : modinv_sparse_factor(long inv)
     183             : {
     184       48096 :   switch (inv) {
     185        3643 :   case INV_G2:
     186             :   case INV_F8:
     187             :   case INV_W3W5:
     188             :   case INV_W2W5E2:
     189             :   case INV_W3W3E2:
     190        3643 :     return 3;
     191         604 :   case INV_F:
     192         604 :     return 24;
     193         357 :   case INV_F2:
     194             :   case INV_W2W3:
     195         357 :     return 12;
     196         112 :   case INV_F3:
     197         112 :     return 8;
     198        1645 :   case INV_F4:
     199             :   case INV_W2W3E2:
     200             :   case INV_W2W5:
     201             :   case INV_W3W3:
     202        1645 :     return 6;
     203        1046 :   case INV_W2W7:
     204        1046 :     return 4;
     205        2914 :   case INV_W2W7E2:
     206             :   case INV_W2W13:
     207             :   case INV_W3W7:
     208        2914 :     return 2;
     209             :   }
     210       37775 :   return 1;
     211             : }
     212             : 
     213             : #define IQ_FILTER_1MOD3 1
     214             : #define IQ_FILTER_2MOD3 2
     215             : #define IQ_FILTER_1MOD4 4
     216             : #define IQ_FILTER_3MOD4 8
     217             : 
     218             : INLINE long
     219       15877 : modinv_pfilter(long inv)
     220             : {
     221       15877 :   switch (inv) {
     222        2045 :   case INV_G2:
     223             :   case INV_W3W3:
     224             :   case INV_W3W3E2:
     225             :   case INV_W3W5:
     226             :   case INV_W2W5:
     227             :   case INV_W2W3E2:
     228             :   case INV_W2W5E2:
     229             :   case INV_W3W13:
     230        2045 :     return IQ_FILTER_1MOD3; /* ensure unique cube roots */
     231         529 :   case INV_W2W7:
     232             :   case INV_F3:
     233         529 :     return IQ_FILTER_1MOD4; /* ensure at most two 4th/8th roots */
     234         951 :   case INV_F:
     235             :   case INV_F2:
     236             :   case INV_F4:
     237             :   case INV_F8:
     238             :   case INV_W2W3:
     239             :     /* Ensure unique cube roots and at most two 4th/8th roots */
     240         951 :     return IQ_FILTER_1MOD3 | IQ_FILTER_1MOD4;
     241             :   }
     242       12352 :   return 0;
     243             : }
     244             : 
     245             : int
     246    11453157 : modinv_good_prime(long inv, long p)
     247             : {
     248    11453157 :   switch (inv) {
     249      342781 :   case INV_G2:
     250             :   case INV_W2W3E2:
     251             :   case INV_W3W3:
     252             :   case INV_W3W3E2:
     253             :   case INV_W3W5:
     254             :   case INV_W2W5E2:
     255             :   case INV_W2W5:
     256      342781 :     return (p % 3) == 2;
     257      398068 :   case INV_W2W7:
     258             :   case INV_F3:
     259      398068 :     return (p & 3) != 1;
     260      408761 :   case INV_F2:
     261             :   case INV_F4:
     262             :   case INV_F8:
     263             :   case INV_F:
     264             :   case INV_W2W3:
     265      408761 :     return ((p % 3) == 2) && (p & 3) != 1;
     266             :   }
     267    10303547 :   return 1;
     268             : }
     269             : 
     270             : /* Returns true if the prime p does not divide the conductor of D */
     271             : INLINE int
     272     3502361 : prime_to_conductor(long D, long p)
     273             : {
     274             :   long b;
     275     3502361 :   if (p > 2) return (D % (p * p));
     276     1280564 :   b = D & 0xF;
     277     1280564 :   return (b && b != 4); /* 2 divides the conductor of D <=> D=0,4 mod 16 */
     278             : }
     279             : 
     280             : INLINE GEN
     281     3502361 : red_primeform(long D, long p)
     282             : {
     283     3502361 :   pari_sp av = avma;
     284             :   GEN P;
     285     3502361 :   if (!prime_to_conductor(D, p)) return NULL;
     286     3502361 :   P = primeform_u(stoi(D), p); /* primitive since p \nmid conductor */
     287     3502361 :   return gc_upto(av, qfi_red(P));
     288             : }
     289             : 
     290             : /* Computes product of primeforms over primes appearing in the prime
     291             :  * factorization of n (including multiplicity) */
     292             : GEN
     293      144613 : qfb_nform(long D, long n)
     294             : {
     295      144613 :   pari_sp av = avma;
     296      144613 :   GEN N = NULL, fa = factoru(n), P = gel(fa,1), E = gel(fa,2);
     297      144613 :   long i, l = lg(P);
     298             : 
     299      433587 :   for (i = 1; i < l; ++i)
     300             :   {
     301             :     long j, e;
     302      288974 :     GEN Q = red_primeform(D, P[i]);
     303      288974 :     if (!Q) return gc_NULL(av);
     304      288974 :     e = E[i];
     305      288974 :     if (i == 1) { N = Q; j = 1; } else j = 0;
     306      433419 :     for (; j < e; ++j) N = qfbcomp_i(Q, N);
     307             :   }
     308      144613 :   return gc_upto(av, N);
     309             : }
     310             : 
     311             : INLINE int
     312     1717114 : qfb_is_two_torsion(GEN x)
     313             : {
     314     3434228 :   return equali1(gel(x,1)) || !signe(gel(x,2))
     315     3434228 :     || equalii(gel(x,1), gel(x,2)) || equalii(gel(x,1), gel(x,3));
     316             : }
     317             : 
     318             : /* Returns true iff the products p1*p2, p1*p2^-1, p1^-1*p2, and
     319             :  * p1^-1*p2^-1 are all distinct in cl(D) */
     320             : INLINE int
     321      235817 : qfb_distinct_prods(long D, long p1, long p2)
     322             : {
     323             :   GEN P1, P2;
     324             : 
     325      235817 :   P1 = red_primeform(D, p1);
     326      235817 :   if (!P1) return 0;
     327      235817 :   P1 = qfbsqr_i(P1);
     328             : 
     329      235817 :   P2 = red_primeform(D, p2);
     330      235817 :   if (!P2) return 0;
     331      235817 :   P2 = qfbsqr_i(P2);
     332             : 
     333      235817 :   return !(equalii(gel(P1,1), gel(P2,1)) && absequalii(gel(P1,2), gel(P2,2)));
     334             : }
     335             : 
     336             : /* By Corollary 3.1 of Enge-Schertz Constructing elliptic curves over finite
     337             :  * fields using double eta-quotients, we need p1 != p2 to both be noninert
     338             :  * and prime to the conductor, and if p1=p2=p we want p split and prime to the
     339             :  * conductor. We exclude the case that p1=p2 divides the conductor, even
     340             :  * though this does yield class invariants */
     341             : INLINE int
     342     5500283 : modinv_double_eta_good_disc(long D, long inv)
     343             : {
     344     5500283 :   pari_sp av = avma;
     345             :   GEN P;
     346             :   long i1, i2, p1, p2, N;
     347             : 
     348     5500283 :   N = modinv_degree(&p1, &p2, inv);
     349     5500283 :   if (! N) return 0;
     350     5500283 :   i1 = kross(D, p1);
     351     5500283 :   if (i1 < 0) return 0;
     352             :   /* Exclude ramified case for w_{p,p} */
     353     2518939 :   if (p1 == p2 && !i1) return 0;
     354     2518939 :   i2 = kross(D, p2);
     355     2518939 :   if (i2 < 0) return 0;
     356             :   /* this also verifies that p1 is prime to the conductor */
     357     1403828 :   P = red_primeform(D, p1);
     358     1403828 :   if (!P || gequal1(gel(P,1)) /* don't allow p1 to be principal */
     359             :       /* if p1 is unramified, require it to have order > 2 */
     360     1403828 :       || (i1 && qfb_is_two_torsion(P))) return gc_bool(av,0);
     361     1402036 :   if (p1 == p2) /* if p1=p2 we need p1*p1 to be distinct from its inverse */
     362      222621 :     return gc_bool(av, !qfb_is_two_torsion(qfbsqr_i(P)));
     363             : 
     364             :   /* this also verifies that p2 is prime to the conductor */
     365     1179415 :   P = red_primeform(D, p2);
     366     1179415 :   if (!P || gequal1(gel(P,1)) /* don't allow p2 to be principal */
     367             :       /* if p2 is unramified, require it to have order > 2 */
     368     1179415 :       || (i2 && qfb_is_two_torsion(P))) return gc_bool(av,0);
     369     1177875 :   set_avma(av);
     370             : 
     371             :   /* if p1 and p2 are split, we also require p1*p2, p1*p2^-1, p1^-1*p2,
     372             :    * and p1^-1*p2^-1 to be distinct */
     373     1177875 :   if (i1>0 && i2>0 && !qfb_distinct_prods(D, p1, p2)) return gc_bool(av,0);
     374     1174815 :   if (!i1 && !i2) {
     375             :     /* if both p1 and p2 are ramified, make sure their product is not
     376             :      * principal */
     377      144060 :     P = qfb_nform(D, N);
     378      144060 :     if (equali1(gel(P,1))) return gc_bool(av,0);
     379      143829 :     set_avma(av);
     380             :   }
     381     1174584 :   return 1;
     382             : }
     383             : 
     384             : /* Assumes D is a good discriminant for inv, which implies that the
     385             :  * level is prime to the conductor */
     386             : long
     387         798 : modinv_ramified(long D, long inv, long *pN)
     388             : {
     389         798 :   long p1, p2; *pN = modinv_degree(&p1, &p2, inv);
     390         798 :   if (*pN <= 1) return 0;
     391         798 :   return !(D % p1) && !(D % p2);
     392             : }
     393             : 
     394             : static int
     395      665182 : modinv_good_atkin(long L, long D)
     396             : {
     397      665182 :   long L2 = L*L;
     398             :   GEN q;
     399      665182 :   if (kross(D,L) < 0 || -D%L2==0) return 0;
     400      351911 :   if (-D > 4*L2) return 1;
     401       33565 :   q = red_primeform(D,L);
     402       33565 :   if (equali1(gel(q,1))) return 0;
     403       29988 :   if (D%L==0) return 1;
     404       26726 :   q = qfbsqr(q);
     405       26726 :   if (equali1(gel(q,1))) return 0;
     406       20895 :   return 1;
     407             : }
     408             : 
     409             : int
     410    15170644 : modinv_good_disc(long inv, long D)
     411             : {
     412    15170644 :   switch (inv) {
     413      923311 :   case INV_J:
     414      923311 :     return 1;
     415       98728 :   case INV_G2:
     416       98728 :     return !!(D % 3);
     417      502845 :   case INV_F3:
     418      502845 :     return (-D & 7) == 7;
     419     2058390 :   case INV_F:
     420             :   case INV_F2:
     421             :   case INV_F4:
     422             :   case INV_F8:
     423     2058390 :     return ((-D & 7) == 7) && (D % 3);
     424      622069 :   case INV_W3W5:
     425      622069 :     return (D % 3) && modinv_double_eta_good_disc(D, inv);
     426      310919 :   case INV_W3W3E2:
     427      310919 :     return (D % 3) && modinv_double_eta_good_disc(D, inv);
     428      901663 :   case INV_W3W3:
     429      901663 :     return (D & 1) && (D % 3) && modinv_double_eta_good_disc(D, inv);
     430      667688 :   case INV_W2W3E2:
     431      667688 :     return (D % 3) && modinv_double_eta_good_disc(D, inv);
     432     1554721 :   case INV_W2W3:
     433     1554721 :     return ((-D & 7) == 7) && (D % 3) && modinv_double_eta_good_disc(D, inv);
     434     1577387 :   case INV_W2W5:
     435     1577387 :     return ((-D % 80) != 20) && (D % 3) && modinv_double_eta_good_disc(D, inv);
     436      540722 :   case INV_W2W5E2:
     437      540722 :     return (D % 3) && modinv_double_eta_good_disc(D, inv);
     438      566027 :   case INV_W2W7E2:
     439      566027 :     return ((-D % 112) != 84) && modinv_double_eta_good_disc(D, inv);
     440     1324607 :   case INV_W2W7:
     441     1324607 :     return ((-D & 7) == 7) && modinv_double_eta_good_disc(D, inv);
     442     1181782 :   case INV_W2W13:
     443     1181782 :     return ((-D % 208) != 52) && modinv_double_eta_good_disc(D, inv);
     444      679735 :   case INV_W3W7:
     445      679735 :     return (D & 1) && (-D % 21) && modinv_double_eta_good_disc(D, inv);
     446      474180 :   case INV_W5W7: /* NB: This is a guess; avs doesn't have an entry */
     447      474180 :     return modinv_double_eta_good_disc(D, inv);
     448      520688 :   case INV_W3W13: /* NB: This is a guess; avs doesn't have an entry */
     449      520688 :     return (D & 1) && (D % 3) && modinv_double_eta_good_disc(D, inv);
     450      665182 :   case INV_ATKIN3:
     451             :   case INV_ATKIN5:
     452             :   case INV_ATKIN7:
     453             :   case INV_ATKIN11:
     454             :   case INV_ATKIN13:
     455             :   case INV_ATKIN17:
     456             :   case INV_ATKIN19:
     457             :   case INV_ATKIN23:
     458             :   case INV_ATKIN29:
     459      665182 :      return modinv_good_atkin(inv-100, D);
     460             :   }
     461           0 :   pari_err_BUG("modinv_good_disc");
     462             :   return 0;/*LCOV_EXCL_LINE*/
     463             : }
     464             : 
     465             : int
     466        1078 : modinv_is_Weber(long inv)
     467             : {
     468           0 :   return inv == INV_F || inv == INV_F2 || inv == INV_F3 || inv == INV_F4
     469        1078 :     || inv == INV_F8;
     470             : }
     471             : 
     472             : int
     473      259174 : modinv_is_double_eta(long inv)
     474             : {
     475      259174 :   switch (inv) {
     476       42162 :   case INV_W2W3:
     477             :   case INV_W2W3E2:
     478             :   case INV_W2W5:
     479             :   case INV_W2W5E2:
     480             :   case INV_W2W7:
     481             :   case INV_W2W7E2:
     482             :   case INV_W2W13:
     483             :   case INV_W3W3:
     484             :   case INV_W3W3E2:
     485             :   case INV_W3W5:
     486             :   case INV_W3W7:
     487             :   case INV_W5W7:
     488             :   case INV_W3W13:
     489             :   case INV_ATKIN3: /* as far as we are concerned */
     490             :   case INV_ATKIN5: /* as far as we are concerned */
     491             :   case INV_ATKIN7: /* as far as we are concerned */
     492             :   case INV_ATKIN11: /* as far as we are concerned */
     493             :   case INV_ATKIN13: /* as far as we are concerned */
     494             :   case INV_ATKIN17: /* as far as we are concerned */
     495             :   case INV_ATKIN19: /* as far as we are concerned */
     496             :   case INV_ATKIN23: /* as far as we are concerned */
     497             :   case INV_ATKIN29: /* as far as we are concerned */
     498       42162 :     return 1;
     499             :   }
     500      217012 :   return 0;
     501             : }
     502             : 
     503             : /* END Code from "class_inv.h" */
     504             : 
     505             : INLINE int
     506       10064 : safe_abs_sqrt(ulong *r, ulong x, ulong p, ulong pi, ulong s2)
     507             : {
     508       10064 :   if (krouu(x, p) == -1)
     509             :   {
     510        4513 :     if (p%4 == 1) return 0;
     511        4513 :     x = Fl_neg(x, p);
     512             :   }
     513       10064 :   *r = Fl_sqrt_pre_i(x, s2, p, pi);
     514       10064 :   return 1;
     515             : }
     516             : 
     517             : INLINE int
     518        5021 : eighth_root(ulong *r, ulong x, ulong p, ulong pi, ulong s2)
     519             : {
     520             :   ulong s;
     521        5021 :   if (krouu(x, p) == -1) return 0;
     522        2811 :   s = Fl_sqrt_pre_i(x, s2, p, pi);
     523        2811 :   return safe_abs_sqrt(&s, s, p, pi, s2) && safe_abs_sqrt(r, s, p, pi, s2);
     524             : }
     525             : 
     526             : INLINE ulong
     527        3259 : modinv_f_from_j(ulong j, ulong p, ulong pi, ulong s2, long only_residue)
     528             : {
     529        3259 :   pari_sp av = avma;
     530             :   GEN pol, r;
     531             :   long i;
     532        3259 :   ulong g2, f = ULONG_MAX;
     533             : 
     534             :   /* f^8 must be a root of X^3 - \gamma_2 X - 16 */
     535        3259 :   g2 = Fl_sqrtl_pre(j, 3, p, pi);
     536             : 
     537        3259 :   pol = mkvecsmall5(0UL, Fl_neg(16 % p, p), Fl_neg(g2, p), 0UL, 1UL);
     538        3259 :   r = Flx_roots_pre(pol, p, pi);
     539        5825 :   for (i = 1; i < lg(r); ++i)
     540        5825 :     if (only_residue)
     541        1177 :     { if (krouu(r[i], p) != -1) return gc_ulong(av,r[i]); }
     542        4648 :     else if (eighth_root(&f, r[i], p, pi, s2)) return gc_ulong(av,f);
     543           0 :   pari_err_BUG("modinv_f_from_j");
     544             :   return 0;/*LCOV_EXCL_LINE*/
     545             : }
     546             : 
     547             : INLINE ulong
     548         168 : modinv_f3_from_j(ulong j, ulong p, ulong pi, ulong s2)
     549             : {
     550         168 :   pari_sp av = avma;
     551             :   GEN pol, r;
     552             :   long i;
     553         168 :   ulong f = ULONG_MAX;
     554             : 
     555         168 :   pol = mkvecsmall5(0UL,
     556         168 :       Fl_neg(4096 % p, p), Fl_sub(768 % p, j, p), Fl_neg(48 % p, p), 1UL);
     557         168 :   r = Flx_roots_pre(pol, p, pi);
     558         373 :   for (i = 1; i < lg(r); ++i)
     559         373 :     if (eighth_root(&f, r[i], p, pi, s2)) return gc_ulong(av,f);
     560           0 :   pari_err_BUG("modinv_f3_from_j");
     561             :   return 0;/*LCOV_EXCL_LINE*/
     562             : }
     563             : 
     564             : /* Return the exponent e for the double-eta "invariant" w such that
     565             :  * w^e is a class invariant.  For example w2w3^12 is a class
     566             :  * invariant, so double_eta_exponent(INV_W2W3) is 12 and
     567             :  * double_eta_exponent(INV_W2W3E2) is 6. */
     568             : INLINE ulong
     569       67341 : double_eta_exponent(long inv)
     570             : {
     571       67341 :   switch (inv) {
     572        2446 :   case INV_W2W3: return 12;
     573       13012 :   case INV_W2W3E2:
     574             :   case INV_W2W5:
     575       13012 :   case INV_W3W3: return 6;
     576        9730 :   case INV_W2W7: return 4;
     577        5419 :   case INV_W3W5:
     578             :   case INV_W2W5E2:
     579        5419 :   case INV_W3W3E2: return 3;
     580       15351 :   case INV_W2W7E2:
     581             :   case INV_W2W13:
     582       15351 :   case INV_W3W7: return 2;
     583       21383 :   default: return 1;
     584             :   }
     585             : }
     586             : 
     587             : INLINE ulong
     588          77 : weber_exponent(long inv)
     589             : {
     590          77 :   switch (inv)
     591             :   {
     592          77 :   case INV_F:  return 24;
     593           0 :   case INV_F2: return 12;
     594           0 :   case INV_F3: return 8;
     595           0 :   case INV_F4: return 6;
     596           0 :   case INV_F8: return 3;
     597           0 :   default:     return 1;
     598             :   }
     599             : }
     600             : 
     601             : INLINE ulong
     602       32113 : double_eta_power(long inv, ulong w, ulong p, ulong pi)
     603             : {
     604       32113 :   return Fl_powu_pre(w, double_eta_exponent(inv), p, pi);
     605             : }
     606             : 
     607             : static GEN
     608         455 : double_eta_raw_to_Fp(GEN f, GEN p)
     609             : {
     610         455 :   GEN u = FpX_red(RgV_to_RgX(gel(f,1), 0), p);
     611         455 :   GEN v = FpX_red(RgV_to_RgX(gel(f,2), 0), p);
     612         455 :   return mkvec3(u, v, gel(f,3));
     613             : }
     614             : 
     615             : /* Given a root x of polclass(D, inv) modulo N, returns a root of polclass(D,0)
     616             :  * modulo N by plugging x to a modular polynomial. For double-eta quotients,
     617             :  * this is done by plugging x into the modular polynomial Phi(INV_WpWq, j)
     618             :  * Enge, Morain 2013: Generalised Weber Functions. */
     619             : GEN
     620        1133 : Fp_modinv_to_j(GEN x, long inv, GEN p)
     621             : {
     622        1133 :   switch(inv)
     623             :   {
     624         258 :     case INV_J: return Fp_red(x, p);
     625         343 :     case INV_G2: return Fp_powu(x, 3, p);
     626          77 :     case INV_F: case INV_F2: case INV_F3: case INV_F4: case INV_F8:
     627             :     {
     628          77 :       GEN xe = Fp_powu(x, weber_exponent(inv), p);
     629          77 :       return Fp_div(Fp_powu(subiu(xe, 16), 3, p), xe, p);
     630             :     }
     631         455 :     default:
     632         455 :     if (modinv_is_double_eta(inv))
     633             :     {
     634         455 :       GEN xe = Fp_powu(x, double_eta_exponent(inv), p);
     635         455 :       GEN uvk = double_eta_raw_to_Fp(double_eta_raw(inv), p);
     636         455 :       GEN J0 = FpX_eval(gel(uvk,1), xe, p);
     637         455 :       GEN J1 = FpX_eval(gel(uvk,2), xe, p);
     638         455 :       GEN J2 = Fp_pow(xe, gel(uvk,3), p);
     639         455 :       GEN phi = mkvec3(J0, J1, J2);
     640         455 :       return FpX_oneroot(RgX_to_FpX(RgV_to_RgX(phi,1), p),p);
     641             :     }
     642             :     pari_err_BUG("Fp_modinv_to_j"); return NULL;/* LCOV_EXCL_LINE */
     643             :   }
     644             : }
     645             : 
     646             : /* Assuming p = 2 (mod 3) and p = 3 (mod 4): if the two 12th roots of
     647             :  * x (mod p) exist, set *r to one of them and return 1, otherwise
     648             :  * return 0 (without touching *r). */
     649             : INLINE int
     650         893 : twelth_root(ulong *r, ulong x, ulong p, ulong pi, ulong s2)
     651             : {
     652         893 :   ulong t = Fl_sqrtl_pre(x, 3, p, pi);
     653         893 :   if (krouu(t, p) == -1) return 0;
     654         850 :   t = Fl_sqrt_pre_i(t, s2, p, pi);
     655         850 :   return safe_abs_sqrt(r, t, p, pi, s2);
     656             : }
     657             : 
     658             : INLINE int
     659        5537 : sixth_root(ulong *r, ulong x, ulong p, ulong pi, ulong s2)
     660             : {
     661        5537 :   ulong t = Fl_sqrtl_pre(x, 3, p, pi);
     662        5536 :   if (krouu(t, p) == -1) return 0;
     663        5349 :   *r = Fl_sqrt_pre_i(t, s2, p, pi);
     664        5352 :   return 1;
     665             : }
     666             : 
     667             : INLINE int
     668        3926 : fourth_root(ulong *r, ulong x, ulong p, ulong pi, ulong s2)
     669             : {
     670             :   ulong s;
     671        3926 :   if (krouu(x, p) == -1) return 0;
     672        3592 :   s = Fl_sqrt_pre_i(x, s2, p, pi);
     673        3592 :   return safe_abs_sqrt(r, s, p, pi, s2);
     674             : }
     675             : 
     676             : INLINE int
     677       34774 : double_eta_root(long inv, ulong *r, ulong w, ulong p, ulong pi, ulong s2)
     678             : {
     679       34774 :   switch (double_eta_exponent(inv)) {
     680         893 :   case 12: return twelth_root(r, w, p, pi, s2);
     681        5537 :   case 6: return sixth_root(r, w, p, pi, s2);
     682        3926 :   case 4: return fourth_root(r, w, p, pi, s2);
     683        2343 :   case 3: *r = Fl_sqrtl_pre(w, 3, p, pi); return 1;
     684        8310 :   case 2: return krouu(w, p) != -1 && !!(*r = Fl_sqrt_pre_i(w, s2, p, pi));
     685       13764 :   default: *r = w; return 1; /* case 1 */
     686             :   }
     687             : }
     688             : 
     689             : /* F = double_eta_Fl(inv, p) */
     690             : static GEN
     691       61086 : Flx_double_eta_xpoly(GEN F, ulong j, ulong p, ulong pi)
     692             : {
     693       61086 :   GEN u = gel(F,1), v = gel(F,2), w;
     694       61086 :   long i, k = itos(gel(F,3)), lu = lg(u), lv = lg(v), lw = lu + 1;
     695             : 
     696       61086 :   w = cgetg(lw, t_VECSMALL); /* lu >= max(lv,k) */
     697       61087 :   w[1] = 0; /* variable number */
     698     1600603 :   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);
     699      122176 :   for (     ; i < lu; i++) uel(w, i+1) = uel(u,i);
     700       61088 :   uel(w, k+2) = Fl_add(uel(w, k+2), Fl_sqr_pre(j, p, pi), p);
     701       61089 :   return Flx_renormalize(w, lw);
     702             : }
     703             : 
     704             : /* F = double_eta_Fl(inv, p) */
     705             : static GEN
     706       32113 : Flx_double_eta_jpoly(GEN F, ulong x, ulong p, ulong pi)
     707             : {
     708       32113 :   pari_sp av = avma;
     709       32113 :   GEN u = gel(F,1), v = gel(F,2), xs;
     710       32113 :   long k = itos(gel(F,3));
     711             :   ulong a, b, c;
     712             : 
     713             :   /* u is always longest and the length is bigger than k */
     714       32113 :   xs = Fl_powers_pre(x, lg(u) - 1, p, pi);
     715       32113 :   c = Flv_dotproduct_pre(u, xs, p, pi);
     716       32113 :   b = Flv_dotproduct_pre(v, xs, p, pi);
     717       32113 :   a = uel(xs, k + 1);
     718       32113 :   set_avma(av);
     719       32113 :   return mkvecsmall4(0, c, b, a);
     720             : }
     721             : 
     722             : /* reduce F = double_eta_raw(inv) mod p */
     723             : static GEN
     724       39903 : double_eta_raw_to_Fl(GEN f, ulong p)
     725             : {
     726       39903 :   GEN u = ZV_to_Flv(gel(f,1), p);
     727       39903 :   GEN v = ZV_to_Flv(gel(f,2), p);
     728       39903 :   return mkvec3(u, v, gel(f,3));
     729             : }
     730             : /* double_eta_raw(inv) mod p */
     731             : static GEN
     732       33889 : double_eta_Fl(long inv, ulong p)
     733       33889 : { return double_eta_raw_to_Fl(double_eta_raw(inv), p); }
     734             : 
     735             : /* Go through roots of Psi(X,j) until one has an double_eta_exponent(inv)-th
     736             :  * root, and return that root. F = double_eta_Fl(inv,p) */
     737             : INLINE ulong
     738        6697 : modinv_double_eta_from_j(GEN F, long inv, ulong j, ulong p, ulong pi, ulong s2)
     739             : {
     740        6697 :   pari_sp av = avma;
     741             :   long i;
     742        6697 :   ulong f = ULONG_MAX;
     743        6697 :   GEN a = Flx_double_eta_xpoly(F, j, p, pi);
     744        6697 :   a = Flx_roots_pre(a, p, pi);
     745        7582 :   for (i = 1; i < lg(a); ++i)
     746        7582 :     if (double_eta_root(inv, &f, uel(a, i), p, pi, s2)) break;
     747        6697 :   if (i == lg(a)) pari_err_BUG("modinv_double_eta_from_j");
     748        6697 :   return gc_ulong(av,f);
     749             : }
     750             : 
     751             : /* assume j1 != j2 */
     752             : static long
     753       20496 : modinv_double_eta_from_2j(
     754             :   ulong *r, long inv, ulong j1, ulong j2, ulong p, ulong pi, ulong s2)
     755             : {
     756       20496 :   GEN f, g, d, F = double_eta_Fl(inv, p);
     757       20498 :   f = Flx_double_eta_xpoly(F, j1, p, pi);
     758       20497 :   g = Flx_double_eta_xpoly(F, j2, p, pi);
     759       20498 :   d = Flx_gcd(f, g, p);
     760             :   /* we should have deg(d) = 1, but because j1 or j2 may not have the correct
     761             :    * endomorphism ring, we use the less strict conditional underneath */
     762       40990 :   return (degpol(d) > 2 || (*r = Flx_oneroot_pre(d, p, pi)) == p
     763       40991 :           || ! double_eta_root(inv, r, *r, p, pi, s2));
     764             : }
     765             : 
     766             : long
     767       20577 : modfn_unambiguous_root(ulong *r, long inv, ulong j0, norm_eqn_t ne, GEN jdb)
     768             : {
     769       20577 :   pari_sp av = avma;
     770       20577 :   long p1, p2, v = ne->v, p1_depth;
     771       20577 :   ulong j1, p = ne->p, pi = ne->pi, s2 = ne->s2;
     772             :   GEN phi;
     773             : 
     774       20577 :   (void) modinv_degree(&p1, &p2, inv);
     775       20577 :   p1_depth = u_lval(v, p1);
     776             : 
     777       20577 :   phi = polmodular_db_getp(jdb, p1, p);
     778       20577 :   if (!next_surface_nbr(&j1, phi, p1, p1_depth, j0, NULL, p, pi))
     779           0 :     pari_err_BUG("modfn_unambiguous_root");
     780       20573 :   if (p2 == p1) {
     781        1989 :     if (!next_surface_nbr(&j1, phi, p1, p1_depth, j1, &j0, p, pi))
     782           0 :       pari_err_BUG("modfn_unambiguous_root");
     783       18584 :   } else if (p2 > 1)
     784             :   {
     785       10190 :     long p2_depth = u_lval(v, p2);
     786       10190 :     phi = polmodular_db_getp(jdb, p2, p);
     787       10190 :     if (!next_surface_nbr(&j1, phi, p2, p2_depth, j1, NULL, p, pi))
     788           0 :       pari_err_BUG("modfn_unambiguous_root");
     789             :   }
     790       23525 :   return gc_long(av, j1 != j0
     791       20566 :                      && !modinv_double_eta_from_2j(r, inv, j0, j1, p, pi, s2));
     792             : }
     793             : 
     794             : ulong
     795      205999 : modfn_root(ulong j, norm_eqn_t ne, long inv)
     796             : {
     797      205999 :   ulong f, p = ne->p, pi = ne->pi, s2 = ne->s2;
     798      205999 :   switch (inv) {
     799      197898 :     case INV_J:  return j;
     800        4675 :     case INV_G2: return Fl_sqrtl_pre(j, 3, p, pi);
     801        1894 :     case INV_F:  return modinv_f_from_j(j, p, pi, s2, 0);
     802         196 :     case INV_F2:
     803         196 :       f = modinv_f_from_j(j, p, pi, s2, 0);
     804         196 :       return Fl_sqr_pre(f, p, pi);
     805         168 :     case INV_F3: return modinv_f3_from_j(j, p, pi, s2);
     806         553 :     case INV_F4:
     807         553 :       f = modinv_f_from_j(j, p, pi, s2, 0);
     808         553 :       return Fl_sqr_pre(Fl_sqr_pre(f, p, pi), p, pi);
     809         616 :     case INV_F8: return modinv_f_from_j(j, p, pi, s2, 1);
     810             :   }
     811           0 :   if (modinv_is_double_eta(inv))
     812             :   {
     813           0 :     pari_sp av = avma;
     814           0 :     ulong f = modinv_double_eta_from_j(double_eta_Fl(inv,p), inv, j, p, pi, s2);
     815           0 :     return gc_ulong(av,f);
     816             :   }
     817             :   pari_err_BUG("modfn_root"); return ULONG_MAX;/*LCOV_EXCL_LINE*/
     818             : }
     819             : 
     820             : /* F = double_eta_raw(inv) */
     821             : long
     822        6011 : modinv_j_from_2double_eta(
     823             :   GEN F, long inv, ulong x0, ulong x1, ulong p, ulong pi)
     824             : {
     825             :   GEN f, g, d;
     826             : 
     827        6011 :   x0 = double_eta_power(inv, x0, p, pi);
     828        6011 :   x1 = double_eta_power(inv, x1, p, pi);
     829        6011 :   F = double_eta_raw_to_Fl(F, p);
     830        6011 :   f = Flx_double_eta_jpoly(F, x0, p, pi);
     831        6011 :   g = Flx_double_eta_jpoly(F, x1, p, pi);
     832        6011 :   d = Flx_gcd(f, g, p); /* >= 1 */
     833        6011 :   return degpol(d) == 1;
     834             : }
     835             : 
     836             : /* x root of (X^24 - 16)^3 - X^24 * j = 0 => j = (x^24 - 16)^3 / x^24 */
     837             : INLINE ulong
     838        1844 : modinv_j_from_f(ulong x, ulong n, ulong p, ulong pi)
     839             : {
     840        1844 :   ulong x24 = Fl_powu_pre(x, 24 / n, p, pi);
     841        1844 :   return Fl_div(Fl_powu_pre(Fl_sub(x24, 16 % p, p), 3, p, pi), x24, p);
     842             : }
     843             : /* should never be called if modinv_double_eta(inv) is true */
     844             : INLINE ulong
     845       70203 : modfn_preimage(ulong x, ulong p, ulong pi, long inv)
     846             : {
     847       70203 :   switch (inv) {
     848       64433 :     case INV_J:  return x;
     849        3926 :     case INV_G2: return Fl_powu_pre(x, 3, p, pi);
     850             :     /* NB: could replace these with a single call modinv_j_from_f(x,inv,p,pi)
     851             :      * but avoid the dependence on the actual value of inv */
     852         640 :     case INV_F:  return modinv_j_from_f(x, 1, p, pi);
     853         196 :     case INV_F2: return modinv_j_from_f(x, 2, p, pi);
     854         168 :     case INV_F3: return modinv_j_from_f(x, 3, p, pi);
     855         392 :     case INV_F4: return modinv_j_from_f(x, 4, p, pi);
     856         448 :     case INV_F8: return modinv_j_from_f(x, 8, p, pi);
     857             :   }
     858             :   pari_err_BUG("modfn_preimage"); return ULONG_MAX;/*LCOV_EXCL_LINE*/
     859             : }
     860             : 
     861             : /* SECTION: class group bb_group. */
     862             : 
     863             : INLINE GEN
     864      152847 : mkqfis(GEN a, ulong b, ulong c, GEN D) { retmkqfb(a, utoi(b), utoi(c), D); }
     865             : 
     866             : /* SECTION: dot-product-like functions on Fl's with precomputed inverse. */
     867             : 
     868             : /* Computes x0y1 + y0x1 (mod p); assumes p < 2^63. */
     869             : INLINE ulong
     870    63715116 : Fl_addmul2(
     871             :   ulong x0, ulong x1, ulong y0, ulong y1,
     872             :   ulong p, ulong pi)
     873             : {
     874    63715116 :   return Fl_addmulmul_pre(x0,y1,y0,x1,p,pi);
     875             : }
     876             : 
     877             : /* Computes x0y2 + x1y1 + x2y0 (mod p); assumes p < 2^62. */
     878             : INLINE ulong
     879    12612029 : Fl_addmul3(
     880             :   ulong x0, ulong x1, ulong x2, ulong y0, ulong y1, ulong y2,
     881             :   ulong p, ulong pi)
     882             : {
     883             :   ulong l0, l1, h0, h1;
     884             :   LOCAL_OVERFLOW;
     885             :   LOCAL_HIREMAINDER;
     886    12612029 :   l0 = mulll(x0, y2); h0 = hiremainder;
     887    12612029 :   l1 = mulll(x1, y1); h1 = hiremainder;
     888    12612029 :   l1 = addll(l0, l1); h1 = addllx(h0, h1);
     889    12612029 :   l0 = mulll(x2, y0); h0 = hiremainder;
     890    12612029 :   l1 = addll(l0, l1); h1 = addllx(h0, h1);
     891    12612029 :   return remll_pre(h1, l1, p, pi);
     892             : }
     893             : 
     894             : /* Computes x0y3 + x1y2 + x2y1 + x3y0 (mod p); assumes p < 2^62. */
     895             : INLINE ulong
     896     5317745 : Fl_addmul4(
     897             :   ulong x0, ulong x1, ulong x2, ulong x3,
     898             :   ulong y0, ulong y1, ulong y2, ulong y3,
     899             :   ulong p, ulong pi)
     900             : {
     901             :   ulong l0, l1, h0, h1;
     902             :   LOCAL_OVERFLOW;
     903             :   LOCAL_HIREMAINDER;
     904     5317745 :   l0 = mulll(x0, y3); h0 = hiremainder;
     905     5317745 :   l1 = mulll(x1, y2); h1 = hiremainder;
     906     5317745 :   l1 = addll(l0, l1); h1 = addllx(h0, h1);
     907     5317745 :   l0 = mulll(x2, y1); h0 = hiremainder;
     908     5317745 :   l1 = addll(l0, l1); h1 = addllx(h0, h1);
     909     5317745 :   l0 = mulll(x3, y0); h0 = hiremainder;
     910     5317745 :   l1 = addll(l0, l1); h1 = addllx(h0, h1);
     911     5317745 :   return remll_pre(h1, l1, p, pi);
     912             : }
     913             : 
     914             : /* Computes x0y4 + x1y3 + x2y2 + x3y1 + x4y0 (mod p); assumes p < 2^62. */
     915             : INLINE ulong
     916    26435367 : Fl_addmul5(
     917             :   ulong x0, ulong x1, ulong x2, ulong x3, ulong x4,
     918             :   ulong y0, ulong y1, ulong y2, ulong y3, ulong y4,
     919             :   ulong p, ulong pi)
     920             : {
     921             :   ulong l0, l1, h0, h1;
     922             :   LOCAL_OVERFLOW;
     923             :   LOCAL_HIREMAINDER;
     924    26435367 :   l0 = mulll(x0, y4); h0 = hiremainder;
     925    26435367 :   l1 = mulll(x1, y3); h1 = hiremainder;
     926    26435367 :   l1 = addll(l0, l1); h1 = addllx(h0, h1);
     927    26435367 :   l0 = mulll(x2, y2); h0 = hiremainder;
     928    26435367 :   l1 = addll(l0, l1); h1 = addllx(h0, h1);
     929    26435367 :   l0 = mulll(x3, y1); h0 = hiremainder;
     930    26435367 :   l1 = addll(l0, l1); h1 = addllx(h0, h1);
     931    26435367 :   l0 = mulll(x4, y0); h0 = hiremainder;
     932    26435367 :   l1 = addll(l0, l1); h1 = addllx(h0, h1);
     933    26435367 :   return remll_pre(h1, l1, p, pi);
     934             : }
     935             : 
     936             : /* A polmodular database for a given class invariant consists of a t_VEC whose
     937             :  * L-th entry is 0 or a GEN pointing to Phi_L.  This function produces a pair
     938             :  * of databases corresponding to the j-invariant and inv */
     939             : GEN
     940       21492 : polmodular_db_init(long inv)
     941             : {
     942       21492 :   const long LEN = 32;
     943       21492 :   GEN res = cgetg_block(3, t_VEC);
     944       21492 :   gel(res, 1) = zerovec_block(LEN);
     945       21492 :   gel(res, 2) = (inv == INV_J)? gen_0: zerovec_block(LEN);
     946       21492 :   return res;
     947             : }
     948             : 
     949             : void
     950       27200 : polmodular_db_add_level(GEN *DB, long L, long inv)
     951             : {
     952       27200 :   GEN db = gel(*DB, (inv == INV_J)? 1: 2);
     953       27200 :   long max_L = lg(db) - 1;
     954       27200 :   if (L > max_L) {
     955             :     GEN newdb;
     956          43 :     long i, newlen = 2 * L;
     957             : 
     958          43 :     newdb = cgetg_block(newlen + 1, t_VEC);
     959        1419 :     for (i = 1; i <= max_L; ++i) gel(newdb, i) = gel(db, i);
     960        2941 :     for (     ; i <= newlen; ++i) gel(newdb, i) = gen_0;
     961          43 :     killblock(db);
     962          43 :     gel(*DB, (inv == INV_J)? 1: 2) = db = newdb;
     963             :   }
     964       27200 :   if (typ(gel(db, L)) == t_INT) {
     965        8584 :     pari_sp av = avma;
     966        8584 :     GEN x = polmodular0_ZM(L, inv, NULL, NULL, 0, DB); /* may set db[L] */
     967        8584 :     GEN y = gel(db, L);
     968        8584 :     gel(db, L) = gclone(x);
     969        8584 :     if (typ(y) != t_INT) gunclone(y);
     970        8584 :     set_avma(av);
     971             :   }
     972       27200 : }
     973             : 
     974             : void
     975        5277 : polmodular_db_add_levels(GEN *db, long *levels, long k, long inv)
     976             : {
     977             :   long i;
     978       10949 :   for (i = 0; i < k; ++i) polmodular_db_add_level(db, levels[i], inv);
     979        5277 : }
     980             : 
     981             : GEN
     982      393209 : polmodular_db_for_inv(GEN db, long inv) { return gel(db, (inv==INV_J)? 1: 2); }
     983             : 
     984             : /* TODO: Also cache modpoly mod p for most recent p (avoid repeated
     985             :  * reductions in, for example, polclass.c:oneroot_of_classpoly(). */
     986             : GEN
     987      569036 : polmodular_db_getp(GEN db, long L, ulong p)
     988             : {
     989      569036 :   GEN f = gel(db, L);
     990      569036 :   if (isintzero(f)) pari_err_BUG("polmodular_db_getp");
     991      569037 :   return ZM_to_Flm(f, p);
     992             : }
     993             : 
     994             : /* SECTION: Table of discriminants to use. */
     995             : typedef struct {
     996             :   long GENcode0;  /* used when serializing the struct to a t_VECSMALL */
     997             :   long inv;      /* invariant */
     998             :   long L;        /* modpoly level */
     999             :   long D0;       /* fundamental discriminant */
    1000             :   long D1;       /* chosen discriminant */
    1001             :   long L0;       /* first generator norm */
    1002             :   long L1;       /* second generator norm */
    1003             :   long n1;       /* order of L0 in cl(D1) */
    1004             :   long n2;       /* order of L0 in cl(D2) where D2 = L^2 D1 */
    1005             :   long dl1;      /* m such that L0^m = L in cl(D1) */
    1006             :   long dl2_0;    /* These two are (m, n) such that L0^m L1^n = form of norm L^2 in D2 */
    1007             :   long dl2_1;    /* This n is always 1 or 0. */
    1008             :   /* this part is not serialized */
    1009             :   long nprimes;  /* number of primes needed for D1 */
    1010             :   long cost;     /* cost to enumerate  subgroup of cl(L^2D): subgroup size is n2 if L1=0, 2*n2 o.w. */
    1011             :   long bits;
    1012             :   ulong *primes;
    1013             :   ulong *traces;
    1014             : } disc_info;
    1015             : 
    1016             : #define MODPOLY_MAX_DCNT    64
    1017             : 
    1018             : /* Flag for last parameter of discriminant_with_classno_at_least.
    1019             :  * Warning: ignoring the sparse factor makes everything slower by
    1020             :  * something like (sparse factor)^3. */
    1021             : #define USE_SPARSE_FACTOR 0
    1022             : #define IGNORE_SPARSE_FACTOR 1
    1023             : 
    1024             : static long
    1025             : discriminant_with_classno_at_least(disc_info Ds[MODPOLY_MAX_DCNT], long L,
    1026             :   long inv, GEN Q, long ignore_sparse);
    1027             : 
    1028             : /* SECTION: evaluation functions for modular polynomials of small level. */
    1029             : 
    1030             : /* Based on phi2_eval_ff() in Sutherland's classpoly programme.
    1031             :  * Calculates Phi_2(X, j) (mod p) with 6M+7A (4 reductions, not
    1032             :  * counting those for Phi_2) */
    1033             : INLINE GEN
    1034    29889809 : Flm_Fl_phi2_evalx(GEN phi2, ulong j, ulong p, ulong pi)
    1035             : {
    1036    29889809 :   GEN res = cgetg(6, t_VECSMALL);
    1037             :   ulong j2, t1;
    1038             : 
    1039    29811911 :   res[1] = 0; /* variable name */
    1040             : 
    1041    29811911 :   j2 = Fl_sqr_pre(j, p, pi);
    1042    29863936 :   t1 = Fl_add(j, coeff(phi2, 3, 1), p);
    1043    29851300 :   t1 = Fl_addmul2(j, j2, t1, coeff(phi2, 2, 1), p, pi);
    1044    29950520 :   res[2] = Fl_add(t1, coeff(phi2, 1, 1), p);
    1045             : 
    1046    29917771 :   t1 = Fl_addmul2(j, j2, coeff(phi2, 3, 2), coeff(phi2, 2, 2), p, pi);
    1047    29987105 :   res[3] = Fl_add(t1, coeff(phi2, 2, 1), p);
    1048             : 
    1049    29946713 :   t1 = Fl_mul_pre(j, coeff(phi2, 3, 2), p, pi);
    1050    29937449 :   t1 = Fl_add(t1, coeff(phi2, 3, 1), p);
    1051    29904243 :   res[4] = Fl_sub(t1, j2, p);
    1052             : 
    1053    29879082 :   res[5] = 1;
    1054    29879082 :   return res;
    1055             : }
    1056             : 
    1057             : /* Based on phi3_eval_ff() in Sutherland's classpoly programme.
    1058             :  * Calculates Phi_3(X, j) (mod p) with 13M+13A (6 reductions, not
    1059             :  * counting those for Phi_3) */
    1060             : INLINE GEN
    1061     4215793 : Flm_Fl_phi3_evalx(GEN phi3, ulong j, ulong p, ulong pi)
    1062             : {
    1063     4215793 :   GEN res = cgetg(7, t_VECSMALL);
    1064             :   ulong j2, j3, t1;
    1065             : 
    1066     4209415 :   res[1] = 0; /* variable name */
    1067             : 
    1068     4209415 :   j2 = Fl_sqr_pre(j, p, pi);
    1069     4215452 :   j3 = Fl_mul_pre(j, j2, p, pi);
    1070             : 
    1071     4216390 :   t1 = Fl_add(j, coeff(phi3, 4, 1), p);
    1072     4216575 :   t1 = Fl_addmul3(j, j2, j3, t1, coeff(phi3, 3, 1), coeff(phi3, 2, 1), p, pi);
    1073     4227376 :   res[2] = Fl_add(t1, coeff(phi3, 1, 1), p);
    1074             : 
    1075     4223804 :   t1 = Fl_addmul3(j, j2, j3, coeff(phi3, 4, 2),
    1076     4223804 :                   coeff(phi3, 3, 2), coeff(phi3, 2, 2), p, pi);
    1077     4228192 :   res[3] = Fl_add(t1, coeff(phi3, 2, 1), p);
    1078             : 
    1079     4224688 :   t1 = Fl_addmul3(j, j2, j3, coeff(phi3, 4, 3),
    1080     4224688 :                   coeff(phi3, 3, 3), coeff(phi3, 3, 2), p, pi);
    1081     4228660 :   res[4] = Fl_add(t1, coeff(phi3, 3, 1), p);
    1082             : 
    1083     4225409 :   t1 = Fl_addmul2(j, j2, coeff(phi3, 4, 3), coeff(phi3, 4, 2), p, pi);
    1084     4228016 :   t1 = Fl_add(t1, coeff(phi3, 4, 1), p);
    1085     4224419 :   res[5] = Fl_sub(t1, j3, p);
    1086             : 
    1087     4220665 :   res[6] = 1;
    1088     4220665 :   return res;
    1089             : }
    1090             : 
    1091             : /* Based on phi5_eval_ff() in Sutherland's classpoly programme.
    1092             :  * Calculates Phi_5(X, j) (mod p) with 33M+31A (10 reductions, not
    1093             :  * counting those for Phi_5) */
    1094             : INLINE GEN
    1095     5307958 : Flm_Fl_phi5_evalx(GEN phi5, ulong j, ulong p, ulong pi)
    1096             : {
    1097     5307958 :   GEN res = cgetg(9, t_VECSMALL);
    1098             :   ulong j2, j3, j4, j5, t1;
    1099             : 
    1100     5301275 :   res[1] = 0; /* variable name */
    1101             : 
    1102     5301275 :   j2 = Fl_sqr_pre(j, p, pi);
    1103     5307221 :   j3 = Fl_mul_pre(j, j2, p, pi);
    1104     5307924 :   j4 = Fl_sqr_pre(j2, p, pi);
    1105     5307633 :   j5 = Fl_mul_pre(j, j4, p, pi);
    1106             : 
    1107     5309991 :   t1 = Fl_add(j, coeff(phi5, 6, 1), p);
    1108     5310278 :   t1 = Fl_addmul5(j, j2, j3, j4, j5, t1,
    1109     5310278 :                   coeff(phi5, 5, 1), coeff(phi5, 4, 1),
    1110     5310278 :                   coeff(phi5, 3, 1), coeff(phi5, 2, 1),
    1111             :                   p, pi);
    1112     5319262 :   res[2] = Fl_add(t1, coeff(phi5, 1, 1), p);
    1113             : 
    1114     5315163 :   t1 = Fl_addmul5(j, j2, j3, j4, j5,
    1115     5315163 :                   coeff(phi5, 6, 2), coeff(phi5, 5, 2),
    1116     5315163 :                   coeff(phi5, 4, 2), coeff(phi5, 3, 2), coeff(phi5, 2, 2),
    1117             :                   p, pi);
    1118     5320194 :   res[3] = Fl_add(t1, coeff(phi5, 2, 1), p);
    1119             : 
    1120     5316036 :   t1 = Fl_addmul5(j, j2, j3, j4, j5,
    1121     5316036 :                   coeff(phi5, 6, 3), coeff(phi5, 5, 3),
    1122     5316036 :                   coeff(phi5, 4, 3), coeff(phi5, 3, 3), coeff(phi5, 3, 2),
    1123             :                   p, pi);
    1124     5319718 :   res[4] = Fl_add(t1, coeff(phi5, 3, 1), p);
    1125             : 
    1126     5316706 :   t1 = Fl_addmul5(j, j2, j3, j4, j5,
    1127     5316706 :                   coeff(phi5, 6, 4), coeff(phi5, 5, 4),
    1128     5316706 :                   coeff(phi5, 4, 4), coeff(phi5, 4, 3), coeff(phi5, 4, 2),
    1129             :                   p, pi);
    1130     5321319 :   res[5] = Fl_add(t1, coeff(phi5, 4, 1), p);
    1131             : 
    1132     5317321 :   t1 = Fl_addmul5(j, j2, j3, j4, j5,
    1133     5317321 :                   coeff(phi5, 6, 5), coeff(phi5, 5, 5),
    1134     5317321 :                   coeff(phi5, 5, 4), coeff(phi5, 5, 3), coeff(phi5, 5, 2),
    1135             :                   p, pi);
    1136     5322305 :   res[6] = Fl_add(t1, coeff(phi5, 5, 1), p);
    1137             : 
    1138     5319465 :   t1 = Fl_addmul4(j, j2, j3, j4,
    1139     5319465 :                   coeff(phi5, 6, 5), coeff(phi5, 6, 4),
    1140     5319465 :                   coeff(phi5, 6, 3), coeff(phi5, 6, 2),
    1141             :                   p, pi);
    1142     5323445 :   t1 = Fl_add(t1, coeff(phi5, 6, 1), p);
    1143     5320104 :   res[7] = Fl_sub(t1, j5, p);
    1144             : 
    1145     5316956 :   res[8] = 1;
    1146     5316956 :   return res;
    1147             : }
    1148             : 
    1149             : GEN
    1150    46443822 : Flm_Fl_polmodular_evalx(GEN phi, long L, ulong j, ulong p, ulong pi)
    1151             : {
    1152    46443822 :   switch (L) {
    1153    29902628 :     case 2: return Flm_Fl_phi2_evalx(phi, j, p, pi);
    1154     4214265 :     case 3: return Flm_Fl_phi3_evalx(phi, j, p, pi);
    1155     5306801 :     case 5: return Flm_Fl_phi5_evalx(phi, j, p, pi);
    1156     7020128 :     default: { /* not GC clean, but gc_upto-safe */
    1157     7020128 :       GEN j_powers = Fl_powers_pre(j, L + 1, p, pi);
    1158     7103833 :       return Flm_Flc_mul_pre_Flx(phi, j_powers, p, pi, 0);
    1159             :     }
    1160             :   }
    1161             : }
    1162             : 
    1163             : /* SECTION: Velu's formula for the codmain curve (Fl case). */
    1164             : 
    1165             : INLINE ulong
    1166     1854428 : Fl_mul4(ulong x, ulong p)
    1167     1854428 : { return Fl_double(Fl_double(x, p), p); }
    1168             : 
    1169             : INLINE ulong
    1170       98975 : Fl_mul5(ulong x, ulong p)
    1171       98975 : { return Fl_add(x, Fl_mul4(x, p), p); }
    1172             : 
    1173             : INLINE ulong
    1174      927289 : Fl_mul8(ulong x, ulong p)
    1175      927289 : { return Fl_double(Fl_mul4(x, p), p); }
    1176             : 
    1177             : INLINE ulong
    1178      828385 : Fl_mul6(ulong x, ulong p)
    1179      828385 : { return Fl_sub(Fl_mul8(x, p), Fl_double(x, p), p); }
    1180             : 
    1181             : INLINE ulong
    1182       98974 : Fl_mul7(ulong x, ulong p)
    1183       98974 : { return Fl_sub(Fl_mul8(x, p), x, p); }
    1184             : 
    1185             : /* Given an elliptic curve E = [a4, a6] over F_p and a nonzero point
    1186             :  * pt on E, return the quotient E' = E/<P> = [a4_img, a6_img] */
    1187             : static void
    1188       98989 : Fle_quotient_from_kernel_generator(
    1189             :   ulong *a4_img, ulong *a6_img, ulong a4, ulong a6, GEN pt, ulong p, ulong pi)
    1190             : {
    1191       98989 :   pari_sp av = avma;
    1192       98989 :   ulong t = 0, w = 0;
    1193             :   GEN Q;
    1194             :   ulong xQ, yQ, tQ, uQ;
    1195             : 
    1196       98989 :   Q = gcopy(pt);
    1197             :   /* Note that, as L is odd, say L = 2n + 1, we necessarily have
    1198             :    * [(L - 1)/2]P = [n]P = [n - L]P = -[n + 1]P = -[(L + 1)/2]P.  This is
    1199             :    * what the condition Q[1] != xQ tests, so the loop will execute n times. */
    1200             :   do {
    1201      828268 :     xQ = uel(Q, 1);
    1202      828268 :     yQ = uel(Q, 2);
    1203             :     /* tQ = 6 xQ^2 + b2 xQ + b4
    1204             :      *    = 6 xQ^2 + 2 a4 (since b2 = 0 and b4 = 2 a4) */
    1205      828268 :     tQ = Fl_add(Fl_mul6(Fl_sqr_pre(xQ, p, pi), p), Fl_double(a4, p), p);
    1206      828269 :     uQ = Fl_add(Fl_mul4(Fl_sqr_pre(yQ, p, pi), p),
    1207             :                 Fl_mul_pre(tQ, xQ, p, pi), p);
    1208             : 
    1209      828286 :     t = Fl_add(t, tQ, p);
    1210      828249 :     w = Fl_add(w, uQ, p);
    1211      828213 :     Q = gc_upto(av, Fle_add(pt, Q, a4, p));
    1212      828257 :   } while (uel(Q, 1) != xQ);
    1213             : 
    1214       98976 :   set_avma(av);
    1215             :   /* a4_img = a4 - 5 * t */
    1216       98974 :   *a4_img = Fl_sub(a4, Fl_mul5(t, p), p);
    1217             :   /* a6_img = a6 - b2 * t - 7 * w = a6 - 7 * w (since a1 = a2 = 0 ==> b2 = 0) */
    1218       98974 :   *a6_img = Fl_sub(a6, Fl_mul7(w, p), p);
    1219       98973 : }
    1220             : 
    1221             : /* SECTION: Calculation of modular polynomials. */
    1222             : 
    1223             : /* Given an elliptic curve [a4, a6] over FF_p, try to find a
    1224             :  * nontrivial L-torsion point on the curve by considering n times a
    1225             :  * random point; val controls the maximum L-valuation expected of n
    1226             :  * times a random point */
    1227             : static GEN
    1228      144772 : find_L_tors_point(
    1229             :   ulong *ival,
    1230             :   ulong a4, ulong a6, ulong p, ulong pi,
    1231             :   ulong n, ulong L, ulong val)
    1232             : {
    1233      144772 :   pari_sp av = avma;
    1234             :   ulong i;
    1235             :   GEN P, Q;
    1236             :   do {
    1237      146233 :     Q = random_Flj_pre(a4, a6, p, pi);
    1238      146229 :     P = Flj_mulu_pre(Q, n, a4, p, pi);
    1239      146236 :   } while (P[3] == 0);
    1240             : 
    1241      281151 :   for (i = 0; i < val; ++i) {
    1242      235359 :     Q = Flj_mulu_pre(P, L, a4, p, pi);
    1243      235361 :     if (Q[3] == 0) break;
    1244      136376 :     P = Q;
    1245             :   }
    1246      144777 :   if (ival) *ival = i;
    1247      144777 :   return gc_GEN(av, P);
    1248             : }
    1249             : 
    1250             : static GEN
    1251       90290 : select_curve_with_L_tors_point(
    1252             :   ulong *a4, ulong *a6,
    1253             :   ulong L, ulong j, ulong n, ulong card, ulong val,
    1254             :   norm_eqn_t ne)
    1255             : {
    1256       90290 :   pari_sp av = avma;
    1257             :   ulong A4, A4t, A6, A6t;
    1258       90290 :   ulong p = ne->p, pi = ne->pi;
    1259             :   GEN P;
    1260       90290 :   if (card % L != 0) {
    1261           0 :     pari_err_BUG("select_curve_with_L_tors_point: "
    1262             :                  "Cardinality not divisible by L");
    1263             :   }
    1264             : 
    1265       90290 :   Fl_ellj_to_a4a6(j, p, &A4, &A6);
    1266       90285 :   Fl_elltwist_disc(A4, A6, ne->T, p, &A4t, &A6t);
    1267             : 
    1268             :   /* Either E = [a4, a6] or its twist has cardinality divisible by L
    1269             :    * because of the choice of p and t earlier on.  We find out which
    1270             :    * by attempting to find a point of order L on each.  See bot p16 of
    1271             :    * Sutherland 2012. */
    1272       45795 :   while (1) {
    1273             :     ulong i;
    1274      136078 :     P = find_L_tors_point(&i, A4, A6, p, pi, n, L, val);
    1275      136083 :     if (i < val)
    1276       90287 :       break;
    1277       45796 :     set_avma(av);
    1278       45795 :     lswap(A4, A4t);
    1279       45795 :     lswap(A6, A6t);
    1280             :   }
    1281       90287 :   *a4 = A4;
    1282       90287 :   *a6 = A6; return gc_GEN(av, P);
    1283             : }
    1284             : 
    1285             : /* Return 1 if the L-Sylow subgroup of the curve [a4, a6] (mod p) is
    1286             :  * cyclic, return 0 if it is not cyclic with "high" probability (I
    1287             :  * guess around 1/L^3 chance it is still cyclic when we return 0).
    1288             :  *
    1289             :  * Based on Sutherland's velu.c:velu_verify_Sylow_cyclic() in classpoly-1.0.1 */
    1290             : INLINE long
    1291       50485 : verify_L_sylow_is_cyclic(long e, ulong a4, ulong a6, ulong p, ulong pi)
    1292             : {
    1293             :   /* Number of times to try to find a point with maximal order in the
    1294             :    * L-Sylow subgroup. */
    1295             :   enum { N_RETRIES = 3 };
    1296       50485 :   pari_sp av = avma;
    1297       50485 :   long i, res = 0;
    1298             :   GEN P;
    1299       81237 :   for (i = 0; i < N_RETRIES; ++i) {
    1300       72539 :     P = random_Flj_pre(a4, a6, p, pi);
    1301       72548 :     P = Flj_mulu_pre(P, e, a4, p, pi);
    1302       72549 :     if (P[3] != 0) { res = 1; break; }
    1303             :   }
    1304       50495 :   return gc_long(av,res);
    1305             : }
    1306             : 
    1307             : static ulong
    1308       90286 : find_noniso_L_isogenous_curve(
    1309             :   ulong L, ulong n,
    1310             :   norm_eqn_t ne, long e, ulong val, ulong a4, ulong a6, GEN init_pt, long verify)
    1311             : {
    1312             :   pari_sp ltop, av;
    1313       90286 :   ulong p = ne->p, pi = ne->pi, j_res = 0;
    1314       90286 :   GEN pt = init_pt;
    1315       90286 :   ltop = av = avma;
    1316        8697 :   while (1) {
    1317             :     /* c. Use Velu to calculate L-isogenous curve E' = E/<P> */
    1318             :     ulong a4_img, a6_img;
    1319       98983 :     ulong z2 = Fl_sqr_pre(pt[3], p, pi);
    1320       98992 :     pt = mkvecsmall2(Fl_div(pt[1], z2, p),
    1321       98991 :                      Fl_div(pt[2], Fl_mul_pre(z2, pt[3], p, pi), p));
    1322       98989 :     Fle_quotient_from_kernel_generator(&a4_img, &a6_img,
    1323             :                                        a4, a6, pt, p, pi);
    1324             : 
    1325             :     /* d. If j(E') = j_res has a different endo ring to j(E), then
    1326             :      *    return j(E').  Otherwise, go to b. */
    1327       98973 :     if (!verify || verify_L_sylow_is_cyclic(e, a4_img, a6_img, p, pi)) {
    1328       90284 :       j_res = Fl_ellj_pre(a4_img, a6_img, p, pi);
    1329       90292 :       break;
    1330             :     }
    1331             : 
    1332             :     /* b. Generate random point P on E of order L */
    1333        8698 :     set_avma(av);
    1334        8698 :     pt = find_L_tors_point(NULL, a4, a6, p, pi, n, L, val);
    1335             :   }
    1336       90292 :   return gc_ulong(ltop, j_res);
    1337             : }
    1338             : 
    1339             : /* Given a prime L and a j-invariant j (mod p), return the j-invariant
    1340             :  * of a curve which has a different endomorphism ring to j and is
    1341             :  * L-isogenous to j */
    1342             : INLINE ulong
    1343       90290 : compute_L_isogenous_curve(
    1344             :   ulong L, ulong n, norm_eqn_t ne,
    1345             :   ulong j, ulong card, ulong val, long verify)
    1346             : {
    1347             :   ulong a4, a6;
    1348             :   long e;
    1349             :   GEN pt;
    1350             : 
    1351       90290 :   if (ne->p < 5 || j == 0 || j == 1728 % ne->p)
    1352           0 :     pari_err_BUG("compute_L_isogenous_curve");
    1353       90290 :   pt = select_curve_with_L_tors_point(&a4, &a6, L, j, n, card, val, ne);
    1354       90286 :   e = card / L;
    1355       90286 :   if (e * L != card) pari_err_BUG("compute_L_isogenous_curve");
    1356             : 
    1357       90286 :   return find_noniso_L_isogenous_curve(L, n, ne, e, val, a4, a6, pt, verify);
    1358             : }
    1359             : 
    1360             : INLINE GEN
    1361       41799 : get_Lsqr_cycle(const disc_info *dinfo)
    1362             : {
    1363       41799 :   long i, n1 = dinfo->n1, L = dinfo->L;
    1364       41799 :   GEN cyc = cgetg(L, t_VECSMALL);
    1365       41799 :   cyc[1] = 0;
    1366      351999 :   for (i = 2; i <= L / 2; ++i) cyc[i] = cyc[i - 1] + n1;
    1367       41799 :   if ( ! dinfo->L1) {
    1368      116377 :     for ( ; i < L; ++i) cyc[i] = cyc[i - 1] + n1;
    1369             :   } else {
    1370       28021 :     cyc[L - 1] = 2 * dinfo->n2 - n1 / 2;
    1371      249400 :     for (i = L - 2; i > L / 2; --i) cyc[i] = cyc[i + 1] - n1;
    1372             :   }
    1373       41799 :   return cyc;
    1374             : }
    1375             : 
    1376             : INLINE void
    1377      618778 : update_Lsqr_cycle(GEN cyc, const disc_info *dinfo)
    1378             : {
    1379      618778 :   long i, L = dinfo->L;
    1380    17633987 :   for (i = 1; i < L; ++i) ++cyc[i];
    1381      618778 :   if (dinfo->L1 && cyc[L - 1] == 2 * dinfo->n2) {
    1382       26400 :     long n1 = dinfo->n1;
    1383      246838 :     for (i = L / 2 + 1; i < L; ++i) cyc[i] -= n1;
    1384             :   }
    1385      618778 : }
    1386             : 
    1387             : static ulong
    1388       41787 : oneroot_of_classpoly(GEN hilb, GEN factu, norm_eqn_t ne, GEN jdb)
    1389             : {
    1390       41787 :   pari_sp av = avma;
    1391       41787 :   ulong j0, p = ne->p, pi = ne->pi;
    1392       41787 :   long i, nfactors = lg(gel(factu, 1)) - 1;
    1393       41787 :   GEN hilbp = ZX_to_Flx(hilb, p);
    1394             : 
    1395             :   /* TODO: Work out how to use hilb with better invariant */
    1396       41776 :   j0 = Flx_oneroot_split_pre(hilbp, p, pi);
    1397       41795 :   if (j0 == p) {
    1398           0 :     pari_err_BUG("oneroot_of_classpoly: "
    1399             :                  "Didn't find a root of the class polynomial");
    1400             :   }
    1401       43356 :   for (i = 1; i <= nfactors; ++i) {
    1402        1561 :     long L = gel(factu, 1)[i];
    1403        1561 :     long val = gel(factu, 2)[i];
    1404        1561 :     GEN phi = polmodular_db_getp(jdb, L, p);
    1405        1560 :     val += z_lval(ne->v, L);
    1406        1560 :     j0 = descend_volcano(phi, j0, p, pi, 0, L, val, val);
    1407        1561 :     set_avma(av);
    1408             :   }
    1409       41795 :   return gc_ulong(av, j0);
    1410             : }
    1411             : 
    1412             : /* TODO: Precompute the GEN structs and link them to dinfo */
    1413             : INLINE GEN
    1414        3104 : make_pcp_surface(const disc_info *dinfo)
    1415             : {
    1416        3104 :   GEN L = mkvecsmall(dinfo->L0);
    1417        3104 :   GEN n = mkvecsmall(dinfo->n1);
    1418        3104 :   GEN o = mkvecsmall(dinfo->n1);
    1419        3104 :   return mkvec2(mkvec3(L, n, o), mkvecsmall3(0, 1, dinfo->n1));
    1420             : }
    1421             : 
    1422             : INLINE GEN
    1423        3104 : make_pcp_floor(const disc_info *dinfo)
    1424             : {
    1425        3104 :   long k = dinfo->L1 ? 2 : 1;
    1426             :   GEN L, n, o;
    1427        3104 :   if (k==1)
    1428             :   {
    1429        1453 :     L = mkvecsmall(dinfo->L0);
    1430        1453 :     n = mkvecsmall(dinfo->n2);
    1431        1453 :     o = mkvecsmall(dinfo->n2);
    1432             :   } else
    1433             :   {
    1434        1651 :     L = mkvecsmall2(dinfo->L0, dinfo->L1);
    1435        1651 :     n = mkvecsmall2(dinfo->n2, 2);
    1436        1651 :     o = mkvecsmall2(dinfo->n2, 2);
    1437             :   }
    1438        3104 :   return mkvec2(mkvec3(L, n, o), mkvecsmall3(0, k, dinfo->n2*k));
    1439             : }
    1440             : 
    1441             : INLINE GEN
    1442       41792 : enum_volcano_surface(norm_eqn_t ne, ulong j0, GEN fdb, GEN G)
    1443             : {
    1444       41792 :   pari_sp av = avma;
    1445       41792 :   return gc_upto(av, enum_roots(j0, ne, fdb, G, NULL));
    1446             : }
    1447             : 
    1448             : INLINE GEN
    1449       41797 : enum_volcano_floor(long L, norm_eqn_t ne, ulong j0_pr, GEN fdb, GEN G)
    1450             : {
    1451       41797 :   pari_sp av = avma;
    1452             :   /* L^2 D is the discriminant for the order R = Z + L OO. */
    1453       41797 :   long DR = L * L * ne->D;
    1454       41797 :   long R_cond = L * ne->u; /* conductor(DR); */
    1455       41797 :   long w = R_cond * ne->v;
    1456             :   /* TODO: Calculate these once and for all in polmodular0_ZM(). */
    1457             :   norm_eqn_t eqn;
    1458       41797 :   memcpy(eqn, ne, sizeof *ne);
    1459       41797 :   eqn->D = DR;
    1460       41797 :   eqn->u = R_cond;
    1461       41797 :   eqn->v = w;
    1462       41797 :   return gc_upto(av, enum_roots(j0_pr, eqn, fdb, G, NULL));
    1463             : }
    1464             : 
    1465             : INLINE void
    1466       20110 : carray_reverse_inplace(long *arr, long n)
    1467             : {
    1468       20110 :   long lim = n>>1, i;
    1469       20110 :   --n;
    1470      208290 :   for (i = 0; i < lim; i++) lswap(arr[i], arr[n - i]);
    1471       20110 : }
    1472             : 
    1473             : INLINE void
    1474      660599 : append_neighbours(GEN rts, GEN surface_js, long njs, long L, long m, long i)
    1475             : {
    1476      660599 :   long r_idx = (((i - 1) + m) % njs) + 1; /* (i + m) % njs */
    1477      660599 :   long l_idx = umodsu((i - 1) - m, njs) + 1; /* (i - m) % njs */
    1478      660579 :   rts[L] = surface_js[l_idx];
    1479      660579 :   rts[L + 1] = surface_js[r_idx];
    1480      660579 : }
    1481             : 
    1482             : INLINE GEN
    1483       44126 : roots_to_coeffs(GEN rts, ulong p, long L)
    1484             : {
    1485       44126 :   long i, k, lrts= lg(rts);
    1486       44126 :   GEN M = cgetg(L+2+1, t_MAT);
    1487      960955 :   for (i = 1; i <= L+2; ++i)
    1488      916826 :     gel(M, i) = cgetg(lrts, t_VECSMALL);
    1489      729881 :   for (i = 1; i < lrts; ++i) {
    1490      685821 :     pari_sp av = avma;
    1491      685821 :     GEN modpol = Flv_roots_to_pol(gel(rts, i), p, 0);
    1492    21843455 :     for (k = 1; k <= L + 2; ++k) mael(M, k, i) = modpol[k + 1];
    1493      685608 :     set_avma(av);
    1494             :   }
    1495       44060 :   return M;
    1496             : }
    1497             : 
    1498             : /* NB: Assumes indices are offset at 0, not at 1 like in GENs;
    1499             :  * i.e. indices[i] will pick out v[indices[i] + 1] from v. */
    1500             : INLINE void
    1501      660594 : vecsmall_pick(GEN res, GEN v, GEN indices)
    1502             : {
    1503             :   long i;
    1504    18379939 :   for (i = 1; i < lg(indices); ++i) res[i] = v[indices[i] + 1];
    1505      660594 : }
    1506             : 
    1507             : /* First element of surface_js must lie above the first element of floor_js.
    1508             :  * Reverse surface_js if it is not oriented in the same direction as floor_js */
    1509             : INLINE GEN
    1510       41798 : root_matrix(long L, const disc_info *dinfo, long njinvs, GEN surface_js,
    1511             :   GEN floor_js, ulong n, ulong card, ulong val, norm_eqn_t ne)
    1512             : {
    1513             :   pari_sp av;
    1514       41798 :   long i, m = dinfo->dl1, njs = lg(surface_js) - 1, inv = dinfo->inv, rev;
    1515       41798 :   GEN rt_mat = zero_Flm_copy(L + 1, njinvs), rts, cyc;
    1516       41799 :   ulong p = ne->p, pi = ne->pi, j;
    1517       41799 :   av = avma;
    1518             : 
    1519       41799 :   i = 1;
    1520       41799 :   cyc = get_Lsqr_cycle(dinfo);
    1521       41799 :   rts = gel(rt_mat, i);
    1522       41799 :   vecsmall_pick(rts, floor_js, cyc);
    1523       41799 :   append_neighbours(rts, surface_js, njs, L, m, i);
    1524             : 
    1525       41799 :   i = 2;
    1526       41799 :   update_Lsqr_cycle(cyc, dinfo);
    1527       41799 :   rts = gel(rt_mat, i);
    1528       41799 :   vecsmall_pick(rts, floor_js, cyc);
    1529             : 
    1530             :   /* Fix orientation if necessary */
    1531       41799 :   if (modinv_is_double_eta(inv)) {
    1532             :     /* TODO: There is potential for refactoring between this,
    1533             :      * double_eta_initial_js and modfn_preimage. */
    1534        6697 :     pari_sp av0 = avma;
    1535        6697 :     GEN F = double_eta_Fl(inv, p);
    1536        6697 :     pari_sp av = avma;
    1537        6697 :     ulong r1 = double_eta_power(inv, uel(rts, 1), p, pi);
    1538        6697 :     GEN r, f = Flx_double_eta_jpoly(F, r1, p, pi);
    1539        6697 :     if ((j = Flx_oneroot_pre(f, p, pi)) == p) pari_err_BUG("root_matrix");
    1540        6697 :     j = compute_L_isogenous_curve(L, n, ne, j, card, val, 0);
    1541        6697 :     set_avma(av);
    1542        6697 :     r1 = double_eta_power(inv, uel(surface_js, i), p, pi);
    1543        6697 :     f = Flx_double_eta_jpoly(F, r1, p, pi);
    1544        6697 :     r = Flx_roots_pre(f, p, pi);
    1545        6697 :     if (lg(r) != 3) pari_err_BUG("root_matrix");
    1546        6697 :     rev = (j != uel(r, 1)) && (j != uel(r, 2));
    1547        6697 :     set_avma(av0);
    1548             :   } else {
    1549             :     ulong j1pr, j1;
    1550       35102 :     j1pr = modfn_preimage(uel(rts, 1), p, pi, dinfo->inv);
    1551       35102 :     j1 = compute_L_isogenous_curve(L, n, ne, j1pr, card, val, 0);
    1552       35101 :     rev = j1 != modfn_preimage(uel(surface_js, i), p, pi, dinfo->inv);
    1553             :   }
    1554       41798 :   if (rev)
    1555       20110 :     carray_reverse_inplace(surface_js + 2, njs - 1);
    1556       41798 :   append_neighbours(rts, surface_js, njs, L, m, i);
    1557             : 
    1558      618785 :   for (i = 3; i <= njinvs; ++i) {
    1559      576988 :     update_Lsqr_cycle(cyc, dinfo);
    1560      577011 :     rts = gel(rt_mat, i);
    1561      577011 :     vecsmall_pick(rts, floor_js, cyc);
    1562      577012 :     append_neighbours(rts, surface_js, njs, L, m, i);
    1563             :   }
    1564       41797 :   set_avma(av); return rt_mat;
    1565             : }
    1566             : 
    1567             : INLINE void
    1568       44453 : interpolate_coeffs(GEN phi_modp, ulong p, GEN j_invs, GEN coeff_mat)
    1569             : {
    1570       44453 :   pari_sp av = avma;
    1571             :   long i;
    1572       44453 :   GEN pols = Flv_Flm_polint(j_invs, coeff_mat, p, 0);
    1573      963361 :   for (i = 1; i < lg(pols); ++i) {
    1574      918907 :     GEN pol = gel(pols, i);
    1575      918907 :     long k, maxk = lg(pol);
    1576    20672094 :     for (k = 2; k < maxk; ++k) coeff(phi_modp, k - 1, i) = pol[k];
    1577             :   }
    1578       44454 :   set_avma(av);
    1579       44456 : }
    1580             : 
    1581             : INLINE long
    1582      336717 : Flv_lastnonzero(GEN v)
    1583             : {
    1584             :   long i;
    1585    26648650 :   for (i = lg(v) - 1; i > 0; --i)
    1586    26647979 :     if (v[i]) break;
    1587      336717 :   return i;
    1588             : }
    1589             : 
    1590             : /* Assuming the matrix of coefficients in phi corresponds to polynomials
    1591             :  * phi_k^* satisfying Y^c phi_k^*(Y^s) for c in {0, 1, ..., s} satisfying
    1592             :  * c + Lk = L + 1 (mod s), change phi so that the coefficients are for the
    1593             :  * polynomials Y^c phi_k^*(Y^s) (s is the sparsity factor) */
    1594             : INLINE void
    1595        9971 : inflate_polys(GEN phi, long L, long s)
    1596             : {
    1597        9971 :   long k, deg = L + 1;
    1598             :   long maxr;
    1599        9971 :   maxr = nbrows(phi);
    1600      346700 :   for (k = 0; k <= deg; ) {
    1601      336729 :     long i, c = umodsu(L * (1 - k) + 1, s);
    1602             :     /* TODO: We actually know that the last nonzero element of gel(phi, k)
    1603             :      * can't be later than index n+1, where n is about (L + 1)/s. */
    1604      336719 :     ++k;
    1605     5483380 :     for (i = Flv_lastnonzero(gel(phi, k)); i > 0; --i) {
    1606     5146661 :       long r = c + (i - 1) * s + 1;
    1607     5146661 :       if (r > maxr) { coeff(phi, i, k) = 0; continue; }
    1608     5076165 :       if (r != i) {
    1609     4973575 :         coeff(phi, r, k) = coeff(phi, i, k);
    1610     4973575 :         coeff(phi, i, k) = 0;
    1611             :       }
    1612             :     }
    1613             :   }
    1614        9971 : }
    1615             : 
    1616             : INLINE void
    1617       39845 : Flv_powu_inplace_pre(GEN v, ulong n, ulong p, ulong pi)
    1618             : {
    1619             :   long i;
    1620      333363 :   for (i = 1; i < lg(v); ++i) v[i] = Fl_powu_pre(v[i], n, p, pi);
    1621       39845 : }
    1622             : 
    1623             : INLINE void
    1624        9971 : normalise_coeffs(GEN coeffs, GEN js, long L, long s, ulong p, ulong pi)
    1625             : {
    1626        9971 :   pari_sp av = avma;
    1627             :   long k;
    1628             :   GEN pows, modinv_js;
    1629             : 
    1630             :   /* NB: In fact it would be correct to return the coefficients "as is" when
    1631             :    * s = 1, but we make that an error anyway since this function should never
    1632             :    * be called with s = 1. */
    1633        9971 :   if (s <= 1) pari_err_BUG("normalise_coeffs");
    1634             : 
    1635             :   /* pows[i + 1] contains 1 / js[i + 1]^i for i = 0, ..., s - 1. */
    1636        9971 :   pows = cgetg(s + 1, t_VEC);
    1637        9971 :   gel(pows, 1) = const_vecsmall(lg(js) - 1, 1);
    1638        9971 :   modinv_js = Flv_inv_pre(js, p, pi);
    1639        9971 :   gel(pows, 2) = modinv_js;
    1640       37668 :   for (k = 3; k <= s; ++k) {
    1641       27697 :     gel(pows, k) = gcopy(modinv_js);
    1642       27697 :     Flv_powu_inplace_pre(gel(pows, k), k - 1, p, pi);
    1643             :   }
    1644             : 
    1645             :   /* For each column of coefficients coeffs[k] = [a0 .. an],
    1646             :    *   replace ai by ai / js[i]^c.
    1647             :    * Said in another way, normalise each row i of coeffs by
    1648             :    * dividing through by js[i - 1]^c (where c depends on i). */
    1649      346867 :   for (k = 1; k < lg(coeffs); ++k) {
    1650      336726 :     long i, c = umodsu(L * (1 - (k - 1)) + 1, s);
    1651      336725 :     GEN col = gel(coeffs, k), C = gel(pows, c + 1);
    1652     5845580 :     for (i = 1; i < lg(col); ++i)
    1653     5508684 :       col[i] = Fl_mul_pre(col[i], C[i], p, pi);
    1654             :   }
    1655       10141 :   set_avma(av);
    1656        9971 : }
    1657             : 
    1658             : INLINE void
    1659        6697 : double_eta_initial_js(
    1660             :   ulong *x0, ulong *x0pr, ulong j0, ulong j0pr, norm_eqn_t ne,
    1661             :   long inv, ulong L, ulong n, ulong card, ulong val)
    1662             : {
    1663        6697 :   pari_sp av0 = avma;
    1664        6697 :   ulong p = ne->p, pi = ne->pi, s2 = ne->s2;
    1665        6697 :   GEN F = double_eta_Fl(inv, p);
    1666        6697 :   pari_sp av = avma;
    1667             :   ulong j1pr, j1, r, t;
    1668             :   GEN f, g;
    1669             : 
    1670        6697 :   *x0pr = modinv_double_eta_from_j(F, inv, j0pr, p, pi, s2);
    1671        6697 :   t = double_eta_power(inv, *x0pr, p, pi);
    1672        6697 :   f = Flx_div_by_X_x(Flx_double_eta_jpoly(F, t, p, pi), j0pr, p, &r);
    1673        6697 :   if (r) pari_err_BUG("double_eta_initial_js");
    1674        6697 :   j1pr = Flx_deg1_root(f, p);
    1675        6697 :   set_avma(av);
    1676             : 
    1677        6697 :   j1 = compute_L_isogenous_curve(L, n, ne, j1pr, card, val, 0);
    1678        6697 :   f = Flx_double_eta_xpoly(F, j0, p, pi);
    1679        6697 :   g = Flx_double_eta_xpoly(F, j1, p, pi);
    1680             :   /* x0 is the unique common root of f and g */
    1681        6697 :   *x0 = Flx_deg1_root(Flx_gcd(f, g, p), p);
    1682        6697 :   set_avma(av0);
    1683             : 
    1684        6697 :   if ( ! double_eta_root(inv, x0, *x0, p, pi, s2))
    1685           0 :     pari_err_BUG("double_eta_initial_js");
    1686        6696 : }
    1687             : 
    1688             : /* This is Sutherland 2012, Algorithm 2.1, p16. */
    1689             : static GEN
    1690       41783 : polmodular_split_p_Flm(ulong L, GEN hilb, GEN factu, norm_eqn_t ne, GEN db,
    1691             :   GEN G_surface, GEN G_floor, const disc_info *dinfo)
    1692             : {
    1693             :   ulong j0, j0_rt, j0pr, j0pr_rt;
    1694       41783 :   ulong n, card, val, p = ne->p, pi = ne->pi;
    1695       41783 :   long inv = dinfo->inv, s = modinv_sparse_factor(inv);
    1696       41782 :   long nj_selected = ceil((L + 1)/(double)s) + 1;
    1697             :   GEN surface_js, floor_js, rts, phi_modp, jdb, fdb;
    1698       41782 :   long switched_signs = 0;
    1699             : 
    1700       41782 :   jdb = polmodular_db_for_inv(db, INV_J);
    1701       41785 :   fdb = polmodular_db_for_inv(db, inv);
    1702             : 
    1703             :   /* Precomputation */
    1704       41785 :   card = p + 1 - ne->t;
    1705       41785 :   val = u_lvalrem(card, L, &n); /* n = card / L^{v_L(card)} */
    1706             : 
    1707       41786 :   j0 = oneroot_of_classpoly(hilb, factu, ne, jdb);
    1708       41796 :   j0pr = compute_L_isogenous_curve(L, n, ne, j0, card, val, 1);
    1709       41796 :   if (modinv_is_double_eta(inv)) {
    1710        6697 :     double_eta_initial_js(&j0_rt, &j0pr_rt, j0, j0pr, ne, inv, L, n, card, val);
    1711             :   } else {
    1712       35099 :     j0_rt = modfn_root(j0, ne, inv);
    1713       35098 :     j0pr_rt = modfn_root(j0pr, ne, inv);
    1714             :   }
    1715       41792 :   surface_js = enum_volcano_surface(ne, j0_rt, fdb, G_surface);
    1716       41797 :   floor_js = enum_volcano_floor(L, ne, j0pr_rt, fdb, G_floor);
    1717       41798 :   rts = root_matrix(L, dinfo, nj_selected, surface_js, floor_js,
    1718             :                     n, card, val, ne);
    1719        2329 :   do {
    1720       44126 :     pari_sp btop = avma;
    1721             :     long i;
    1722             :     GEN coeffs, surf;
    1723             : 
    1724       44126 :     coeffs = roots_to_coeffs(rts, p, L);
    1725       44118 :     surf = vecsmall_shorten(surface_js, nj_selected);
    1726       44120 :     if (s > 1) {
    1727        9971 :       normalise_coeffs(coeffs, surf, L, s, p, pi);
    1728        9971 :       Flv_powu_inplace_pre(surf, s, p, pi);
    1729             :     }
    1730       44120 :     phi_modp = zero_Flm_copy(L + 2, L + 2);
    1731       44123 :     interpolate_coeffs(phi_modp, p, surf, coeffs);
    1732       44127 :     if (s > 1) inflate_polys(phi_modp, L, s);
    1733             : 
    1734             :     /* TODO: Calculate just this coefficient of X^L Y^L, so we can do this
    1735             :      * test, then calculate the other coefficients; at the moment we are
    1736             :      * sometimes doing all the roots-to-coeffs, normalisation and interpolation
    1737             :      * work twice. */
    1738       44127 :     if (ucoeff(phi_modp, L + 1, L + 1) == p - 1) break;
    1739             : 
    1740        2329 :     if (switched_signs) pari_err_BUG("polmodular_split_p_Flm");
    1741             : 
    1742        2329 :     set_avma(btop);
    1743       27893 :     for (i = 1; i < lg(rts); ++i) {
    1744       25564 :       surface_js[i] = Fl_neg(surface_js[i], p);
    1745       25564 :       coeff(rts, L, i) = Fl_neg(coeff(rts, L, i), p);
    1746       25564 :       coeff(rts, L + 1, i) = Fl_neg(coeff(rts, L + 1, i), p);
    1747             :     }
    1748        2329 :     switched_signs = 1;
    1749             :   } while (1);
    1750       41798 :   dbg_printf(4)("  Phi_%lu(X, Y) (mod %lu) = %Ps\n", L, p, phi_modp);
    1751             : 
    1752       41798 :   return phi_modp;
    1753             : }
    1754             : 
    1755             : INLINE void
    1756        2464 : Flv_deriv_pre_inplace(GEN v, long deg, ulong p, ulong pi)
    1757             : {
    1758        2464 :   long i, ln = lg(v), d = deg % p;
    1759       57202 :   for (i = ln - 1; i > 1; --i, --d) v[i] = Fl_mul_pre(v[i - 1], d, p, pi);
    1760        2464 :   v[1] = 0;
    1761        2464 : }
    1762             : 
    1763             : INLINE GEN
    1764        2674 : eval_modpoly_modp(GEN Tp, GEN j_powers, ulong p, ulong pi, int compute_derivs)
    1765             : {
    1766        2674 :   long L = lg(j_powers) - 3;
    1767        2674 :   GEN j_pows_p = ZV_to_Flv(j_powers, p);
    1768        2674 :   GEN tmp = cgetg(2 + 2 * compute_derivs, t_VEC);
    1769             :   /* We wrap the result in this t_VEC Tp to trick the
    1770             :    * ZM_*_CRT() functions into thinking it's a matrix. */
    1771        2673 :   gel(tmp, 1) = Flm_Flc_mul_pre(Tp, j_pows_p, p, pi);
    1772        2674 :   if (compute_derivs) {
    1773        1232 :     Flv_deriv_pre_inplace(j_pows_p, L + 1, p, pi);
    1774        1232 :     gel(tmp, 2) = Flm_Flc_mul_pre(Tp, j_pows_p, p, pi);
    1775        1232 :     Flv_deriv_pre_inplace(j_pows_p, L + 1, p, pi);
    1776        1232 :     gel(tmp, 3) = Flm_Flc_mul_pre(Tp, j_pows_p, p, pi);
    1777             :   }
    1778        2674 :   return tmp;
    1779             : }
    1780             : 
    1781             : /* Parallel interface */
    1782             : GEN
    1783       41791 : polmodular_worker(GEN tp, ulong L, GEN hilb, GEN factu, GEN vne, GEN vinfo,
    1784             :                   long derivs, GEN j_powers, GEN G_surface, GEN G_floor,
    1785             :                   GEN fdb)
    1786             : {
    1787       41791 :   pari_sp av = avma;
    1788             :   norm_eqn_t ne;
    1789       41791 :   long D = vne[1], u = vne[2];
    1790       41791 :   ulong vL, t = tp[1], p = tp[2];
    1791             :   GEN Tp;
    1792             : 
    1793       41791 :   if (! uissquareall((4 * p - t * t) / -D, &vL))
    1794           0 :     pari_err_BUG("polmodular_worker");
    1795       41793 :   norm_eqn_set(ne, D, t, u, vL, NULL, p); /* L | vL */
    1796       41780 :   Tp = polmodular_split_p_Flm(L, hilb, factu, ne, fdb,
    1797             :                               G_surface, G_floor, (const disc_info*)vinfo);
    1798       41798 :   if (!isintzero(j_powers))
    1799        2674 :     Tp = eval_modpoly_modp(Tp, j_powers, ne->p, ne->pi, derivs);
    1800       41798 :   return gc_upto(av, Tp);
    1801             : }
    1802             : 
    1803             : static GEN
    1804       24806 : sympol_to_ZM(GEN phi, long L)
    1805             : {
    1806       24806 :   pari_sp av = avma;
    1807       24806 :   GEN res = zeromatcopy(L + 2, L + 2);
    1808       24806 :   long i, j, c = 1;
    1809      108531 :   for (i = 1; i <= L + 1; ++i)
    1810      277410 :     for (j = 1; j <= i; ++j, ++c)
    1811      193685 :       gcoeff(res, i, j) = gcoeff(res, j, i) = gel(phi, c);
    1812       24806 :   gcoeff(res, L + 2, 1) = gcoeff(res, 1, L + 2) = gen_1;
    1813       24806 :   return gc_GEN(av, res);
    1814             : }
    1815             : 
    1816             : static GEN polmodular_small_ZM(long L, long inv, GEN *db);
    1817             : 
    1818             : INLINE long
    1819       28158 : modinv_max_internal_level(long inv)
    1820             : {
    1821       28158 :   switch (inv) {
    1822       25355 :     case INV_J: return 5;
    1823         252 :     case INV_G2: return 2;
    1824         443 :     case INV_F:
    1825             :     case INV_F2:
    1826             :     case INV_F4:
    1827         443 :     case INV_F8: return 5;
    1828         210 :     case INV_W2W5:
    1829         210 :     case INV_W2W5E2: return 7;
    1830         497 :     case INV_W2W3:
    1831             :     case INV_W2W3E2:
    1832             :     case INV_W3W3:
    1833         497 :     case INV_W3W7:  return 5;
    1834          63 :     case INV_W3W3E2:return 2;
    1835         680 :     case INV_F3:
    1836             :     case INV_W2W7:
    1837             :     case INV_W2W7E2:
    1838         680 :     case INV_W2W13: return 3;
    1839         658 :     case INV_W3W5:
    1840             :     case INV_W5W7:
    1841             :     case INV_W3W13:
    1842             :     case INV_ATKIN3:
    1843             :     case INV_ATKIN5:
    1844             :     case INV_ATKIN7:
    1845             :     case INV_ATKIN11:
    1846             :     case INV_ATKIN13:
    1847             :     case INV_ATKIN17:
    1848             :     case INV_ATKIN19:
    1849             :     case INV_ATKIN23:
    1850         658 :     case INV_ATKIN29: return 2;
    1851             :   }
    1852             :   pari_err_BUG("modinv_max_internal_level"); return LONG_MAX;/*LCOV_EXCL_LINE*/
    1853             : }
    1854             : static void
    1855          24 : db_add_levels(GEN *db, GEN P, long inv)
    1856          24 : { polmodular_db_add_levels(db, zv_to_longptr(P), lg(P)-1, inv); }
    1857             : 
    1858             : GEN
    1859       28039 : polmodular0_ZM(long L, long inv, GEN J, GEN Q, int compute_derivs, GEN *db)
    1860             : {
    1861       28039 :   pari_sp ltop = avma;
    1862       28039 :   long k, d, Dcnt, nprimes = 0;
    1863             :   GEN modpoly, plist, tp, j_powers;
    1864             :   disc_info Ds[MODPOLY_MAX_DCNT];
    1865       28039 :   long lvl = modinv_level(inv);
    1866       28039 :   if (ugcd(L, lvl) != 1)
    1867           7 :     pari_err_DOMAIN("polmodular0_ZM", "invariant",
    1868             :                     "incompatible with", stoi(L), stoi(lvl));
    1869             : 
    1870       28032 :   dbg_printf(1)("Calculating modular polynomial of level %lu for invariant %d\n", L, inv);
    1871       28032 :   if (L <= modinv_max_internal_level(inv)) return polmodular_small_ZM(L,inv,db);
    1872             : 
    1873        3086 :   Dcnt = discriminant_with_classno_at_least(Ds, L, inv, Q, USE_SPARSE_FACTOR);
    1874        6190 :   for (d = 0; d < Dcnt; d++) nprimes += Ds[d].nprimes;
    1875        3086 :   modpoly = cgetg(nprimes+1, t_VEC);
    1876        3086 :   plist = cgetg(nprimes+1, t_VECSMALL);
    1877        3086 :   tp = mkvec(mkvecsmall2(0,0));
    1878        3086 :   j_powers = gen_0;
    1879        3086 :   if (J) {
    1880          63 :     compute_derivs = !!compute_derivs;
    1881          63 :     j_powers = Fp_powers(J, L+1, Q);
    1882             :   }
    1883        6190 :   for (d = 0, k = 1; d < Dcnt; d++)
    1884             :   {
    1885        3104 :     disc_info *dinfo = &Ds[d];
    1886             :     struct pari_mt pt;
    1887        3104 :     const long D = dinfo->D1, DK = dinfo->D0;
    1888        3104 :     const ulong cond = usqrt(D / DK);
    1889        3104 :     long i, pending = 0;
    1890        3104 :     GEN worker, hilb, factu = factoru(cond);
    1891             : 
    1892        3104 :     polmodular_db_add_level(db, dinfo->L0, inv);
    1893        3104 :     if (dinfo->L1) polmodular_db_add_level(db, dinfo->L1, inv);
    1894        3104 :     dbg_printf(1)("Selected discriminant D = %ld = %ld^2 * %ld.\n", D,cond,DK);
    1895        3104 :     hilb = polclass0(DK, INV_J, 0, db);
    1896        3104 :     if (cond > 1) db_add_levels(db, gel(factu,1), INV_J);
    1897        3104 :     dbg_printf(1)("D = %ld, L0 = %lu, L1 = %lu, ", dinfo->D1, dinfo->L0, dinfo->L1);
    1898        3104 :     dbg_printf(1)("n1 = %lu, n2 = %lu, dl1 = %lu, dl2_0 = %lu, dl2_1 = %lu\n",
    1899             :           dinfo->n1, dinfo->n2, dinfo->dl1, dinfo->dl2_0, dinfo->dl2_1);
    1900        3104 :     dbg_printf(0)("Calculating modular polynomial of level %lu:", L);
    1901             : 
    1902        3104 :     worker = snm_closure(is_entry("_polmodular_worker"),
    1903             :                          mkvecn(10, utoi(L), hilb, factu, mkvecsmall2(D, cond),
    1904             :                                    (GEN)dinfo, stoi(compute_derivs), j_powers,
    1905             :                                    make_pcp_surface(dinfo),
    1906             :                                    make_pcp_floor(dinfo), *db));
    1907        3104 :     mt_queue_start_lim(&pt, worker, dinfo->nprimes);
    1908       49049 :     for (i = 0; i < dinfo->nprimes || pending; i++)
    1909             :     {
    1910             :       long workid;
    1911             :       GEN done;
    1912       45945 :       if (i < dinfo->nprimes)
    1913             :       {
    1914       41799 :         mael(tp, 1, 1) = dinfo->traces[i];
    1915       41799 :         mael(tp, 1, 2) = dinfo->primes[i];
    1916             :       }
    1917       45945 :       mt_queue_submit(&pt, i, i < dinfo->nprimes? tp: NULL);
    1918       45945 :       done = mt_queue_get(&pt, &workid, &pending);
    1919       45945 :       if (done)
    1920             :       {
    1921       41799 :         plist[k] = dinfo->primes[workid];
    1922       41799 :         gel(modpoly, k) = done; k++;
    1923       41799 :         dbg_printf(0)(" %ld%%", k*100/nprimes);
    1924             :       }
    1925             :     }
    1926        3104 :     dbg_printf(0)(" done\n");
    1927        3104 :     mt_queue_end(&pt);
    1928        3104 :     killblock((GEN)dinfo->primes);
    1929             :   }
    1930        3086 :   modpoly = nmV_chinese_center(modpoly, plist, NULL);
    1931        3086 :   if (J) modpoly = FpM_red(modpoly, Q);
    1932        3086 :   return gc_upto(ltop, modpoly);
    1933             : }
    1934             : 
    1935             : GEN
    1936       19266 : polmodular_ZM(long L, long inv)
    1937             : {
    1938             :   GEN db, Phi;
    1939             : 
    1940       19266 :   if (L < 2)
    1941           7 :     pari_err_DOMAIN("polmodular_ZM", "L", "<", gen_2, stoi(L));
    1942             : 
    1943             :   /* TODO: Handle nonprime L. Algorithm 1.1 and Corollary 3.4 in Sutherland,
    1944             :    * "Class polynomials for nonholomorphic modular functions" */
    1945       19259 :   if (! uisprime(L)) pari_err_IMPL("composite level");
    1946             : 
    1947       19252 :   db = polmodular_db_init(inv);
    1948       19252 :   Phi = polmodular0_ZM(L, inv, NULL, NULL, 0, &db);
    1949       19245 :   gunclone_deep(db); return Phi;
    1950             : }
    1951             : 
    1952             : GEN
    1953       19182 : polmodular_ZXX(long L, long inv, long vx, long vy)
    1954             : {
    1955       19182 :   pari_sp av = avma;
    1956       19182 :   GEN phi = polmodular_ZM(L, inv);
    1957             : 
    1958       19161 :   if (vx < 0) vx = 0;
    1959       19161 :   if (vy < 0) vy = 1;
    1960       19161 :   if (varncmp(vx, vy) >= 0)
    1961          14 :     pari_err_PRIORITY("polmodular_ZXX", pol_x(vx), "<=", vy);
    1962       19147 :   return gc_GEN(av, RgM_to_RgXX(phi, vx, vy));
    1963             : }
    1964             : 
    1965             : INLINE GEN
    1966          56 : FpV_deriv(GEN v, long deg, GEN P)
    1967             : {
    1968          56 :   long i, ln = lg(v);
    1969          56 :   GEN dv = cgetg(ln, t_VEC);
    1970         392 :   for (i = ln-1; i > 1; i--, deg--) gel(dv, i) = Fp_mulu(gel(v, i-1), deg, P);
    1971          56 :   gel(dv, 1) = gen_0; return dv;
    1972             : }
    1973             : 
    1974             : GEN
    1975         126 : Fp_polmodular_evalx(long L, long inv, GEN J, GEN P, long v, int compute_derivs)
    1976             : {
    1977         126 :   pari_sp av = avma;
    1978             :   GEN db, phi;
    1979             : 
    1980         126 :   if (L <= modinv_max_internal_level(inv)) {
    1981             :     GEN tmp;
    1982          63 :     GEN phi = RgM_to_FpM(polmodular_ZM(L, inv), P);
    1983          63 :     GEN j_powers = Fp_powers(J, L + 1, P);
    1984          63 :     GEN modpol = RgV_to_RgX(FpM_FpC_mul(phi, j_powers, P), v);
    1985          63 :     if (compute_derivs) {
    1986          28 :       tmp = cgetg(4, t_VEC);
    1987          28 :       gel(tmp, 1) = modpol;
    1988          28 :       j_powers = FpV_deriv(j_powers, L + 1, P);
    1989          28 :       gel(tmp, 2) = RgV_to_RgX(FpM_FpC_mul(phi, j_powers, P), v);
    1990          28 :       j_powers = FpV_deriv(j_powers, L + 1, P);
    1991          28 :       gel(tmp, 3) = RgV_to_RgX(FpM_FpC_mul(phi, j_powers, P), v);
    1992             :     } else
    1993          35 :       tmp = modpol;
    1994          63 :     return gc_GEN(av, tmp);
    1995             :   }
    1996             : 
    1997          63 :   db = polmodular_db_init(inv);
    1998          63 :   phi = polmodular0_ZM(L, inv, J, P, compute_derivs, &db);
    1999          63 :   phi = RgM_to_RgXV(phi, v);
    2000          63 :   gunclone_deep(db);
    2001          63 :   return gc_GEN(av, compute_derivs? phi: gel(phi, 1));
    2002             : }
    2003             : 
    2004             : GEN
    2005         651 : polmodular(long L, long inv, GEN x, long v, long compute_derivs)
    2006             : {
    2007         651 :   pari_sp av = avma;
    2008             :   long tx;
    2009         651 :   GEN J = NULL, P = NULL, res = NULL, one = NULL;
    2010             : 
    2011         651 :   check_modinv(inv);
    2012         644 :   if (!x || gequalX(x)) {
    2013         504 :     long xv = 0;
    2014         504 :     if (x) xv = varn(x);
    2015         504 :     if (compute_derivs) pari_err_FLAG("polmodular");
    2016         497 :     return polmodular_ZXX(L, inv, xv, v);
    2017             :   }
    2018             : 
    2019         140 :   tx = typ(x);
    2020         140 :   if (tx == t_INTMOD) {
    2021          63 :     J = gel(x, 2);
    2022          63 :     P = gel(x, 1);
    2023          63 :     one = mkintmod(gen_1, P);
    2024          77 :   } else if (tx == t_FFELT) {
    2025          70 :     J = FF_to_FpXQ_i(x);
    2026          70 :     if (degpol(J) > 0)
    2027           7 :       pari_err_DOMAIN("polmodular", "x", "not in prime subfield ", gen_0, x);
    2028          63 :     J = constant_coeff(J);
    2029          63 :     P = FF_p_i(x);
    2030          63 :     one = FF_1(x);
    2031             :   } else
    2032           7 :     pari_err_TYPE("polmodular", x);
    2033             : 
    2034         126 :   if (v < 0) v = 1;
    2035         126 :   res = Fp_polmodular_evalx(L, inv, J, P, v, compute_derivs);
    2036         126 :   return gc_upto(av, gmul(res, one));
    2037             : }
    2038             : 
    2039             : /* SECTION: Modular polynomials of level <= MAX_INTERNAL_MODPOLY_LEVEL. */
    2040             : 
    2041             : /* These functions return a vector of coefficients of classical modular
    2042             :  * polynomials Phi_L(X,Y) of small level L.  The number of such coefficients is
    2043             :  * (L+1)(L+2)/2 since Phi is symmetric. We omit the common coefficient of
    2044             :  * X^{L+1} and Y^{L+1} since it is always 1. Use sympol_to_ZM() to get the
    2045             :  * corresponding desymmetrised matrix of coefficients */
    2046             : 
    2047             : /*  Phi2, the modular polynomial of level 2:
    2048             :  *
    2049             :  *  X^3 + X^2 * (-Y^2 + 1488*Y - 162000)
    2050             :  *      + X * (1488*Y^2 + 40773375*Y + 8748000000)
    2051             :  *      + Y^3 - 162000*Y^2 + 8748000000*Y - 157464000000000
    2052             :  *
    2053             :  *  [[3, 0, 1],
    2054             :  *   [2, 2, -1],
    2055             :  *   [2, 1, 1488],
    2056             :  *   [2, 0, -162000],
    2057             :  *   [1, 1, 40773375],
    2058             :  *   [1, 0, 8748000000],
    2059             :  *   [0, 0, -157464000000000]], */
    2060             : static GEN
    2061       20015 : phi2_ZV(void)
    2062             : {
    2063       20015 :   GEN phi2 = cgetg(7, t_VEC);
    2064       20015 :   gel(phi2, 1) = uu32toi(36662, 1908994048);
    2065       20015 :   setsigne(gel(phi2, 1), -1);
    2066       20015 :   gel(phi2, 2) = uu32toi(2, 158065408);
    2067       20015 :   gel(phi2, 3) = stoi(40773375);
    2068       20015 :   gel(phi2, 4) = stoi(-162000);
    2069       20015 :   gel(phi2, 5) = stoi(1488);
    2070       20015 :   gel(phi2, 6) = gen_m1;
    2071       20015 :   return phi2;
    2072             : }
    2073             : 
    2074             : /* L = 3
    2075             :  *
    2076             :  * [4, 0, 1],
    2077             :  * [3, 3, -1],
    2078             :  * [3, 2, 2232],
    2079             :  * [3, 1, -1069956],
    2080             :  * [3, 0, 36864000],
    2081             :  * [2, 2, 2587918086],
    2082             :  * [2, 1, 8900222976000],
    2083             :  * [2, 0, 452984832000000],
    2084             :  * [1, 1, -770845966336000000],
    2085             :  * [1, 0, 1855425871872000000000]
    2086             :  * [0, 0, 0]
    2087             :  *
    2088             :  * 1855425871872000000000 = 2^32 * (100 * 2^32 + 2503270400) */
    2089             : static GEN
    2090        1910 : phi3_ZV(void)
    2091             : {
    2092        1910 :   GEN phi3 = cgetg(11, t_VEC);
    2093        1910 :   pari_sp av = avma;
    2094        1910 :   gel(phi3, 1) = gen_0;
    2095        1910 :   gel(phi3, 2) = gc_upto(av, shifti(uu32toi(100, 2503270400UL), 32));
    2096        1910 :   gel(phi3, 3) = uu32toi(179476562, 2147483648UL);
    2097        1910 :   setsigne(gel(phi3, 3), -1);
    2098        1910 :   gel(phi3, 4) = uu32toi(105468, 3221225472UL);
    2099        1910 :   gel(phi3, 5) = uu32toi(2072, 1050738688);
    2100        1910 :   gel(phi3, 6) = utoi(2587918086UL);
    2101        1910 :   gel(phi3, 7) = stoi(36864000);
    2102        1910 :   gel(phi3, 8) = stoi(-1069956);
    2103        1910 :   gel(phi3, 9) = stoi(2232);
    2104        1910 :   gel(phi3, 10) = gen_m1;
    2105        1910 :   return phi3;
    2106             : }
    2107             : 
    2108             : static GEN
    2109        1880 : phi5_ZV(void)
    2110             : {
    2111        1880 :   GEN phi5 = cgetg(22, t_VEC);
    2112        1880 :   gel(phi5, 1) = mkintn(5, 0x18c2cc9cUL, 0x484382b2UL, 0xdc000000UL, 0x0UL, 0x0UL);
    2113        1880 :   gel(phi5, 2) = mkintn(5, 0x2638fUL, 0x2ff02690UL, 0x68026000UL, 0x0UL, 0x0UL);
    2114        1880 :   gel(phi5, 3) = mkintn(5, 0x308UL, 0xac9d9a4UL, 0xe0fdab12UL, 0xc0000000UL, 0x0UL);
    2115        1880 :   setsigne(gel(phi5, 3), -1);
    2116        1880 :   gel(phi5, 4) = mkintn(5, 0x13UL, 0xaae09f9dUL, 0x1b5ef872UL, 0x30000000UL, 0x0UL);
    2117        1880 :   gel(phi5, 5) = mkintn(4, 0x1b802fa9UL, 0x77ba0653UL, 0xd2f78000UL, 0x0UL);
    2118        1880 :   gel(phi5, 6) = mkintn(4, 0xfbfdUL, 0x278e4756UL, 0xdf08a7c4UL, 0x40000000UL);
    2119        1880 :   gel(phi5, 7) = mkintn(4, 0x35f922UL, 0x62ccea6fUL, 0x153d0000UL, 0x0UL);
    2120        1880 :   gel(phi5, 8) = mkintn(4, 0x97dUL, 0x29203fafUL, 0xc3036909UL, 0x80000000UL);
    2121        1880 :   setsigne(gel(phi5, 8), -1);
    2122        1880 :   gel(phi5, 9) = mkintn(3, 0x56e9e892UL, 0xd7781867UL, 0xf2ea0000UL);
    2123        1880 :   gel(phi5, 10) = mkintn(3, 0x5d6dUL, 0xe0a58f4eUL, 0x9ee68c14UL);
    2124        1880 :   setsigne(gel(phi5, 10), -1);
    2125        1880 :   gel(phi5, 11) = mkintn(3, 0x1100dUL, 0x85cea769UL, 0x40000000UL);
    2126        1880 :   gel(phi5, 12) = mkintn(3, 0x1b38UL, 0x43cf461fUL, 0x3a900000UL);
    2127        1880 :   gel(phi5, 13) = mkintn(3, 0x14UL, 0xc45a616eUL, 0x4801680fUL);
    2128        1880 :   gel(phi5, 14) = uu32toi(0x17f4350UL, 0x493ca3e0UL);
    2129        1880 :   gel(phi5, 15) = uu32toi(0x183UL, 0xe54ce1f8UL);
    2130        1880 :   gel(phi5, 16) = uu32toi(0x1c9UL, 0x18860000UL);
    2131        1880 :   gel(phi5, 17) = uu32toi(0x39UL, 0x6f7a2206UL);
    2132        1880 :   setsigne(gel(phi5, 17), -1);
    2133        1880 :   gel(phi5, 18) = stoi(2028551200);
    2134        1880 :   gel(phi5, 19) = stoi(-4550940);
    2135        1880 :   gel(phi5, 20) = stoi(3720);
    2136        1880 :   gel(phi5, 21) = gen_m1;
    2137        1880 :   return phi5;
    2138             : }
    2139             : 
    2140             : static GEN
    2141         189 : phi5_f_ZV(void)
    2142             : {
    2143         189 :   GEN phi = zerovec(21);
    2144         189 :   gel(phi, 3) = stoi(4);
    2145         189 :   gel(phi, 21) = gen_m1;
    2146         189 :   return phi;
    2147             : }
    2148             : 
    2149             : static GEN
    2150          14 : phi3_f3_ZV(void)
    2151             : {
    2152          14 :   GEN phi = zerovec(10);
    2153          14 :   gel(phi, 3) = stoi(8);
    2154          14 :   gel(phi, 10) = gen_m1;
    2155          14 :   return phi;
    2156             : }
    2157             : 
    2158             : static GEN
    2159          98 : phi2_g2_ZV(void)
    2160          98 : { return mkvec6s(-54000,0,495,0,0,-1); }
    2161             : 
    2162             : static GEN
    2163          56 : phi5_w2w3_ZV(void)
    2164             : {
    2165          56 :   GEN phi = zerovec(21);
    2166          56 :   gel(phi, 3) = gen_m1;
    2167          56 :   gel(phi, 10) = stoi(5);
    2168          56 :   gel(phi, 21) = gen_m1;
    2169          56 :   return phi;
    2170             : }
    2171             : 
    2172             : static GEN
    2173          91 : phi7_w2w5_ZV(void)
    2174             : {
    2175          91 :   GEN phi = zerovec(36);
    2176          91 :   gel(phi, 3) = gen_m1;
    2177          91 :   gel(phi, 15) = stoi(56);
    2178          91 :   gel(phi, 19) = stoi(42);
    2179          91 :   gel(phi, 24) = stoi(21);
    2180          91 :   gel(phi, 30) = stoi(7);
    2181          91 :   gel(phi, 36) = gen_m1;
    2182          91 :   return phi;
    2183             : }
    2184             : 
    2185             : static GEN
    2186          63 : phi5_w3w3_ZV(void)
    2187             : {
    2188          63 :   GEN phi = zerovec(21);
    2189          63 :   gel(phi, 3) = stoi(9);
    2190          63 :   gel(phi, 6) = stoi(-15);
    2191          63 :   gel(phi, 15) = stoi(5);
    2192          63 :   gel(phi, 21) = gen_m1;
    2193          63 :   return phi;
    2194             : }
    2195             : 
    2196             : static GEN
    2197         182 : phi3_w2w7_ZV(void)
    2198             : {
    2199         182 :   GEN phi = zerovec(10);
    2200         182 :   gel(phi, 3) = gen_m1;
    2201         182 :   gel(phi, 6) = stoi(3);
    2202         182 :   gel(phi, 10) = gen_m1;
    2203         182 :   return phi;
    2204             : }
    2205             : 
    2206             : static GEN
    2207          35 : phi2_w3w5_ZV(void)
    2208          35 : { return mkvec6s(0,0,1,0,0,-1); }
    2209             : 
    2210             : static GEN
    2211          49 : phi5_w3w7_ZV(void)
    2212             : {
    2213          49 :   GEN phi = zerovec(21);
    2214          49 :   gel(phi, 3) = gen_m1;
    2215          49 :   gel(phi, 6) = stoi(10);
    2216          49 :   gel(phi, 8) = stoi(5);
    2217          49 :   gel(phi, 10) = stoi(35);
    2218          49 :   gel(phi, 13) = stoi(20);
    2219          49 :   gel(phi, 15) = stoi(10);
    2220          49 :   gel(phi, 17) = stoi(5);
    2221          49 :   gel(phi, 19) = stoi(5);
    2222          49 :   gel(phi, 21) = gen_m1;
    2223          49 :   return phi;
    2224             : }
    2225             : 
    2226             : static GEN
    2227          35 : phi3_w2w13_ZV(void)
    2228             : {
    2229          35 :   GEN phi = zerovec(10);
    2230          35 :   gel(phi, 3) = gen_m1;
    2231          35 :   gel(phi, 6) = stoi(3);
    2232          35 :   gel(phi, 8) = stoi(3);
    2233          35 :   gel(phi, 10) = gen_m1;
    2234          35 :   return phi;
    2235             : }
    2236             : 
    2237             : static GEN
    2238          21 : phi2_w3w3e2_ZV(void)
    2239          21 : { return mkvec6s(0,0,3,0,0,-1); }
    2240             : 
    2241             : static GEN
    2242          70 : phi2_w5w7_ZV(void)
    2243          70 : { return mkvec6s(0,0,1,0,2,-1); }
    2244             : 
    2245             : static GEN
    2246          14 : phi2_w3w13_ZV(void)
    2247          14 : { return mkvec6s(0,0,-1,0,2,-1); }
    2248             : 
    2249             : static GEN
    2250           7 : phi2_atkin3_ZV(void)
    2251           7 : { return mkvec6s(28166076,741474,17343,1566,0,-1); }
    2252             : 
    2253             : static GEN
    2254          14 : phi2_atkin5_ZV(void)
    2255          14 : { return mkvec6s(323456,24244,1519,268,0,-1); }
    2256             : 
    2257             : static GEN
    2258           7 : phi2_atkin7_ZV(void)
    2259           7 : { return mkvec6s(27100,3810,407,102,0,-1); }
    2260             : 
    2261             : static GEN
    2262           0 : phi2_atkin11_ZV(void)
    2263           0 : { return mkvec6s(1600,470,91,34,0,-1); }
    2264             : 
    2265             : static GEN
    2266           0 : phi2_atkin13_ZV(void)
    2267           0 : { return mkvec6s(656,240,55,24,0,-1); }
    2268             : 
    2269             : static GEN
    2270           0 : phi2_atkin17_ZV(void)
    2271           0 : { return mkvec6s(156,86,27,14,0,-1); }
    2272             : 
    2273             : static GEN
    2274          14 : phi2_atkin19_ZV(void)
    2275          14 : { return mkvec6s(100,60,19,12,0,-1); }
    2276             : 
    2277             : static GEN
    2278          21 : phi2_atkin23_ZV(void)
    2279          21 : { return mkvec6s(2,6,9,4,2,-1); }
    2280             : 
    2281             : static GEN
    2282          21 : phi2_atkin29_ZV(void)
    2283          21 : { return mkvec6s(0,0,3,2,2,-1); }
    2284             : 
    2285             : INLINE long
    2286         140 : modinv_parent(long inv)
    2287             : {
    2288         140 :   switch (inv) {
    2289          42 :     case INV_F2:
    2290             :     case INV_F4:
    2291          42 :     case INV_F8:     return INV_F;
    2292          14 :     case INV_W2W3E2: return INV_W2W3;
    2293          21 :     case INV_W2W5E2: return INV_W2W5;
    2294          63 :     case INV_W2W7E2: return INV_W2W7;
    2295           0 :     case INV_W3W3E2: return INV_W3W3;
    2296             :     default: pari_err_BUG("modinv_parent"); return -1;/*LCOV_EXCL_LINE*/
    2297             :   }
    2298             : }
    2299             : 
    2300             : /* TODO: Think of a better name than "parent power"; sheesh. */
    2301             : INLINE long
    2302         140 : modinv_parent_power(long inv)
    2303             : {
    2304         140 :   switch (inv) {
    2305          14 :     case INV_F4: return 4;
    2306          14 :     case INV_F8: return 8;
    2307         112 :     case INV_F2:
    2308             :     case INV_W2W3E2:
    2309             :     case INV_W2W5E2:
    2310             :     case INV_W2W7E2:
    2311         112 :     case INV_W3W3E2: return 2;
    2312             :     default: pari_err_BUG("modinv_parent_power"); return -1;/*LCOV_EXCL_LINE*/
    2313             :   }
    2314             : }
    2315             : 
    2316             : static GEN
    2317         140 : polmodular0_powerup_ZM(long L, long inv, GEN *db)
    2318             : {
    2319         140 :   pari_sp ltop = avma, av;
    2320             :   long s, D, nprimes, N;
    2321             :   GEN mp, pol, P, H;
    2322         140 :   long parent = modinv_parent(inv);
    2323         140 :   long e = modinv_parent_power(inv);
    2324             :   disc_info Ds[MODPOLY_MAX_DCNT];
    2325             :   /* FIXME: We throw away the table of fundamental discriminants here. */
    2326         140 :   long nDs = discriminant_with_classno_at_least(Ds, L, inv, NULL, IGNORE_SPARSE_FACTOR);
    2327         140 :   if (nDs != 1) pari_err_BUG("polmodular0_powerup_ZM");
    2328         140 :   D = Ds[0].D1;
    2329         140 :   nprimes = Ds[0].nprimes + 1;
    2330         140 :   mp = polmodular0_ZM(L, parent, NULL, NULL, 0, db);
    2331         140 :   H = polclass0(D, parent, 0, db);
    2332             : 
    2333         140 :   N = L + 2;
    2334         140 :   if (degpol(H) < N) pari_err_BUG("polmodular0_powerup_ZM");
    2335             : 
    2336         140 :   av = avma;
    2337         140 :   pol = ZM_init_CRT(zero_Flm_copy(N, L + 2), 1);
    2338         140 :   P = gen_1;
    2339         469 :   for (s = 1; s < nprimes; ++s) {
    2340             :     pari_sp av1, av2;
    2341         329 :     ulong p = Ds[0].primes[s-1], pi = get_Fl_red(p);
    2342             :     long i;
    2343             :     GEN Hrts, js, Hp, Phip, coeff_mat, phi_modp;
    2344             : 
    2345         329 :     phi_modp = zero_Flm_copy(N, L + 2);
    2346         329 :     av1 = avma;
    2347         329 :     Hp = ZX_to_Flx(H, p);
    2348         329 :     Hrts = Flx_roots_pre(Hp, p, pi);
    2349         329 :     if (lg(Hrts)-1 < N) pari_err_BUG("polmodular0_powerup_ZM");
    2350         329 :     js = cgetg(N + 1, t_VECSMALL);
    2351        2506 :     for (i = 1; i <= N; ++i)
    2352        2177 :       uel(js, i) = Fl_powu_pre(uel(Hrts, i), e, p, pi);
    2353             : 
    2354         329 :     Phip = ZM_to_Flm(mp, p);
    2355         329 :     coeff_mat = zero_Flm_copy(N, L + 2);
    2356         329 :     av2 = avma;
    2357        2506 :     for (i = 1; i <= N; ++i) {
    2358             :       long k;
    2359             :       GEN phi_at_ji, mprts;
    2360             : 
    2361        2177 :       phi_at_ji = Flm_Fl_polmodular_evalx(Phip, L, uel(Hrts, i), p, pi);
    2362        2177 :       mprts = Flx_roots_pre(phi_at_ji, p, pi);
    2363        2177 :       if (lg(mprts) != L + 2) pari_err_BUG("polmodular0_powerup_ZM");
    2364             : 
    2365        2177 :       Flv_powu_inplace_pre(mprts, e, p, pi);
    2366        2177 :       phi_at_ji = Flv_roots_to_pol(mprts, p, 0);
    2367             : 
    2368       17290 :       for (k = 1; k <= L + 2; ++k)
    2369       15113 :         ucoeff(coeff_mat, i, k) = uel(phi_at_ji, k + 1);
    2370        2177 :       set_avma(av2);
    2371             :     }
    2372             : 
    2373         329 :     interpolate_coeffs(phi_modp, p, js, coeff_mat);
    2374         329 :     set_avma(av1);
    2375             : 
    2376         329 :     (void) ZM_incremental_CRT(&pol, phi_modp, &P, p);
    2377         329 :     if (gc_needed(av, 2)) (void)gc_all(av, 2, &pol, &P);
    2378             :   }
    2379         140 :   killblock((GEN)Ds[0].primes); return gc_upto(ltop, pol);
    2380             : }
    2381             : 
    2382             : /* Returns the modular polynomial with the smallest level for the given
    2383             :  * invariant, except if inv is INV_J, in which case return the modular
    2384             :  * polynomial of level L in {2,3,5}.  NULL is returned if the modular
    2385             :  * polynomial can be calculated using polmodular0_powerup_ZM. */
    2386             : INLINE GEN
    2387       24946 : internal_db(long L, long inv)
    2388             : {
    2389       24946 :   switch (inv) {
    2390       23805 :   case INV_J: switch (L) {
    2391       20015 :     case 2: return phi2_ZV();
    2392        1910 :     case 3: return phi3_ZV();
    2393        1880 :     case 5: return phi5_ZV();
    2394           0 :     default: break;
    2395             :   }
    2396         189 :   case INV_F: return phi5_f_ZV();
    2397          14 :   case INV_F2: return NULL;
    2398          14 :   case INV_F3: return phi3_f3_ZV();
    2399          14 :   case INV_F4: return NULL;
    2400          98 :   case INV_G2: return phi2_g2_ZV();
    2401          56 :   case INV_W2W3: return phi5_w2w3_ZV();
    2402          14 :   case INV_F8: return NULL;
    2403          63 :   case INV_W3W3: return phi5_w3w3_ZV();
    2404          91 :   case INV_W2W5: return phi7_w2w5_ZV();
    2405         182 :   case INV_W2W7: return phi3_w2w7_ZV();
    2406          35 :   case INV_W3W5: return phi2_w3w5_ZV();
    2407          49 :   case INV_W3W7: return phi5_w3w7_ZV();
    2408          14 :   case INV_W2W3E2: return NULL;
    2409          21 :   case INV_W2W5E2: return NULL;
    2410          35 :   case INV_W2W13: return phi3_w2w13_ZV();
    2411          63 :   case INV_W2W7E2: return NULL;
    2412          21 :   case INV_W3W3E2: return phi2_w3w3e2_ZV();
    2413          70 :   case INV_W5W7: return phi2_w5w7_ZV();
    2414          14 :   case INV_W3W13: return phi2_w3w13_ZV();
    2415           7 :   case INV_ATKIN3: return phi2_atkin3_ZV();
    2416          14 :   case INV_ATKIN5: return phi2_atkin5_ZV();
    2417           7 :   case INV_ATKIN7: return phi2_atkin7_ZV();
    2418           0 :   case INV_ATKIN11: return phi2_atkin11_ZV();
    2419           0 :   case INV_ATKIN13: return phi2_atkin13_ZV();
    2420           0 :   case INV_ATKIN17: return phi2_atkin17_ZV();
    2421          14 :   case INV_ATKIN19: return phi2_atkin19_ZV();
    2422          21 :   case INV_ATKIN23: return phi2_atkin23_ZV();
    2423          21 :   case INV_ATKIN29: return phi2_atkin29_ZV();
    2424             :   }
    2425           0 :   pari_err_BUG("internal_db");
    2426             :   return NULL;/*LCOV_EXCL_LINE*/
    2427             : }
    2428             : 
    2429             : /* NB: Should only be called if L <= modinv_max_internal_level(inv) */
    2430             : static GEN
    2431       24946 : polmodular_small_ZM(long L, long inv, GEN *db)
    2432             : {
    2433       24946 :   GEN f = internal_db(L, inv);
    2434       24946 :   if (!f) return polmodular0_powerup_ZM(L, inv, db);
    2435       24806 :   return sympol_to_ZM(f, L);
    2436             : }
    2437             : 
    2438             : /* Each function phi_w?w?_j() returns a vector V containing two
    2439             :  * vectors u and v, and a scalar k, which together represent the
    2440             :  * bivariate polnomial
    2441             :  *
    2442             :  *   phi(X, Y) = \sum_i u[i] X^i + Y \sum_i v[i] X^i + Y^2 X^k
    2443             :  */
    2444             : static GEN
    2445        1060 : phi_w2w3_j(void)
    2446             : {
    2447             :   GEN phi, phi0, phi1;
    2448        1060 :   phi = cgetg(4, t_VEC);
    2449             : 
    2450        1060 :   phi0 = cgetg(14, t_VEC);
    2451        1060 :   gel(phi0, 1) = gen_1;
    2452        1060 :   gel(phi0, 2) = utoineg(0x3cUL);
    2453        1060 :   gel(phi0, 3) = utoi(0x702UL);
    2454        1060 :   gel(phi0, 4) = utoineg(0x797cUL);
    2455        1060 :   gel(phi0, 5) = utoi(0x5046fUL);
    2456        1060 :   gel(phi0, 6) = utoineg(0x1be0b8UL);
    2457        1060 :   gel(phi0, 7) = utoi(0x28ef9cUL);
    2458        1060 :   gel(phi0, 8) = utoi(0x15e2968UL);
    2459        1060 :   gel(phi0, 9) = utoi(0x1b8136fUL);
    2460        1060 :   gel(phi0, 10) = utoi(0xa67674UL);
    2461        1060 :   gel(phi0, 11) = utoi(0x23982UL);
    2462        1060 :   gel(phi0, 12) = utoi(0x294UL);
    2463        1060 :   gel(phi0, 13) = gen_1;
    2464             : 
    2465        1060 :   phi1 = cgetg(13, t_VEC);
    2466        1060 :   gel(phi1, 1) = gen_0;
    2467        1060 :   gel(phi1, 2) = gen_0;
    2468        1060 :   gel(phi1, 3) = gen_m1;
    2469        1060 :   gel(phi1, 4) = utoi(0x23UL);
    2470        1060 :   gel(phi1, 5) = utoineg(0xaeUL);
    2471        1060 :   gel(phi1, 6) = utoineg(0x5b8UL);
    2472        1060 :   gel(phi1, 7) = utoi(0x12d7UL);
    2473        1060 :   gel(phi1, 8) = utoineg(0x7c86UL);
    2474        1060 :   gel(phi1, 9) = utoi(0x37c8UL);
    2475        1060 :   gel(phi1, 10) = utoineg(0x69cUL);
    2476        1060 :   gel(phi1, 11) = utoi(0x48UL);
    2477        1060 :   gel(phi1, 12) = gen_m1;
    2478             : 
    2479        1060 :   gel(phi, 1) = phi0;
    2480        1060 :   gel(phi, 2) = phi1;
    2481        1060 :   gel(phi, 3) = utoi(5); return phi;
    2482             : }
    2483             : 
    2484             : static GEN
    2485        3608 : phi_w3w3_j(void)
    2486             : {
    2487             :   GEN phi, phi0, phi1;
    2488        3608 :   phi = cgetg(4, t_VEC);
    2489             : 
    2490        3608 :   phi0 = cgetg(14, t_VEC);
    2491        3608 :   gel(phi0, 1) = utoi(0x2d9UL);
    2492        3608 :   gel(phi0, 2) = utoi(0x4fbcUL);
    2493        3608 :   gel(phi0, 3) = utoi(0x5828aUL);
    2494        3608 :   gel(phi0, 4) = utoi(0x3a7a3cUL);
    2495        3608 :   gel(phi0, 5) = utoi(0x1bd8edfUL);
    2496        3608 :   gel(phi0, 6) = utoi(0x8348838UL);
    2497        3608 :   gel(phi0, 7) = utoi(0x1983f8acUL);
    2498        3608 :   gel(phi0, 8) = utoi(0x14e4e098UL);
    2499        3608 :   gel(phi0, 9) = utoi(0x69ed1a7UL);
    2500        3608 :   gel(phi0, 10) = utoi(0xc3828cUL);
    2501        3608 :   gel(phi0, 11) = utoi(0x2696aUL);
    2502        3608 :   gel(phi0, 12) = utoi(0x2acUL);
    2503        3608 :   gel(phi0, 13) = gen_1;
    2504             : 
    2505        3608 :   phi1 = cgetg(13, t_VEC);
    2506        3608 :   gel(phi1, 1) = gen_0;
    2507        3608 :   gel(phi1, 2) = utoineg(0x1bUL);
    2508        3608 :   gel(phi1, 3) = utoineg(0x5d6UL);
    2509        3608 :   gel(phi1, 4) = utoineg(0x1c7bUL);
    2510        3608 :   gel(phi1, 5) = utoi(0x7980UL);
    2511        3608 :   gel(phi1, 6) = utoi(0x12168UL);
    2512        3608 :   gel(phi1, 7) = utoineg(0x3528UL);
    2513        3608 :   gel(phi1, 8) = utoineg(0x6174UL);
    2514        3608 :   gel(phi1, 9) = utoi(0x2208UL);
    2515        3608 :   gel(phi1, 10) = utoineg(0x41dUL);
    2516        3608 :   gel(phi1, 11) = utoi(0x36UL);
    2517        3608 :   gel(phi1, 12) = gen_m1;
    2518             : 
    2519        3608 :   gel(phi, 1) = phi0;
    2520        3608 :   gel(phi, 2) = phi1;
    2521        3608 :   gel(phi, 3) = gen_2; return phi;
    2522             : }
    2523             : 
    2524             : static GEN
    2525        2927 : phi_w2w5_j(void)
    2526             : {
    2527             :   GEN phi, phi0, phi1;
    2528        2927 :   phi = cgetg(4, t_VEC);
    2529             : 
    2530        2927 :   phi0 = cgetg(20, t_VEC);
    2531        2927 :   gel(phi0, 1) = gen_1;
    2532        2927 :   gel(phi0, 2) = utoineg(0x2aUL);
    2533        2927 :   gel(phi0, 3) = utoi(0x549UL);
    2534        2927 :   gel(phi0, 4) = utoineg(0x6530UL);
    2535        2927 :   gel(phi0, 5) = utoi(0x60504UL);
    2536        2927 :   gel(phi0, 6) = utoineg(0x3cbbc8UL);
    2537        2927 :   gel(phi0, 7) = utoi(0x1d1ee74UL);
    2538        2927 :   gel(phi0, 8) = utoineg(0x7ef9ab0UL);
    2539        2927 :   gel(phi0, 9) = utoi(0x12b888beUL);
    2540        2927 :   gel(phi0, 10) = utoineg(0x15fa174cUL);
    2541        2927 :   gel(phi0, 11) = utoi(0x615d9feUL);
    2542        2927 :   gel(phi0, 12) = utoi(0xbeca070UL);
    2543        2927 :   gel(phi0, 13) = utoineg(0x88de74cUL);
    2544        2927 :   gel(phi0, 14) = utoineg(0x2b3a268UL);
    2545        2927 :   gel(phi0, 15) = utoi(0x24b3244UL);
    2546        2927 :   gel(phi0, 16) = utoi(0xb56270UL);
    2547        2927 :   gel(phi0, 17) = utoi(0x25989UL);
    2548        2927 :   gel(phi0, 18) = utoi(0x2a6UL);
    2549        2927 :   gel(phi0, 19) = gen_1;
    2550             : 
    2551        2927 :   phi1 = cgetg(19, t_VEC);
    2552        2927 :   gel(phi1, 1) = gen_0;
    2553        2927 :   gel(phi1, 2) = gen_0;
    2554        2927 :   gel(phi1, 3) = gen_m1;
    2555        2927 :   gel(phi1, 4) = utoi(0x1eUL);
    2556        2927 :   gel(phi1, 5) = utoineg(0xffUL);
    2557        2927 :   gel(phi1, 6) = utoi(0x243UL);
    2558        2927 :   gel(phi1, 7) = utoineg(0xf3UL);
    2559        2927 :   gel(phi1, 8) = utoineg(0x5c4UL);
    2560        2927 :   gel(phi1, 9) = utoi(0x107bUL);
    2561        2927 :   gel(phi1, 10) = utoineg(0x11b2fUL);
    2562        2927 :   gel(phi1, 11) = utoi(0x48fa8UL);
    2563        2927 :   gel(phi1, 12) = utoineg(0x6ff7cUL);
    2564        2927 :   gel(phi1, 13) = utoi(0x4bf48UL);
    2565        2927 :   gel(phi1, 14) = utoineg(0x187efUL);
    2566        2927 :   gel(phi1, 15) = utoi(0x404cUL);
    2567        2927 :   gel(phi1, 16) = utoineg(0x582UL);
    2568        2927 :   gel(phi1, 17) = utoi(0x3cUL);
    2569        2927 :   gel(phi1, 18) = gen_m1;
    2570             : 
    2571        2927 :   gel(phi, 1) = phi0;
    2572        2927 :   gel(phi, 2) = phi1;
    2573        2927 :   gel(phi, 3) = utoi(7); return phi;
    2574             : }
    2575             : 
    2576             : static GEN
    2577        6628 : phi_w2w7_j(void)
    2578             : {
    2579             :   GEN phi, phi0, phi1;
    2580        6628 :   phi = cgetg(4, t_VEC);
    2581             : 
    2582        6628 :   phi0 = cgetg(26, t_VEC);
    2583        6628 :   gel(phi0, 1) = gen_1;
    2584        6628 :   gel(phi0, 2) = utoineg(0x24UL);
    2585        6628 :   gel(phi0, 3) = utoi(0x4ceUL);
    2586        6628 :   gel(phi0, 4) = utoineg(0x5d60UL);
    2587        6628 :   gel(phi0, 5) = utoi(0x62b05UL);
    2588        6628 :   gel(phi0, 6) = utoineg(0x47be78UL);
    2589        6628 :   gel(phi0, 7) = utoi(0x2a3880aUL);
    2590        6628 :   gel(phi0, 8) = utoineg(0x114bccf4UL);
    2591        6628 :   gel(phi0, 9) = utoi(0x4b95e79aUL);
    2592        6628 :   gel(phi0, 10) = utoineg(0xe2cfee1cUL);
    2593        6628 :   gel(phi0, 11) = uu32toi(0x1UL, 0xe43d1126UL);
    2594        6628 :   gel(phi0, 12) = uu32toineg(0x2UL, 0xf04dc6f8UL);
    2595        6628 :   gel(phi0, 13) = uu32toi(0x3UL, 0x5384987dUL);
    2596        6628 :   gel(phi0, 14) = uu32toineg(0x2UL, 0xa5ccbe18UL);
    2597        6628 :   gel(phi0, 15) = uu32toi(0x1UL, 0x4c52c8a6UL);
    2598        6628 :   gel(phi0, 16) = utoineg(0x2643fdecUL);
    2599        6628 :   gel(phi0, 17) = utoineg(0x49f5ab66UL);
    2600        6628 :   gel(phi0, 18) = utoi(0x33074d3cUL);
    2601        6628 :   gel(phi0, 19) = utoineg(0x6a3e376UL);
    2602        6628 :   gel(phi0, 20) = utoineg(0x675aa58UL);
    2603        6628 :   gel(phi0, 21) = utoi(0x2674005UL);
    2604        6628 :   gel(phi0, 22) = utoi(0xba5be0UL);
    2605        6628 :   gel(phi0, 23) = utoi(0x2644eUL);
    2606        6628 :   gel(phi0, 24) = utoi(0x2acUL);
    2607        6628 :   gel(phi0, 25) = gen_1;
    2608             : 
    2609        6628 :   phi1 = cgetg(25, t_VEC);
    2610        6628 :   gel(phi1, 1) = gen_0;
    2611        6628 :   gel(phi1, 2) = gen_0;
    2612        6628 :   gel(phi1, 3) = gen_m1;
    2613        6628 :   gel(phi1, 4) = utoi(0x1cUL);
    2614        6628 :   gel(phi1, 5) = utoineg(0x10aUL);
    2615        6628 :   gel(phi1, 6) = utoi(0x3f0UL);
    2616        6628 :   gel(phi1, 7) = utoineg(0x5d3UL);
    2617        6628 :   gel(phi1, 8) = utoi(0x3efUL);
    2618        6628 :   gel(phi1, 9) = utoineg(0x102UL);
    2619        6628 :   gel(phi1, 10) = utoineg(0x5c8UL);
    2620        6628 :   gel(phi1, 11) = utoi(0x102fUL);
    2621        6628 :   gel(phi1, 12) = utoineg(0x13f8aUL);
    2622        6628 :   gel(phi1, 13) = utoi(0x86538UL);
    2623        6628 :   gel(phi1, 14) = utoineg(0x1bbd10UL);
    2624        6628 :   gel(phi1, 15) = utoi(0x3614e8UL);
    2625        6628 :   gel(phi1, 16) = utoineg(0x42f793UL);
    2626        6628 :   gel(phi1, 17) = utoi(0x364698UL);
    2627        6628 :   gel(phi1, 18) = utoineg(0x1c7a10UL);
    2628        6628 :   gel(phi1, 19) = utoi(0x97cc8UL);
    2629        6628 :   gel(phi1, 20) = utoineg(0x1fc8aUL);
    2630        6628 :   gel(phi1, 21) = utoi(0x4210UL);
    2631        6628 :   gel(phi1, 22) = utoineg(0x524UL);
    2632        6628 :   gel(phi1, 23) = utoi(0x38UL);
    2633        6628 :   gel(phi1, 24) = gen_m1;
    2634             : 
    2635        6628 :   gel(phi, 1) = phi0;
    2636        6628 :   gel(phi, 2) = phi1;
    2637        6628 :   gel(phi, 3) = utoi(9); return phi;
    2638             : }
    2639             : 
    2640             : static GEN
    2641        2157 : phi_w2w13_j(void)
    2642             : {
    2643             :   GEN phi, phi0, phi1;
    2644        2157 :   phi = cgetg(4, t_VEC);
    2645             : 
    2646        2157 :   phi0 = cgetg(44, t_VEC);
    2647        2157 :   gel(phi0, 1) = gen_1;
    2648        2157 :   gel(phi0, 2) = utoineg(0x1eUL);
    2649        2157 :   gel(phi0, 3) = utoi(0x45fUL);
    2650        2157 :   gel(phi0, 4) = utoineg(0x5590UL);
    2651        2157 :   gel(phi0, 5) = utoi(0x64407UL);
    2652        2157 :   gel(phi0, 6) = utoineg(0x53a792UL);
    2653        2157 :   gel(phi0, 7) = utoi(0x3b21af3UL);
    2654        2157 :   gel(phi0, 8) = utoineg(0x20d056d0UL);
    2655        2157 :   gel(phi0, 9) = utoi(0xe02db4a6UL);
    2656        2157 :   gel(phi0, 10) = uu32toineg(0x4UL, 0xb23400b0UL);
    2657        2157 :   gel(phi0, 11) = uu32toi(0x14UL, 0x57fbb906UL);
    2658        2157 :   gel(phi0, 12) = uu32toineg(0x49UL, 0xcf80c00UL);
    2659        2157 :   gel(phi0, 13) = uu32toi(0xdeUL, 0x84ff421UL);
    2660        2157 :   gel(phi0, 14) = uu32toineg(0x244UL, 0xc500c156UL);
    2661        2157 :   gel(phi0, 15) = uu32toi(0x52cUL, 0x79162979UL);
    2662        2157 :   gel(phi0, 16) = uu32toineg(0xa64UL, 0x8edc5650UL);
    2663        2157 :   gel(phi0, 17) = uu32toi(0x1289UL, 0x4225bb41UL);
    2664        2157 :   gel(phi0, 18) = uu32toineg(0x1d89UL, 0x2a15229aUL);
    2665        2157 :   gel(phi0, 19) = uu32toi(0x2a3eUL, 0x4539f1ebUL);
    2666        2157 :   gel(phi0, 20) = uu32toineg(0x366aUL, 0xa5ea1130UL);
    2667        2157 :   gel(phi0, 21) = uu32toi(0x3f47UL, 0xa19fecb4UL);
    2668        2157 :   gel(phi0, 22) = uu32toineg(0x4282UL, 0x91a3c4a0UL);
    2669        2157 :   gel(phi0, 23) = uu32toi(0x3f30UL, 0xbaa305b4UL);
    2670        2157 :   gel(phi0, 24) = uu32toineg(0x3635UL, 0xd11c2530UL);
    2671        2157 :   gel(phi0, 25) = uu32toi(0x29e2UL, 0x89df27ebUL);
    2672        2157 :   gel(phi0, 26) = uu32toineg(0x1d03UL, 0x6509d48aUL);
    2673        2156 :   gel(phi0, 27) = uu32toi(0x11e2UL, 0x272cc601UL);
    2674        2156 :   gel(phi0, 28) = uu32toineg(0x9b0UL, 0xacd58ff0UL);
    2675        2156 :   gel(phi0, 29) = uu32toi(0x485UL, 0x608d7db9UL);
    2676        2156 :   gel(phi0, 30) = uu32toineg(0x1bfUL, 0xa941546UL);
    2677        2157 :   gel(phi0, 31) = uu32toi(0x82UL, 0x56e48b21UL);
    2678        2157 :   gel(phi0, 32) = uu32toineg(0x13UL, 0xc36b2340UL);
    2679        2157 :   gel(phi0, 33) = uu32toineg(0x5UL, 0x6637257aUL);
    2680        2157 :   gel(phi0, 34) = uu32toi(0x5UL, 0x40f70bd0UL);
    2681        2157 :   gel(phi0, 35) = uu32toineg(0x1UL, 0xf70842daUL);
    2682        2157 :   gel(phi0, 36) = utoi(0x53eea5f0UL);
    2683        2157 :   gel(phi0, 37) = utoi(0xda17bf3UL);
    2684        2157 :   gel(phi0, 38) = utoineg(0xaf246c2UL);
    2685        2157 :   gel(phi0, 39) = utoi(0x278f847UL);
    2686        2157 :   gel(phi0, 40) = utoi(0xbf5550UL);
    2687        2157 :   gel(phi0, 41) = utoi(0x26f1fUL);
    2688        2157 :   gel(phi0, 42) = utoi(0x2b2UL);
    2689        2157 :   gel(phi0, 43) = gen_1;
    2690             : 
    2691        2157 :   phi1 = cgetg(43, t_VEC);
    2692        2157 :   gel(phi1, 1) = gen_0;
    2693        2157 :   gel(phi1, 2) = gen_0;
    2694        2157 :   gel(phi1, 3) = gen_m1;
    2695        2157 :   gel(phi1, 4) = utoi(0x1aUL);
    2696        2157 :   gel(phi1, 5) = utoineg(0x111UL);
    2697        2157 :   gel(phi1, 6) = utoi(0x5e4UL);
    2698        2157 :   gel(phi1, 7) = utoineg(0x1318UL);
    2699        2157 :   gel(phi1, 8) = utoi(0x2804UL);
    2700        2157 :   gel(phi1, 9) = utoineg(0x3cd6UL);
    2701        2157 :   gel(phi1, 10) = utoi(0x467cUL);
    2702        2157 :   gel(phi1, 11) = utoineg(0x3cd6UL);
    2703        2157 :   gel(phi1, 12) = utoi(0x2804UL);
    2704        2157 :   gel(phi1, 13) = utoineg(0x1318UL);
    2705        2157 :   gel(phi1, 14) = utoi(0x5e3UL);
    2706        2157 :   gel(phi1, 15) = utoineg(0x10dUL);
    2707        2157 :   gel(phi1, 16) = utoineg(0x5ccUL);
    2708        2157 :   gel(phi1, 17) = utoi(0x100bUL);
    2709        2157 :   gel(phi1, 18) = utoineg(0x160e1UL);
    2710        2157 :   gel(phi1, 19) = utoi(0xd2cb0UL);
    2711        2157 :   gel(phi1, 20) = utoineg(0x4c85fcUL);
    2712        2157 :   gel(phi1, 21) = utoi(0x137cb98UL);
    2713        2157 :   gel(phi1, 22) = utoineg(0x3c75568UL);
    2714        2157 :   gel(phi1, 23) = utoi(0x95c69c8UL);
    2715        2157 :   gel(phi1, 24) = utoineg(0x131557bcUL);
    2716        2157 :   gel(phi1, 25) = utoi(0x20aacfd0UL);
    2717        2157 :   gel(phi1, 26) = utoineg(0x2f9164e6UL);
    2718        2157 :   gel(phi1, 27) = utoi(0x3b6a5e40UL);
    2719        2157 :   gel(phi1, 28) = utoineg(0x3ff54344UL);
    2720        2157 :   gel(phi1, 29) = utoi(0x3b6a9140UL);
    2721        2157 :   gel(phi1, 30) = utoineg(0x2f927fa6UL);
    2722        2157 :   gel(phi1, 31) = utoi(0x20ae6450UL);
    2723        2157 :   gel(phi1, 32) = utoineg(0x131cd87cUL);
    2724        2157 :   gel(phi1, 33) = utoi(0x967d1e8UL);
    2725        2157 :   gel(phi1, 34) = utoineg(0x3d48ca8UL);
    2726        2157 :   gel(phi1, 35) = utoi(0x14333b8UL);
    2727        2157 :   gel(phi1, 36) = utoineg(0x5406bcUL);
    2728        2157 :   gel(phi1, 37) = utoi(0x10c130UL);
    2729        2157 :   gel(phi1, 38) = utoineg(0x27ba1UL);
    2730        2157 :   gel(phi1, 39) = utoi(0x433cUL);
    2731        2157 :   gel(phi1, 40) = utoineg(0x4c6UL);
    2732        2157 :   gel(phi1, 41) = utoi(0x34UL);
    2733        2157 :   gel(phi1, 42) = gen_m1;
    2734             : 
    2735        2157 :   gel(phi, 1) = phi0;
    2736        2157 :   gel(phi, 2) = phi1;
    2737        2157 :   gel(phi, 3) = utoi(15); return phi;
    2738             : }
    2739             : 
    2740             : static GEN
    2741        1160 : phi_w3w5_j(void)
    2742             : {
    2743             :   GEN phi, phi0, phi1;
    2744        1160 :   phi = cgetg(4, t_VEC);
    2745             : 
    2746        1160 :   phi0 = cgetg(26, t_VEC);
    2747        1160 :   gel(phi0, 1) = gen_1;
    2748        1160 :   gel(phi0, 2) = utoi(0x18UL);
    2749        1160 :   gel(phi0, 3) = utoi(0xb4UL);
    2750        1160 :   gel(phi0, 4) = utoineg(0x178UL);
    2751        1160 :   gel(phi0, 5) = utoineg(0x2d7eUL);
    2752        1160 :   gel(phi0, 6) = utoineg(0x89b8UL);
    2753        1160 :   gel(phi0, 7) = utoi(0x35c24UL);
    2754        1160 :   gel(phi0, 8) = utoi(0x128a18UL);
    2755        1160 :   gel(phi0, 9) = utoineg(0x12a911UL);
    2756        1160 :   gel(phi0, 10) = utoineg(0xcc0190UL);
    2757        1160 :   gel(phi0, 11) = utoi(0x94368UL);
    2758        1160 :   gel(phi0, 12) = utoi(0x1439d0UL);
    2759        1160 :   gel(phi0, 13) = utoi(0x96f931cUL);
    2760        1160 :   gel(phi0, 14) = utoineg(0x1f59ff0UL);
    2761        1160 :   gel(phi0, 15) = utoi(0x20e7e8UL);
    2762        1160 :   gel(phi0, 16) = utoineg(0x25fdf150UL);
    2763        1160 :   gel(phi0, 17) = utoineg(0x7091511UL);
    2764        1160 :   gel(phi0, 18) = utoi(0x1ef52f8UL);
    2765        1160 :   gel(phi0, 19) = utoi(0x341f2de4UL);
    2766        1160 :   gel(phi0, 20) = utoi(0x25d72c28UL);
    2767        1160 :   gel(phi0, 21) = utoi(0x95d2082UL);
    2768        1160 :   gel(phi0, 22) = utoi(0xd2d828UL);
    2769        1160 :   gel(phi0, 23) = utoi(0x281f4UL);
    2770        1160 :   gel(phi0, 24) = utoi(0x2b8UL);
    2771        1160 :   gel(phi0, 25) = gen_1;
    2772             : 
    2773        1160 :   phi1 = cgetg(25, t_VEC);
    2774        1160 :   gel(phi1, 1) = gen_0;
    2775        1160 :   gel(phi1, 2) = gen_0;
    2776        1160 :   gel(phi1, 3) = gen_0;
    2777        1160 :   gel(phi1, 4) = gen_1;
    2778        1160 :   gel(phi1, 5) = utoi(0xfUL);
    2779        1160 :   gel(phi1, 6) = utoi(0x2eUL);
    2780        1160 :   gel(phi1, 7) = utoineg(0x1fUL);
    2781        1160 :   gel(phi1, 8) = utoineg(0x2dUL);
    2782        1160 :   gel(phi1, 9) = utoineg(0x5caUL);
    2783        1160 :   gel(phi1, 10) = utoineg(0x358UL);
    2784        1160 :   gel(phi1, 11) = utoi(0x2f1cUL);
    2785        1160 :   gel(phi1, 12) = utoi(0xd8eaUL);
    2786        1160 :   gel(phi1, 13) = utoineg(0x38c70UL);
    2787        1160 :   gel(phi1, 14) = utoineg(0x1a964UL);
    2788        1160 :   gel(phi1, 15) = utoi(0x93512UL);
    2789        1160 :   gel(phi1, 16) = utoineg(0x58f2UL);
    2790        1160 :   gel(phi1, 17) = utoineg(0x5af1eUL);
    2791        1160 :   gel(phi1, 18) = utoi(0x1afb8UL);
    2792        1160 :   gel(phi1, 19) = utoi(0xc084UL);
    2793        1160 :   gel(phi1, 20) = utoineg(0x7fcbUL);
    2794        1160 :   gel(phi1, 21) = utoi(0x1c89UL);
    2795        1160 :   gel(phi1, 22) = utoineg(0x32aUL);
    2796        1160 :   gel(phi1, 23) = utoi(0x2dUL);
    2797        1160 :   gel(phi1, 24) = gen_m1;
    2798             : 
    2799        1160 :   gel(phi, 1) = phi0;
    2800        1160 :   gel(phi, 2) = phi1;
    2801        1160 :   gel(phi, 3) = utoi(8); return phi;
    2802             : }
    2803             : 
    2804             : static GEN
    2805        2986 : phi_w3w7_j(void)
    2806             : {
    2807             :   GEN phi, phi0, phi1;
    2808        2986 :   phi = cgetg(4, t_VEC);
    2809             : 
    2810        2986 :   phi0 = cgetg(34, t_VEC);
    2811        2986 :   gel(phi0, 1) = gen_1;
    2812        2986 :   gel(phi0, 2) = utoineg(0x14UL);
    2813        2986 :   gel(phi0, 3) = utoi(0x82UL);
    2814        2986 :   gel(phi0, 4) = utoi(0x1f8UL);
    2815        2986 :   gel(phi0, 5) = utoineg(0x2a45UL);
    2816        2986 :   gel(phi0, 6) = utoi(0x9300UL);
    2817        2986 :   gel(phi0, 7) = utoi(0x32abeUL);
    2818        2986 :   gel(phi0, 8) = utoineg(0x19c91cUL);
    2819        2986 :   gel(phi0, 9) = utoi(0xc1ba9UL);
    2820        2986 :   gel(phi0, 10) = utoi(0x1788f68UL);
    2821        2986 :   gel(phi0, 11) = utoineg(0x2b1989cUL);
    2822        2986 :   gel(phi0, 12) = utoineg(0x7a92408UL);
    2823        2986 :   gel(phi0, 13) = utoi(0x1238d56eUL);
    2824        2986 :   gel(phi0, 14) = utoi(0x13dd66a0UL);
    2825        2986 :   gel(phi0, 15) = utoineg(0x2dbedca8UL);
    2826        2986 :   gel(phi0, 16) = utoineg(0x34282eb8UL);
    2827        2986 :   gel(phi0, 17) = utoi(0x2c2a54d2UL);
    2828        2986 :   gel(phi0, 18) = utoi(0x98db81a8UL);
    2829        2986 :   gel(phi0, 19) = utoineg(0x4088be8UL);
    2830        2986 :   gel(phi0, 20) = utoineg(0xe424a220UL);
    2831        2986 :   gel(phi0, 21) = utoineg(0x67bbb232UL);
    2832        2986 :   gel(phi0, 22) = utoi(0x7dd8bb98UL);
    2833        2986 :   gel(phi0, 23) = uu32toi(0x1UL, 0xcaff744UL);
    2834        2986 :   gel(phi0, 24) = utoineg(0x1d46a378UL);
    2835        2986 :   gel(phi0, 25) = utoineg(0x82fa50f7UL);
    2836        2986 :   gel(phi0, 26) = utoineg(0x700ef38cUL);
    2837        2986 :   gel(phi0, 27) = utoi(0x20aa202eUL);
    2838        2986 :   gel(phi0, 28) = utoi(0x299b3440UL);
    2839        2986 :   gel(phi0, 29) = utoi(0xa476c4bUL);
    2840        2986 :   gel(phi0, 30) = utoi(0xd80558UL);
    2841        2986 :   gel(phi0, 31) = utoi(0x28a32UL);
    2842        2986 :   gel(phi0, 32) = utoi(0x2bcUL);
    2843        2986 :   gel(phi0, 33) = gen_1;
    2844             : 
    2845        2986 :   phi1 = cgetg(33, t_VEC);
    2846        2986 :   gel(phi1, 1) = gen_0;
    2847        2986 :   gel(phi1, 2) = gen_0;
    2848        2986 :   gel(phi1, 3) = gen_0;
    2849        2986 :   gel(phi1, 4) = gen_m1;
    2850        2986 :   gel(phi1, 5) = utoi(0xeUL);
    2851        2986 :   gel(phi1, 6) = utoineg(0x31UL);
    2852        2986 :   gel(phi1, 7) = utoineg(0xeUL);
    2853        2986 :   gel(phi1, 8) = utoi(0x99UL);
    2854        2986 :   gel(phi1, 9) = utoineg(0x8UL);
    2855        2986 :   gel(phi1, 10) = utoineg(0x2eUL);
    2856        2986 :   gel(phi1, 11) = utoineg(0x5ccUL);
    2857        2986 :   gel(phi1, 12) = utoi(0x308UL);
    2858        2986 :   gel(phi1, 13) = utoi(0x2904UL);
    2859        2986 :   gel(phi1, 14) = utoineg(0x15700UL);
    2860        2986 :   gel(phi1, 15) = utoineg(0x2b9ecUL);
    2861        2986 :   gel(phi1, 16) = utoi(0xf0966UL);
    2862        2986 :   gel(phi1, 17) = utoi(0xb3cc8UL);
    2863        2986 :   gel(phi1, 18) = utoineg(0x38241cUL);
    2864        2986 :   gel(phi1, 19) = utoineg(0x8604cUL);
    2865        2986 :   gel(phi1, 20) = utoi(0x578a64UL);
    2866        2986 :   gel(phi1, 21) = utoineg(0x11a798UL);
    2867        2986 :   gel(phi1, 22) = utoineg(0x39c85eUL);
    2868        2986 :   gel(phi1, 23) = utoi(0x1a5084UL);
    2869        2986 :   gel(phi1, 24) = utoi(0xcdeb4UL);
    2870        2986 :   gel(phi1, 25) = utoineg(0xb0364UL);
    2871        2986 :   gel(phi1, 26) = utoi(0x129d4UL);
    2872        2986 :   gel(phi1, 27) = utoi(0x126fcUL);
    2873        2986 :   gel(phi1, 28) = utoineg(0x8649UL);
    2874        2986 :   gel(phi1, 29) = utoi(0x1aa2UL);
    2875        2986 :   gel(phi1, 30) = utoineg(0x2dfUL);
    2876        2986 :   gel(phi1, 31) = utoi(0x2aUL);
    2877        2986 :   gel(phi1, 32) = gen_m1;
    2878             : 
    2879        2986 :   gel(phi, 1) = phi0;
    2880        2986 :   gel(phi, 2) = phi1;
    2881        2986 :   gel(phi, 3) = utoi(10); return phi;
    2882             : }
    2883             : 
    2884             : static GEN
    2885         210 : phi_w3w13_j(void)
    2886             : {
    2887             :   GEN phi, phi0, phi1;
    2888         210 :   phi = cgetg(4, t_VEC);
    2889             : 
    2890         210 :   phi0 = cgetg(58, t_VEC);
    2891         210 :   gel(phi0, 1) = gen_1;
    2892         210 :   gel(phi0, 2) = utoineg(0x10UL);
    2893         210 :   gel(phi0, 3) = utoi(0x58UL);
    2894         210 :   gel(phi0, 4) = utoi(0x258UL);
    2895         210 :   gel(phi0, 5) = utoineg(0x270cUL);
    2896         210 :   gel(phi0, 6) = utoi(0x9c00UL);
    2897         210 :   gel(phi0, 7) = utoi(0x2b40cUL);
    2898         210 :   gel(phi0, 8) = utoineg(0x20e250UL);
    2899         210 :   gel(phi0, 9) = utoi(0x4f46baUL);
    2900         210 :   gel(phi0, 10) = utoi(0x1869448UL);
    2901         210 :   gel(phi0, 11) = utoineg(0xa49ab68UL);
    2902         210 :   gel(phi0, 12) = utoi(0x96c7630UL);
    2903         210 :   gel(phi0, 13) = utoi(0x4f7e0af6UL);
    2904         210 :   gel(phi0, 14) = utoineg(0xea093590UL);
    2905         210 :   gel(phi0, 15) = utoineg(0x6735bc50UL);
    2906         210 :   gel(phi0, 16) = uu32toi(0x5UL, 0x971a2e08UL);
    2907         210 :   gel(phi0, 17) = uu32toineg(0x6UL, 0x29c9d965UL);
    2908         210 :   gel(phi0, 18) = uu32toineg(0xdUL, 0xeb9aa360UL);
    2909         210 :   gel(phi0, 19) = uu32toi(0x26UL, 0xe9c0584UL);
    2910         210 :   gel(phi0, 20) = uu32toineg(0x1UL, 0xb0cadce8UL);
    2911         210 :   gel(phi0, 21) = uu32toineg(0x62UL, 0x73586014UL);
    2912         210 :   gel(phi0, 22) = uu32toi(0x66UL, 0xaf672e38UL);
    2913         210 :   gel(phi0, 23) = uu32toi(0x6bUL, 0x93c28cdcUL);
    2914         210 :   gel(phi0, 24) = uu32toineg(0x11eUL, 0x4f633080UL);
    2915         210 :   gel(phi0, 25) = uu32toi(0x3cUL, 0xcc42461bUL);
    2916         210 :   gel(phi0, 26) = uu32toi(0x17bUL, 0xdec0a78UL);
    2917         210 :   gel(phi0, 27) = uu32toineg(0x166UL, 0x910d8bd0UL);
    2918         210 :   gel(phi0, 28) = uu32toineg(0xd4UL, 0x47873030UL);
    2919         210 :   gel(phi0, 29) = uu32toi(0x204UL, 0x811828baUL);
    2920         210 :   gel(phi0, 30) = uu32toineg(0x50UL, 0x5d713960UL);
    2921         210 :   gel(phi0, 31) = uu32toineg(0x198UL, 0xa27e42b0UL);
    2922         210 :   gel(phi0, 32) = uu32toi(0xe1UL, 0x25685138UL);
    2923         210 :   gel(phi0, 33) = uu32toi(0xe3UL, 0xaa5774bbUL);
    2924         210 :   gel(phi0, 34) = uu32toineg(0xcfUL, 0x392a9a00UL);
    2925         210 :   gel(phi0, 35) = uu32toineg(0x81UL, 0xfb334d04UL);
    2926         210 :   gel(phi0, 36) = uu32toi(0xabUL, 0x59594a68UL);
    2927         210 :   gel(phi0, 37) = uu32toi(0x42UL, 0x356993acUL);
    2928         210 :   gel(phi0, 38) = uu32toineg(0x86UL, 0x307ba678UL);
    2929         210 :   gel(phi0, 39) = uu32toineg(0xbUL, 0x7a9e59dcUL);
    2930         210 :   gel(phi0, 40) = uu32toi(0x4cUL, 0x27935f20UL);
    2931         210 :   gel(phi0, 41) = uu32toineg(0x2UL, 0xe0ac9045UL);
    2932         210 :   gel(phi0, 42) = uu32toineg(0x24UL, 0x14495758UL);
    2933         210 :   gel(phi0, 43) = utoi(0x20973410UL);
    2934         210 :   gel(phi0, 44) = uu32toi(0x13UL, 0x99ff4e00UL);
    2935         210 :   gel(phi0, 45) = uu32toineg(0x1UL, 0xa710d34aUL);
    2936         210 :   gel(phi0, 46) = uu32toineg(0x7UL, 0xfe5405c0UL);
    2937         210 :   gel(phi0, 47) = uu32toi(0x1UL, 0xcdee0f8UL);
    2938         210 :   gel(phi0, 48) = uu32toi(0x2UL, 0x660c92a8UL);
    2939         210 :   gel(phi0, 49) = utoi(0x3f13a35aUL);
    2940         210 :   gel(phi0, 50) = utoineg(0xe4eb4ba0UL);
    2941         210 :   gel(phi0, 51) = utoineg(0x6420f4UL);
    2942         210 :   gel(phi0, 52) = utoi(0x2c624370UL);
    2943         210 :   gel(phi0, 53) = utoi(0xb31b814UL);
    2944         210 :   gel(phi0, 54) = utoi(0xdd3ad8UL);
    2945         210 :   gel(phi0, 55) = utoi(0x29278UL);
    2946         210 :   gel(phi0, 56) = utoi(0x2c0UL);
    2947         210 :   gel(phi0, 57) = gen_1;
    2948             : 
    2949         210 :   phi1 = cgetg(57, t_VEC);
    2950         210 :   gel(phi1, 1) = gen_0;
    2951         210 :   gel(phi1, 2) = gen_0;
    2952         210 :   gel(phi1, 3) = gen_0;
    2953         210 :   gel(phi1, 4) = gen_m1;
    2954         210 :   gel(phi1, 5) = utoi(0xdUL);
    2955         210 :   gel(phi1, 6) = utoineg(0x34UL);
    2956         210 :   gel(phi1, 7) = utoi(0x1aUL);
    2957         210 :   gel(phi1, 8) = utoi(0xf7UL);
    2958         210 :   gel(phi1, 9) = utoineg(0x16cUL);
    2959         210 :   gel(phi1, 10) = utoineg(0xddUL);
    2960         210 :   gel(phi1, 11) = utoi(0x28aUL);
    2961         210 :   gel(phi1, 12) = utoineg(0xddUL);
    2962         210 :   gel(phi1, 13) = utoineg(0x16cUL);
    2963         210 :   gel(phi1, 14) = utoi(0xf6UL);
    2964         210 :   gel(phi1, 15) = utoi(0x1dUL);
    2965         210 :   gel(phi1, 16) = utoineg(0x31UL);
    2966         210 :   gel(phi1, 17) = utoineg(0x5ceUL);
    2967         210 :   gel(phi1, 18) = utoi(0x2e4UL);
    2968         210 :   gel(phi1, 19) = utoi(0x252cUL);
    2969         210 :   gel(phi1, 20) = utoineg(0x1b34cUL);
    2970         210 :   gel(phi1, 21) = utoi(0xaf80UL);
    2971         210 :   gel(phi1, 22) = utoi(0x1cc5f9UL);
    2972         210 :   gel(phi1, 23) = utoineg(0x3e1aa5UL);
    2973         210 :   gel(phi1, 24) = utoineg(0x86d17aUL);
    2974         210 :   gel(phi1, 25) = utoi(0x2427264UL);
    2975         210 :   gel(phi1, 26) = utoineg(0x691c1fUL);
    2976         210 :   gel(phi1, 27) = utoineg(0x862ad4eUL);
    2977         210 :   gel(phi1, 28) = utoi(0xab21e1fUL);
    2978         210 :   gel(phi1, 29) = utoi(0xbc19ddcUL);
    2979         210 :   gel(phi1, 30) = utoineg(0x24331db8UL);
    2980         210 :   gel(phi1, 31) = utoi(0x972c105UL);
    2981         210 :   gel(phi1, 32) = utoi(0x363d7107UL);
    2982         210 :   gel(phi1, 33) = utoineg(0x39696450UL);
    2983         210 :   gel(phi1, 34) = utoineg(0x1bce7c48UL);
    2984         210 :   gel(phi1, 35) = utoi(0x552ecba0UL);
    2985         210 :   gel(phi1, 36) = utoineg(0x1c7771b8UL);
    2986         210 :   gel(phi1, 37) = utoineg(0x393029b8UL);
    2987         210 :   gel(phi1, 38) = utoi(0x3755be97UL);
    2988         210 :   gel(phi1, 39) = utoi(0x83402a9UL);
    2989         210 :   gel(phi1, 40) = utoineg(0x24d5be62UL);
    2990         210 :   gel(phi1, 41) = utoi(0xdb6d90aUL);
    2991         210 :   gel(phi1, 42) = utoi(0xa0ef177UL);
    2992         210 :   gel(phi1, 43) = utoineg(0x99ff162UL);
    2993         210 :   gel(phi1, 44) = utoi(0xb09e27UL);
    2994         210 :   gel(phi1, 45) = utoi(0x26a7adcUL);
    2995         210 :   gel(phi1, 46) = utoineg(0x116e2fcUL);
    2996         210 :   gel(phi1, 47) = utoineg(0x1383b5UL);
    2997         210 :   gel(phi1, 48) = utoi(0x35a9e7UL);
    2998         210 :   gel(phi1, 49) = utoineg(0x1082a0UL);
    2999         210 :   gel(phi1, 50) = utoineg(0x4696UL);
    3000         210 :   gel(phi1, 51) = utoi(0x19f98UL);
    3001         210 :   gel(phi1, 52) = utoineg(0x8bb3UL);
    3002         210 :   gel(phi1, 53) = utoi(0x18bbUL);
    3003         210 :   gel(phi1, 54) = utoineg(0x297UL);
    3004         210 :   gel(phi1, 55) = utoi(0x27UL);
    3005         210 :   gel(phi1, 56) = gen_m1;
    3006             : 
    3007         210 :   gel(phi, 1) = phi0;
    3008         210 :   gel(phi, 2) = phi1;
    3009         210 :   gel(phi, 3) = utoi(16); return phi;
    3010             : }
    3011             : 
    3012             : static GEN
    3013        3331 : phi_w5w7_j(void)
    3014             : {
    3015             :   GEN phi, phi0, phi1;
    3016        3331 :   phi = cgetg(4, t_VEC);
    3017             : 
    3018        3331 :   phi0 = cgetg(50, t_VEC);
    3019        3331 :   gel(phi0, 1) = gen_1;
    3020        3331 :   gel(phi0, 2) = utoi(0xcUL);
    3021        3331 :   gel(phi0, 3) = utoi(0x2aUL);
    3022        3331 :   gel(phi0, 4) = utoi(0x10UL);
    3023        3331 :   gel(phi0, 5) = utoineg(0x69UL);
    3024        3331 :   gel(phi0, 6) = utoineg(0x318UL);
    3025        3331 :   gel(phi0, 7) = utoineg(0x148aUL);
    3026        3331 :   gel(phi0, 8) = utoineg(0x17c4UL);
    3027        3331 :   gel(phi0, 9) = utoi(0x1a73UL);
    3028        3331 :   gel(phi0, 10) = gen_0;
    3029        3331 :   gel(phi0, 11) = utoi(0x338a0UL);
    3030        3331 :   gel(phi0, 12) = utoi(0x61698UL);
    3031        3331 :   gel(phi0, 13) = utoineg(0x96e8UL);
    3032        3331 :   gel(phi0, 14) = utoi(0x140910UL);
    3033        3331 :   gel(phi0, 15) = utoineg(0x45f6b4UL);
    3034        3332 :   gel(phi0, 16) = utoineg(0x309f50UL);
    3035        3332 :   gel(phi0, 17) = utoineg(0xef9f8bUL);
    3036        3332 :   gel(phi0, 18) = utoineg(0x283167cUL);
    3037        3332 :   gel(phi0, 19) = utoi(0x625e20aUL);
    3038        3332 :   gel(phi0, 20) = utoineg(0x16186350UL);
    3039        3332 :   gel(phi0, 21) = utoi(0x46861281UL);
    3040        3332 :   gel(phi0, 22) = utoineg(0x754b96a0UL);
    3041        3332 :   gel(phi0, 23) = uu32toi(0x1UL, 0x421ca02aUL);
    3042        3332 :   gel(phi0, 24) = uu32toineg(0x2UL, 0xdb76a5cUL);
    3043        3332 :   gel(phi0, 25) = uu32toi(0x4UL, 0xf6afd8eUL);
    3044        3332 :   gel(phi0, 26) = uu32toineg(0x6UL, 0xaafd3cb4UL);
    3045        3332 :   gel(phi0, 27) = uu32toi(0x8UL, 0xda2539caUL);
    3046        3332 :   gel(phi0, 28) = uu32toineg(0xfUL, 0x84343790UL);
    3047        3332 :   gel(phi0, 29) = uu32toi(0xfUL, 0x914ff421UL);
    3048        3332 :   gel(phi0, 30) = uu32toineg(0x19UL, 0x3c123950UL);
    3049        3332 :   gel(phi0, 31) = uu32toi(0x15UL, 0x381f722aUL);
    3050        3332 :   gel(phi0, 32) = uu32toineg(0x15UL, 0xe01c0c24UL);
    3051        3332 :   gel(phi0, 33) = uu32toi(0x19UL, 0x3360b375UL);
    3052        3332 :   gel(phi0, 34) = utoineg(0x59fda9c0UL);
    3053        3332 :   gel(phi0, 35) = uu32toi(0x20UL, 0xff55024cUL);
    3054        3332 :   gel(phi0, 36) = uu32toi(0x16UL, 0xcc600800UL);
    3055        3332 :   gel(phi0, 37) = uu32toi(0x24UL, 0x1879c898UL);
    3056        3332 :   gel(phi0, 38) = uu32toi(0x1cUL, 0x37f97498UL);
    3057        3332 :   gel(phi0, 39) = uu32toi(0x19UL, 0x39ec4b60UL);
    3058        3332 :   gel(phi0, 40) = uu32toi(0x10UL, 0x52c660d0UL);
    3059        3332 :   gel(phi0, 41) = uu32toi(0x9UL, 0xcab00333UL);
    3060        3332 :   gel(phi0, 42) = uu32toi(0x4UL, 0x7fe69be4UL);
    3061        3332 :   gel(phi0, 43) = uu32toi(0x1UL, 0xa0c6f116UL);
    3062        3332 :   gel(phi0, 44) = utoi(0x69244638UL);
    3063        3332 :   gel(phi0, 45) = utoi(0xed560f7UL);
    3064        3332 :   gel(phi0, 46) = utoi(0xe7b660UL);
    3065        3332 :   gel(phi0, 47) = utoi(0x29d8aUL);
    3066        3332 :   gel(phi0, 48) = utoi(0x2c4UL);
    3067        3332 :   gel(phi0, 49) = gen_1;
    3068             : 
    3069        3332 :   phi1 = cgetg(49, t_VEC);
    3070        3332 :   gel(phi1, 1) = gen_0;
    3071        3332 :   gel(phi1, 2) = gen_0;
    3072        3332 :   gel(phi1, 3) = gen_0;
    3073        3332 :   gel(phi1, 4) = gen_0;
    3074        3332 :   gel(phi1, 5) = gen_0;
    3075        3332 :   gel(phi1, 6) = gen_1;
    3076        3332 :   gel(phi1, 7) = utoi(0x7UL);
    3077        3332 :   gel(phi1, 8) = utoi(0x8UL);
    3078        3332 :   gel(phi1, 9) = utoineg(0x9UL);
    3079        3332 :   gel(phi1, 10) = gen_0;
    3080        3332 :   gel(phi1, 11) = utoineg(0x13UL);
    3081        3332 :   gel(phi1, 12) = utoineg(0x7UL);
    3082        3332 :   gel(phi1, 13) = utoineg(0x5ceUL);
    3083        3332 :   gel(phi1, 14) = utoineg(0xb0UL);
    3084        3332 :   gel(phi1, 15) = utoi(0x460UL);
    3085        3332 :   gel(phi1, 16) = utoineg(0x194bUL);
    3086        3332 :   gel(phi1, 17) = utoi(0x87c3UL);
    3087        3332 :   gel(phi1, 18) = utoi(0x3cdeUL);
    3088        3332 :   gel(phi1, 19) = utoineg(0xd683UL);
    3089        3332 :   gel(phi1, 20) = utoi(0x6099bUL);
    3090        3332 :   gel(phi1, 21) = utoineg(0x111ea8UL);
    3091        3332 :   gel(phi1, 22) = utoi(0xfa113UL);
    3092        3332 :   gel(phi1, 23) = utoineg(0x1a6561UL);
    3093        3332 :   gel(phi1, 24) = utoineg(0x1e997UL);
    3094        3332 :   gel(phi1, 25) = utoi(0x214e54UL);
    3095        3332 :   gel(phi1, 26) = utoineg(0x29c3f4UL);
    3096        3332 :   gel(phi1, 27) = utoi(0x67e102UL);
    3097        3332 :   gel(phi1, 28) = utoineg(0x227eaaUL);
    3098        3332 :   gel(phi1, 29) = utoi(0x191d10UL);
    3099        3332 :   gel(phi1, 30) = utoi(0x1a9cd5UL);
    3100        3332 :   gel(phi1, 31) = utoineg(0x58386fUL);
    3101        3332 :   gel(phi1, 32) = utoi(0x2e49f6UL);
    3102        3332 :   gel(phi1, 33) = utoineg(0x31194bUL);
    3103        3332 :   gel(phi1, 34) = utoi(0x9e07aUL);
    3104        3332 :   gel(phi1, 35) = utoi(0x260d59UL);
    3105        3332 :   gel(phi1, 36) = utoineg(0x189921UL);
    3106        3332 :   gel(phi1, 37) = utoi(0xeca4aUL);
    3107        3332 :   gel(phi1, 38) = utoineg(0xa3d9cUL);
    3108        3332 :   gel(phi1, 39) = utoineg(0x426daUL);
    3109        3332 :   gel(phi1, 40) = utoi(0x91875UL);
    3110        3332 :   gel(phi1, 41) = utoineg(0x3b55bUL);
    3111        3332 :   gel(phi1, 42) = utoineg(0x56f4UL);
    3112        3332 :   gel(phi1, 43) = utoi(0xcd1bUL);
    3113        3332 :   gel(phi1, 44) = utoineg(0x5159UL);
    3114        3332 :   gel(phi1, 45) = utoi(0x10f4UL);
    3115        3332 :   gel(phi1, 46) = utoineg(0x20dUL);
    3116        3332 :   gel(phi1, 47) = utoi(0x23UL);
    3117        3332 :   gel(phi1, 48) = gen_m1;
    3118             : 
    3119        3332 :   gel(phi, 1) = phi0;
    3120        3332 :   gel(phi, 2) = phi1;
    3121        3332 :   gel(phi, 3) = utoi(12); return phi;
    3122             : }
    3123             : 
    3124             : static GEN
    3125         693 : phi_atkin3_j(void)
    3126             : {
    3127             :   GEN phi, phi0, phi1;
    3128         693 :   phi = cgetg(4, t_VEC);
    3129             : 
    3130         693 :   phi0 = cgetg(6, t_VEC);
    3131         693 :   gel(phi0, 1) = utoi(538141968);
    3132         693 :   gel(phi0, 2) = utoi(19712160);
    3133         693 :   gel(phi0, 3) = utoi(193752);
    3134         693 :   gel(phi0, 4) = utoi(744);
    3135         693 :   gel(phi0, 5) = gen_1;
    3136             : 
    3137         693 :   phi1 = cgetg(5, t_VEC);
    3138         693 :   gel(phi1, 1) = utoi(24528);
    3139         693 :   gel(phi1, 2) = utoi(2348);
    3140         693 :   gel(phi1, 3) = gen_0;
    3141         693 :   gel(phi1, 4) = gen_m1;
    3142             : 
    3143         693 :   gel(phi, 1) = phi0;
    3144         693 :   gel(phi, 2) = phi1;
    3145         693 :   gel(phi, 3) = gen_0; return phi;
    3146             : }
    3147             : 
    3148             : static GEN
    3149         727 : phi_atkin5_j(void)
    3150             : {
    3151             :   GEN phi, phi0, phi1;
    3152         727 :   phi = cgetg(4, t_VEC);
    3153             : 
    3154         727 :   phi0 = cgetg(8, t_VEC);
    3155         727 :   gel(phi0, 1) = uu32toi(0xd,0x595d1000UL);
    3156         727 :   gel(phi0, 2) = uu32toi(0x2,0x935de800UL);
    3157         727 :   gel(phi0, 3) = utoi(756084480);
    3158         727 :   gel(phi0, 4) = utoi(20990720);
    3159         727 :   gel(phi0, 5) = utoi(196080);
    3160         727 :   gel(phi0, 6) = utoi(744);
    3161         728 :   gel(phi0, 7) = gen_1;
    3162             : 
    3163         728 :   phi1 = cgetg(7, t_VEC);
    3164         728 :   gel(phi1, 1) = utoineg(449408);
    3165         728 :   gel(phi1, 2) = utoineg(73056);
    3166         728 :   gel(phi1, 3) = utoi(3800);
    3167         727 :   gel(phi1, 4) = utoi(670);
    3168         726 :   gel(phi1, 5) = gen_0;
    3169         726 :   gel(phi1, 6) = gen_m1;
    3170             : 
    3171         726 :   gel(phi, 1) = phi0;
    3172         726 :   gel(phi, 2) = phi1;
    3173         726 :   gel(phi, 3) = gen_0; return phi;
    3174             : }
    3175             : 
    3176             : static GEN
    3177          70 : phi_atkin7_j(void)
    3178             : {
    3179             :   GEN phi, phi0, phi1;
    3180          70 :   phi = cgetg(4, t_VEC);
    3181             : 
    3182          70 :   phi0 = cgetg(10, t_VEC);
    3183          70 :   gel(phi0, 1) = uu32toi(0x136,0xe07f9221UL);
    3184          70 :   gel(phi0, 2) = uu32toi(0x9d,0xc4224ba8UL);
    3185          70 :   gel(phi0, 3) = uu32toi(0x20,0x58246d3cUL);
    3186          70 :   gel(phi0, 4) = uu32toi(0x3,0x631e2dd8UL);
    3187          70 :   gel(phi0, 5) = utoi(803037606);
    3188          70 :   gel(phi0, 6) = utoi(21226520);
    3189          70 :   gel(phi0, 7) = utoi(196476);
    3190          70 :   gel(phi0, 8) = utoi(744);
    3191          70 :   gel(phi0, 9) = gen_1;
    3192             : 
    3193          70 :   phi1 = cgetg(9, t_VEC);
    3194          70 :   gel(phi1, 1) = utoi(2128500);
    3195          70 :   gel(phi1, 2) = utoi(186955);
    3196          70 :   gel(phi1, 3) = utoineg(204792);
    3197          70 :   gel(phi1, 4) = utoineg(31647);
    3198          70 :   gel(phi1, 5) = utoi(1428);
    3199          70 :   gel(phi1, 6) = utoi(357);
    3200          70 :   gel(phi1, 7) = gen_0;
    3201          70 :   gel(phi1, 8) = gen_m1;
    3202             : 
    3203          70 :   gel(phi, 1) = phi0;
    3204          70 :   gel(phi, 2) = phi1;
    3205          70 :   gel(phi, 3) = gen_0; return phi;
    3206             : }
    3207             : 
    3208             : static GEN
    3209           0 : phi_atkin11_j(void)
    3210             : {
    3211             :   GEN phi, phi0, phi1;
    3212           0 :   phi = cgetg(4, t_VEC);
    3213             : 
    3214           0 :   phi0 = cgetg(14, t_VEC);
    3215           0 :   gel(phi0, 1) = uu32toi(0x351f,0xe3329000);
    3216           0 :   gel(phi0, 2) = uu32toi(0x5a09,0xb4cae000);
    3217           0 :   gel(phi0, 3) = uu32toi(0x4386,0xeec9c800);
    3218           0 :   gel(phi0, 4) = uu32toi(0x1d6c,0x110f8800);
    3219           0 :   gel(phi0, 5) = uu32toi(0x836,0xd0d89f00);
    3220           0 :   gel(phi0, 6) = uu32toi(0x186,0xd34d0c00);
    3221           0 :   gel(phi0, 7) = uu32toi(0x30,0x8f70b700);
    3222           0 :   gel(phi0, 8) = uu32toi(0x3,0xedd91100);
    3223           0 :   gel(phi0, 9) = utoi(830467440);
    3224           0 :   gel(phi0, 10) = utoi(21354080);
    3225           0 :   gel(phi0, 11) = utoi(196680);
    3226           0 :   gel(phi0, 12) = utoi(744);
    3227           0 :   gel(phi0, 13) = gen_1;
    3228             : 
    3229           0 :   phi1 = cgetg(13, t_VEC);
    3230           0 :   gel(phi1, 1) = utoineg(8720000);
    3231           0 :   gel(phi1, 2) = utoineg(19849600);
    3232           0 :   gel(phi1, 3) = utoineg(8252640);
    3233           0 :   gel(phi1, 4) = utoi(1867712);
    3234           0 :   gel(phi1, 5) = utoi(1675784);
    3235           0 :   gel(phi1, 6) = utoi(184184);
    3236           0 :   gel(phi1, 7) = utoineg(57442);
    3237           0 :   gel(phi1, 8) = utoineg(11440);
    3238           0 :   gel(phi1, 9) = utoi(506);
    3239           0 :   gel(phi1, 10) = utoi(187);
    3240           0 :   gel(phi1, 11) = gen_0;
    3241           0 :   gel(phi1, 12) = gen_m1;
    3242             : 
    3243           0 :   gel(phi, 1) = phi0;
    3244           0 :   gel(phi, 2) = phi1;
    3245           0 :   gel(phi, 3) = gen_0; return phi;
    3246             : }
    3247             : 
    3248             : static GEN
    3249        1119 : phi_atkin13_j(void)
    3250             : {
    3251             :   GEN phi, phi0, phi1;
    3252        1119 :   phi = cgetg(4, t_VEC);
    3253             : 
    3254        1119 :   phi0 = cgetg(16, t_VEC);
    3255        1119 :   gel(phi0, 1) = uu32toi(0x8954,0x40000000);
    3256        1120 :   gel(phi0, 2) = uu32toi(0x169eb,0x5e000000);
    3257        1120 :   gel(phi0, 3) = uu32toi(0x1ae7f,0x36e00000);
    3258        1120 :   gel(phi0, 4) = uu32toi(0x13107,0x840d8000);
    3259        1120 :   gel(phi0, 5) = uu32toi(0x8f0a,0xa4ccb800);
    3260        1120 :   gel(phi0, 6) = uu32toi(0x2e9f,0x7cfb8de0);
    3261        1120 :   gel(phi0, 7) = uu32toi(0xac8,0xedcc81b1);
    3262        1120 :   gel(phi0, 8) = uu32toi(0x1c6,0x36bee68);
    3263        1120 :   gel(phi0, 9) = uu32toi(0x34,0x377ed40c);
    3264        1120 :   gel(phi0, 10) = uu32toi(0x4,0xa132b38);
    3265        1120 :   gel(phi0, 11) = utoi(835688022);
    3266        1120 :   gel(phi0, 12) = utoi(21377304);
    3267        1120 :   gel(phi0, 13) = utoi(196716);
    3268        1120 :   gel(phi0, 14) = utoi(744);
    3269        1120 :   gel(phi0, 15) = gen_1;
    3270             : 
    3271        1120 :   phi1 = cgetg(15, t_VEC);
    3272        1120 :   gel(phi1, 1) = utoi(24576000);
    3273        1120 :   gel(phi1, 2) = utoi(32384000);
    3274        1120 :   gel(phi1, 3) = utoineg(5859360);
    3275        1120 :   gel(phi1, 4) = utoineg(23669490);
    3276        1120 :   gel(phi1, 5) = utoineg(9614956);
    3277        1120 :   gel(phi1, 6) = utoi(700323);
    3278        1120 :   gel(phi1, 7) = utoi(1161420);
    3279        1120 :   gel(phi1, 8) = utoi(149786);
    3280        1120 :   gel(phi1, 9) = utoineg(37596);
    3281        1120 :   gel(phi1, 10) = utoineg(8502);
    3282        1120 :   gel(phi1, 11) = utoi(364);
    3283        1120 :   gel(phi1, 12) = utoi(156);
    3284        1120 :   gel(phi1, 13) = gen_0;
    3285        1120 :   gel(phi1, 14) = gen_m1;
    3286             : 
    3287        1120 :   gel(phi, 1) = phi0;
    3288        1120 :   gel(phi, 2) = phi1;
    3289        1120 :   gel(phi, 3) = gen_0; return phi;
    3290             : }
    3291             : 
    3292             : static GEN
    3293        1119 : phi_atkin17_j(void)
    3294             : {
    3295             :   GEN phi, phi0, phi1;
    3296        1119 :   phi = cgetg(4, t_VEC);
    3297             : 
    3298        1119 :   phi0 = cgetg(20, t_VEC);
    3299        1119 :   gel(phi0, 1) = uu32toi(0x1657c,0x54a85640);
    3300        1119 :   gel(phi0, 2) = uu32toi(0x700a8,0xf0f3e240);
    3301        1119 :   gel(phi0, 3) = uu32toi(0x104ffa,0x16a394f0);
    3302        1120 :   gel(phi0, 4) = uu32toi(0x176924,0x252cada0);
    3303        1120 :   gel(phi0, 5) = uu32toi(0x172465,0xa95c437c);
    3304        1120 :   gel(phi0, 6) = uu32toi(0x10afa6,0x44a03d44);
    3305        1120 :   gel(phi0, 7) = uu32toi(0x90fff,0xc76052b1);
    3306        1120 :   gel(phi0, 8) = uu32toi(0x3c625,0x26e00dfc);
    3307        1120 :   gel(phi0, 9) = uu32toi(0x136f3,0xc7587fe);
    3308        1120 :   gel(phi0, 10) = uu32toi(0x4d55,0x39993e90);
    3309        1120 :   gel(phi0, 11) = uu32toi(0xebe,0x56879c1f);
    3310        1120 :   gel(phi0, 12) = uu32toi(0x21e,0x4cf30138);
    3311        1120 :   gel(phi0, 13) = uu32toi(0x39,0x6108ad0);
    3312        1120 :   gel(phi0, 14) = uu32toi(0x4,0x2dd68d04);
    3313        1120 :   gel(phi0, 15) = utoi(842077983);
    3314        1120 :   gel(phi0, 16) = utoi(21404972);
    3315        1120 :   gel(phi0, 17) = utoi(196758);
    3316        1120 :   gel(phi0, 18) = utoi(744);
    3317        1120 :   gel(phi0, 19) = gen_1;
    3318             : 
    3319        1120 :   phi1 = cgetg(19, t_VEC);
    3320        1120 :   gel(phi1, 1) = utoineg(25608112);
    3321        1120 :   gel(phi1, 2) = utoineg(128884056);
    3322        1120 :   gel(phi1, 3) = utoineg(169635044);
    3323        1120 :   gel(phi1, 4) = utoineg(18738794);
    3324        1120 :   gel(phi1, 5) = utoi(125706976);
    3325        1120 :   gel(phi1, 6) = utoi(98725154);
    3326        1120 :   gel(phi1, 7) = utoi(13049914);
    3327        1120 :   gel(phi1, 8) = utoineg(16023299);
    3328        1120 :   gel(phi1, 9) = utoineg(7118240);
    3329        1120 :   gel(phi1, 10) = utoi(70737);
    3330        1120 :   gel(phi1, 11) = utoi(630836);
    3331        1120 :   gel(phi1, 12) = utoi(91766);
    3332        1120 :   gel(phi1, 13) = utoineg(20808);
    3333        1120 :   gel(phi1, 14) = utoineg(5338);
    3334        1120 :   gel(phi1, 15) = utoi(238);
    3335        1120 :   gel(phi1, 16) = utoi(119);
    3336        1120 :   gel(phi1, 17) = gen_0;
    3337        1120 :   gel(phi1, 18) = gen_m1;
    3338             : 
    3339        1120 :   gel(phi, 1) = phi0;
    3340        1120 :   gel(phi, 2) = phi1;
    3341        1120 :   gel(phi, 3) = gen_0; return phi;
    3342             : }
    3343             : 
    3344             : static GEN
    3345        1073 : phi_atkin19_j(void)
    3346             : {
    3347             :   GEN phi, phi0, phi1;
    3348        1073 :   phi = cgetg(4, t_VEC);
    3349             : 
    3350        1073 :   phi0 = cgetg(22, t_VEC);
    3351        1073 :   gel(phi0, 1) = uu32toi(0x8954,0x40000000);
    3352        1073 :   gel(phi0, 2) = uu32toi(0x3f55f,0xd4000000);
    3353        1073 :   gel(phi0, 3) = uu32toi(0xd919c,0xfec00000);
    3354        1073 :   gel(phi0, 4) = uu32toi(0x1caf6f,0x559c0000);
    3355        1073 :   gel(phi0, 5) = uu32toi(0x29e098,0x33660000);
    3356        1073 :   gel(phi0, 6) = uu32toi(0x2ccab4,0x9d840000);
    3357        1073 :   gel(phi0, 7) = uu32toi(0x2456c7,0x80a1b000);
    3358        1073 :   gel(phi0, 8) = uu32toi(0x16d60a,0xd745d000);
    3359        1073 :   gel(phi0, 9) = uu32toi(0xb4073,0xd4d99000);
    3360        1073 :   gel(phi0, 10) = uu32toi(0x45efb,0xfafc9940);
    3361        1073 :   gel(phi0, 11) = uu32toi(0x156b5,0xc5077760);
    3362        1073 :   gel(phi0, 12) = uu32toi(0x524a,0x36e3a250);
    3363        1073 :   gel(phi0, 13) = uu32toi(0xf4f,0x2f2d5961);
    3364        1073 :   gel(phi0, 14) = uu32toi(0x229,0xdaeee798);
    3365        1073 :   gel(phi0, 15) = uu32toi(0x39,0x9e6319bc);
    3366        1073 :   gel(phi0, 16) = uu32toi(0x4,0x322f8d88);
    3367        1073 :   gel(phi0, 17) = utoi(842900838);
    3368        1073 :   gel(phi0, 18) = utoi(21408744);
    3369        1073 :   gel(phi0, 19) = utoi(196764);
    3370        1073 :   gel(phi0, 20) = utoi(744);
    3371        1073 :   gel(phi0, 21) = gen_1;
    3372             : 
    3373        1073 :   phi1 = cgetg(21, t_VEC);
    3374        1073 :   gel(phi1, 1) = utoi(24576000);
    3375        1073 :   gel(phi1, 2) = utoi(90675200);
    3376        1073 :   gel(phi1, 3) = utoi(51363840);
    3377        1073 :   gel(phi1, 4) = utoineg(196605312);
    3378        1073 :   gel(phi1, 5) = utoineg(358921248);
    3379        1073 :   gel(phi1, 6) = utoineg(190349904);
    3380        1073 :   gel(phi1, 7) = utoi(54954270);
    3381        1073 :   gel(phi1, 8) = utoi(101838024);
    3382        1073 :   gel(phi1, 9) = utoi(30202704);
    3383        1073 :   gel(phi1, 10) = utoineg(9356265);
    3384        1073 :   gel(phi1, 11) = utoineg(6935646);
    3385        1073 :   gel(phi1, 12) = utoineg(444030);
    3386        1073 :   gel(phi1, 13) = utoi(519042);
    3387        1073 :   gel(phi1, 14) = utoi(97983);
    3388        1073 :   gel(phi1, 15) = utoineg(16416);
    3389        1073 :   gel(phi1, 16) = utoineg(5073);
    3390        1073 :   gel(phi1, 17) = utoi(190);
    3391        1073 :   gel(phi1, 18) = utoi(114);
    3392        1073 :   gel(phi1, 19) = gen_0;
    3393        1073 :   gel(phi1, 20) = gen_m1;
    3394             : 
    3395        1073 :   gel(phi, 1) = phi0;
    3396        1073 :   gel(phi, 2) = phi1;
    3397        1073 :   gel(phi, 3) = gen_0; return phi;
    3398             : }
    3399             : 
    3400             : static GEN
    3401        1883 : phi_atkin23_j(void)
    3402             : {
    3403             :   GEN phi, phi0, phi1;
    3404        1883 :   phi = cgetg(4, t_VEC);
    3405             : 
    3406        1883 :   phi0 = cgetg(26, t_VEC);
    3407        1883 :   gel(phi0, 1) = utoi(1073741824);
    3408        1883 :   gel(phi0, 2) = uu32toi(0x3,0xf0000000);
    3409        1883 :   gel(phi0, 3) = uu32toi(0x1e,0x30000000);
    3410        1883 :   gel(phi0, 4) = uu32toi(0x95,0x97000000);
    3411        1883 :   gel(phi0, 5) = uu32toi(0x218,0xa3000000);
    3412        1883 :   gel(phi0, 6) = uu32toi(0x5c7,0x5f700000);
    3413        1883 :   gel(phi0, 7) = uu32toi(0xcaf,0xfac0000);
    3414        1883 :   gel(phi0, 8) = uu32toi(0x16aa,0x3900000);
    3415        1883 :   gel(phi0, 9) = uu32toi(0x216f,0x69d20000);
    3416        1883 :   gel(phi0, 10) = uu32toi(0x2911,0x5ada0000);
    3417        1883 :   gel(phi0, 11) = uu32toi(0x2a2c,0x744d0000);
    3418        1883 :   gel(phi0, 12) = uu32toi(0x243b,0xc40d8000);
    3419        1883 :   gel(phi0, 13) = uu32toi(0x19fa,0x68c53000);
    3420        1883 :   gel(phi0, 14) = uu32toi(0xf74,0x41e0c000);
    3421        1883 :   gel(phi0, 15) = uu32toi(0x78e,0xa9057000);
    3422        1883 :   gel(phi0, 16) = uu32toi(0x2ff,0x6f4f000);
    3423        1883 :   gel(phi0, 17) = uu32toi(0xf1,0xb1e5a000);
    3424        1883 :   gel(phi0, 18) = uu32toi(0x3a,0xd0793f00);
    3425        1883 :   gel(phi0, 19) = uu32toi(0xa,0x97960840);
    3426        1883 :   gel(phi0, 20) = uu32toi(0x1,0x52727000);
    3427        1883 :   gel(phi0, 21) = utoi(441081120);
    3428        1883 :   gel(phi0, 22) = utoi(17282016);
    3429        1883 :   gel(phi0, 23) = utoi(179952);
    3430        1883 :   gel(phi0, 24) = utoi(720);
    3431        1883 :   gel(phi0, 25) = gen_1;
    3432             : 
    3433        1883 :   phi1 = cgetg(25, t_VEC);
    3434        1883 :   gel(phi1, 1) = utoi(65536);
    3435        1883 :   gel(phi1, 2) = utoi(516096);
    3436        1883 :   gel(phi1, 3) = utoi(1648640);
    3437        1883 :   gel(phi1, 4) = utoi(2213888);
    3438        1883 :   gel(phi1, 5) = utoineg(1554432);
    3439        1883 :   gel(phi1, 6) = utoineg(11787776);
    3440        1883 :   gel(phi1, 7) = utoineg(21906304);
    3441        1883 :   gel(phi1, 8) = utoineg(19783680);
    3442        1883 :   gel(phi1, 9) = utoineg(3833824);
    3443        1883 :   gel(phi1, 10) = utoi(11002464);
    3444        1883 :   gel(phi1, 11) = utoi(11625488);
    3445        1883 :   gel(phi1, 12) = utoi(2882544);
    3446        1883 :   gel(phi1, 13) = utoineg(2689666);
    3447        1883 :   gel(phi1, 14) = utoineg(1978368);
    3448        1883 :   gel(phi1, 15) = utoi(19136);
    3449        1883 :   gel(phi1, 16) = utoi(393024);
    3450        1883 :   gel(phi1, 17) = utoi(53084);
    3451        1883 :   gel(phi1, 18) = utoineg(46644);
    3452        1883 :   gel(phi1, 19) = utoineg(5681);
    3453        1883 :   gel(phi1, 20) = utoi(3864);
    3454        1883 :   gel(phi1, 21) = gen_0;
    3455        1883 :   gel(phi1, 22) = utoineg(161);
    3456        1883 :   gel(phi1, 23) = utoi(23);
    3457        1883 :   gel(phi1, 24) = gen_m1;
    3458             : 
    3459        1883 :   gel(phi, 1) = phi0;
    3460        1883 :   gel(phi, 2) = phi1;
    3461        1883 :   gel(phi, 3) = gen_0; return phi;
    3462             : }
    3463             : 
    3464             : static GEN
    3465        3858 : phi_atkin29_j(void)
    3466             : {
    3467             :   GEN phi, phi0, phi1;
    3468        3858 :   phi = cgetg(4, t_VEC);
    3469             : 
    3470        3858 :   phi0 = cgetg(32, t_VEC);
    3471        3858 :   gel(phi0, 1) = utoi(11390625);
    3472        3858 :   gel(phi0, 2) = utoi(41006250);
    3473        3858 :   gel(phi0, 3) = utoi(118918125);
    3474        3858 :   gel(phi0, 4) = utoi(73993500);
    3475        3859 :   gel(phi0, 5) = utoineg(591595650);
    3476        3859 :   gel(phi0, 6) = utoineg(2067026040);
    3477        3858 :   gel(phi0, 7) = utoineg(3310173216);
    3478        3858 :   gel(phi0, 8) = utoi(1339615908);
    3479        3858 :   gel(phi0, 9) = uu32toi(0x4,0x1bdea49);
    3480        3858 :   gel(phi0, 10) = uu32toi(0x7,0x4588df8a);
    3481        3858 :   gel(phi0, 11) = uu32toi(0x2,0x76591fcf);
    3482        3859 :   gel(phi0, 12) = uu32toineg(0x10,0xa19368b8);
    3483        3858 :   gel(phi0, 13) = uu32toineg(0x25,0x583f669);
    3484        3858 :   gel(phi0, 14) = uu32toineg(0x12,0x2b9ec67e);
    3485        3858 :   gel(phi0, 15) = uu32toi(0x31,0x939eef85);
    3486        3858 :   gel(phi0, 16) = uu32toi(0x5b,0x174f9444);
    3487        3858 :   gel(phi0, 17) = uu32toi(0x23,0xe0a92fdd);
    3488        3859 :   gel(phi0, 18) = uu32toineg(0x40,0xed23b2fe);
    3489        3859 :   gel(phi0, 19) = uu32toineg(0x65,0x35e74a61);
    3490        3859 :   gel(phi0, 20) = uu32toineg(0x31,0xc9fb3f18);
    3491        3859 :   gel(phi0, 21) = uu32toi(0x12,0x72304077);
    3492        3859 :   gel(phi0, 22) = uu32toi(0x2c,0xf570520a);
    3493        3859 :   gel(phi0, 23) = uu32toi(0x21,0xef31d011);
    3494        3859 :   gel(phi0, 24) = uu32toi(0xf,0x2daf2ec4);
    3495        3859 :   gel(phi0, 25) = uu32toi(0x4,0x598183a8);
    3496        3859 :   gel(phi0, 26) = utoi(3339922344);
    3497        3859 :   gel(phi0, 27) = utoi(340795182);
    3498        3859 :   gel(phi0, 28) = utoi(16216684);
    3499        3859 :   gel(phi0, 29) = utoi(175653);
    3500        3859 :   gel(phi0, 30) = utoi(714);
    3501        3859 :   gel(phi0, 31) = gen_1;
    3502             : 
    3503        3859 :   phi1 = cgetg(31, t_VEC);
    3504        3859 :   gel(phi1, 1) = utoi(6750);
    3505        3859 :   gel(phi1, 2) = utoi(12150);
    3506        3859 :   gel(phi1, 3) = utoineg(281880);
    3507        3859 :   gel(phi1, 4) = utoineg(570024);
    3508        3859 :   gel(phi1, 5) = utoi(1754181);
    3509        3859 :   gel(phi1, 6) = utoi(5229135);
    3510        3859 :   gel(phi1, 7) = utoineg(2357613);
    3511        3859 :   gel(phi1, 8) = utoineg(19103721);
    3512        3859 :   gel(phi1, 9) = utoineg(9708910);
    3513        3859 :   gel(phi1, 10) = utoi(31795426);
    3514        3859 :   gel(phi1, 11) = utoi(38397537);
    3515        3859 :   gel(phi1, 12) = utoineg(19207947);
    3516        3859 :   gel(phi1, 13) = utoineg(54103270);
    3517        3859 :   gel(phi1, 14) = utoineg(9216142);
    3518        3859 :   gel(phi1, 15) = utoi(37142939);
    3519        3859 :   gel(phi1, 16) = utoi(18871083);
    3520        3859 :   gel(phi1, 17) = utoineg(14041394);
    3521        3859 :   gel(phi1, 18) = utoineg(10954634);
    3522        3859 :   gel(phi1, 19) = utoi(3592085);
    3523        3859 :   gel(phi1, 20) = utoi(3427365);
    3524        3859 :   gel(phi1, 21) = utoineg(853818);
    3525        3859 :   gel(phi1, 22) = utoineg(622398);
    3526        3859 :   gel(phi1, 23) = utoi(189399);
    3527        3859 :   gel(phi1, 24) = utoi(53679);
    3528        3859 :   gel(phi1, 25) = utoineg(26680);
    3529        3859 :   gel(phi1, 26) = utoi(580);
    3530        3859 :   gel(phi1, 27) = utoi(1421);
    3531        3859 :   gel(phi1, 28) = utoineg(319);
    3532        3859 :   gel(phi1, 29) = utoi(29);
    3533        3859 :   gel(phi1, 30) = gen_m1;
    3534             : 
    3535        3859 :   gel(phi, 1) = phi0;
    3536        3859 :   gel(phi, 2) = phi1;
    3537        3859 :   gel(phi, 3) = gen_0; return phi;
    3538             : }
    3539             : 
    3540             : GEN
    3541       34609 : double_eta_raw(long inv)
    3542             : {
    3543       34609 :   switch (inv) {
    3544        1060 :     case INV_W2W3:
    3545        1060 :     case INV_W2W3E2: return phi_w2w3_j();
    3546        3608 :     case INV_W3W3:
    3547        3608 :     case INV_W3W3E2: return phi_w3w3_j();
    3548        2927 :     case INV_W2W5:
    3549        2927 :     case INV_W2W5E2: return phi_w2w5_j();
    3550        6628 :     case INV_W2W7:
    3551        6628 :     case INV_W2W7E2: return phi_w2w7_j();
    3552        1160 :     case INV_W3W5:   return phi_w3w5_j();
    3553        2986 :     case INV_W3W7:   return phi_w3w7_j();
    3554        2157 :     case INV_W2W13:  return phi_w2w13_j();
    3555         210 :     case INV_W3W13:  return phi_w3w13_j();
    3556        3331 :     case INV_W5W7:   return phi_w5w7_j();
    3557         693 :     case INV_ATKIN3: return phi_atkin3_j();
    3558         727 :     case INV_ATKIN5: return phi_atkin5_j();
    3559          70 :     case INV_ATKIN7: return phi_atkin7_j();
    3560           0 :     case INV_ATKIN11: return phi_atkin11_j();
    3561        1119 :     case INV_ATKIN13: return phi_atkin13_j();
    3562        1119 :     case INV_ATKIN17: return phi_atkin17_j();
    3563        1073 :     case INV_ATKIN19: return phi_atkin19_j();
    3564        1883 :     case INV_ATKIN23: return phi_atkin23_j();
    3565        3858 :     case INV_ATKIN29: return phi_atkin29_j();
    3566             :     default: pari_err_BUG("double_eta_raw"); return NULL;/*LCOV_EXCL_LINE*/
    3567             :   }
    3568             : }
    3569             : 
    3570             : /* SECTION: Select discriminant for given modpoly level. */
    3571             : 
    3572             : /* require an L1, useful for multi-threading */
    3573             : #define MODPOLY_USE_L1    1
    3574             : /* no bound on L1 other than the fixed bound MAX_L1 - needed to
    3575             :  * handle small L for certain invariants (but not for j) */
    3576             : #define MODPOLY_NO_MAX_L1 2
    3577             : /* don't use any auxilliary primes - needed to handle small L for
    3578             :  * certain invariants (but not for j) */
    3579             : #define MODPOLY_NO_AUX_L  4
    3580             : #define MODPOLY_IGNORE_SPARSE_FACTOR 8
    3581             : 
    3582             : INLINE double
    3583        3226 : modpoly_height_bound(long L, long inv)
    3584             : {
    3585             :   double nbits, nbits2;
    3586             :   double c;
    3587             :   long hf;
    3588             : 
    3589             :   /* proven bound (in bits), derived from: 6l*log(l)+16*l+13*sqrt(l)*log(l) */
    3590        3226 :   nbits = 6.0*L*log2(L)+16/M_LN2*L+8.0*sqrt((double)L)*log2(L);
    3591             :   /* alternative proven bound (in bits), derived from: 6l*log(l)+17*l */
    3592        3226 :   nbits2 = 6.0*L*log2(L)+17/M_LN2*L;
    3593        3226 :   if ( nbits2 < nbits ) nbits = nbits2;
    3594        3226 :   hf = modinv_height_factor(inv);
    3595        3226 :   if (hf > 1) {
    3596             :    /* IMPORTANT: when dividing by the height factor, we only want to reduce
    3597             :    terms related to the bound on j (the roots of Phi_l(X,y)), not terms arising
    3598             :    from binomial coefficients. These arise in lemmas 2 and 3 of the height
    3599             :    bound paper, terms of (log 2)*L and 2.085*(L+1) which we convert here to
    3600             :    binary logs */
    3601             :     /* Massive overestimate: if you care about speed, determine a good height
    3602             :      * bound empirically as done for INV_F below */
    3603        1802 :     nbits2 = nbits - 4.01*L -3.0;
    3604        1802 :     nbits = nbits2/hf + 4.01*L + 3.0;
    3605             :   }
    3606        3226 :   if (inv == INV_F) {
    3607         142 :     if (L < 30) c = 45;
    3608          35 :     else if (L < 100) c = 36;
    3609          21 :     else if (L < 300) c = 32;
    3610           7 :     else if (L < 600) c = 26;
    3611           0 :     else if (L < 1200) c = 24;
    3612           0 :     else if (L < 2400) c = 22;
    3613           0 :     else c = 20;
    3614         142 :     nbits = (6.0*L*log2(L) + c*L)/hf;
    3615             :   }
    3616        3226 :   return nbits;
    3617             : }
    3618             : 
    3619             : /* small enough to write the factorization of a smooth in a BIL bit integer */
    3620             : #define SMOOTH_PRIMES  ((BITS_IN_LONG >> 1) - 1)
    3621             : 
    3622             : #define MAX_ATKIN 255
    3623             : 
    3624             : #define MAX_L1      255
    3625             : 
    3626             : typedef struct D_entry_struct {
    3627             :   ulong m;
    3628             :   long D, h;
    3629             : } D_entry;
    3630             : 
    3631             : /* Returns a form that generates the classes of norm p^2 in cl(p^2D)
    3632             :  * (i.e. one with order p-1), where p is an odd prime that splits in D
    3633             :  * and does not divide its conductor (but this is not verified) */
    3634             : INLINE GEN
    3635       86991 : qform_primeform2(long p, long D)
    3636             : {
    3637       86991 :   GEN a = sqru(p), Dp2 = mulis(a, D), M = Z_factor(utoipos(p - 1));
    3638       86991 :   pari_sp av = avma;
    3639             :   long k;
    3640             : 
    3641      176246 :   for (k = D & 1; k <= p; k += 2)
    3642             :   {
    3643      176246 :     long ord, c = (k * k - D) / 4;
    3644             :     GEN Q, q;
    3645             : 
    3646      176246 :     if (!(c % p)) continue;
    3647      152847 :     q = mkqfis(a, k * p, c, Dp2); Q = qfi_red(q);
    3648             :     /* TODO: How do we know that Q has order dividing p - 1? If we don't, then
    3649             :      * the call to gen_order should be replaced with a call to something with
    3650             :      * fastorder semantics (i.e. return 0 if ord(Q) \ndiv M). */
    3651      152847 :     ord = itos(qfi_order(Q, M));
    3652      152847 :     if (ord == p - 1) {
    3653             :       /* TODO: This check that gen_order returned the correct result should be
    3654             :        * removed when gen_order is replaced with fastorder semantics. */
    3655       86991 :       if (qfb_equal1(gpowgs(Q, p - 1))) return q;
    3656           0 :       break;
    3657             :     }
    3658       65856 :     set_avma(av);
    3659             :   }
    3660           0 :   return NULL;
    3661             : }
    3662             : 
    3663             : /* Let n = #cl(D); return x such that [L0]^x = [L] in cl(D), or -1 if x was
    3664             :  * not found */
    3665             : INLINE long
    3666      211978 : primeform_discrete_log(long L0, long L, long n, long D)
    3667             : {
    3668      211978 :   pari_sp av = avma;
    3669      211978 :   GEN X, Q, R, DD = stoi(D);
    3670      211978 :   Q = primeform_u(DD, L0);
    3671      211978 :   R = primeform_u(DD, L);
    3672      211978 :   X = qfi_Shanks(R, Q, n);
    3673      211978 :   return gc_long(av, X? itos(X): -1);
    3674             : }
    3675             : 
    3676             : /* Return the norm of a class group generator appropriate for a discriminant
    3677             :  * that will be used to calculate the modular polynomial of level L and
    3678             :  * invariant inv.  Don't consider norms less than initial_L0 */
    3679             : static long
    3680        3226 : select_L0(long L, long inv, long initial_L0)
    3681             : {
    3682        3226 :   long L0, modinv_N = modinv_level(inv);
    3683             : 
    3684        3226 :   if (modinv_N % L == 0) pari_err_BUG("select_L0");
    3685             : 
    3686             :   /* TODO: Clean up these anomolous L0 choices */
    3687             : 
    3688             :   /* I've no idea why the discriminant-finding code fails with L0=5
    3689             :    * when L=19 and L=29, nor why L0=7 and L0=11 don't work for L=19
    3690             :    * either, nor why this happens for the otherwise unrelated
    3691             :    * invariants Weber-f and (2,3) double-eta. */
    3692             : 
    3693        3226 :   if (inv == INV_F || inv == INV_F2 || inv == INV_F4 || inv == INV_F8
    3694        2972 :       || inv == INV_W2W3 || inv == INV_W2W3E2
    3695        2909 :       || inv == INV_W3W3) {
    3696         422 :     if (L == 19) return 13;
    3697         372 :     else if (L == 29) return 7;
    3698             :   }
    3699        3169 :   if ((inv == INV_W2W5) && (L == 19)) return 13;
    3700        3155 :   if ((inv == INV_W2W5E2)
    3701          49 :       && (L == 7 || L == 19)) return 13;
    3702        3134 :   if ((inv == INV_W2W7 || inv == INV_W2W7E2)
    3703         358 :       && L == 11) return 13;
    3704        3106 :   if (inv == INV_W3W5) {
    3705          63 :     if (L == 7) return 13;
    3706          56 :     else if (L == 17) return 7;
    3707             :   }
    3708        3099 :   if (inv == INV_W3W7) {
    3709         161 :     if (L == 29 || L == 101) return 11;
    3710         133 :     if (L == 11 || L == 19) return 13;
    3711             :   }
    3712             : 
    3713             :   /* L0 = smallest small prime different from L that doesn't divide modinv_N */
    3714        3036 :   for (L0 = unextprime(initial_L0 + 1);
    3715        4754 :        L0 == L || modinv_N % L0 == 0;
    3716        1718 :        L0 = unextprime(L0 + 1))
    3717             :     ;
    3718        3036 :   return L0;
    3719             : }
    3720             : 
    3721             : /* Return the order of [L]^n in cl(D), where #cl(D) = ord. */
    3722             : INLINE long
    3723     1116787 : primeform_exp_order(long L, long n, long D, long ord)
    3724             : {
    3725     1116787 :   pari_sp av = avma;
    3726     1116787 :   GEN Q = gpowgs(primeform_u(stoi(D), L), n);
    3727     1116787 :   long m = itos(qfi_order(Q, Z_factor(stoi(ord))));
    3728     1116787 :   return gc_long(av,m);
    3729             : }
    3730             : 
    3731             : /* If an ideal of norm modinv_deg is equivalent to an ideal of norm L0, we
    3732             :  * have an orientation ambiguity that we need to avoid. Note that we need to
    3733             :  * check all the possibilities (up to 8), but we can cheaply check inverses
    3734             :  * (so at most 2) */
    3735             : static long
    3736       48746 : orientation_ambiguity(long D1, long L0, long modinv_p1, long modinv_p2, long modinv_N)
    3737             : {
    3738       48746 :   pari_sp av = avma;
    3739       48746 :   long ambiguity = 0;
    3740       48746 :   GEN Q1 = red_primeform(D1, modinv_p1), Q2 = NULL;
    3741             : 
    3742       48746 :   if (modinv_p2 > 1)
    3743             :   {
    3744       33983 :     if (modinv_p1 == modinv_p2) Q1 = qfbsqr(Q1);
    3745             :     else
    3746             :     {
    3747       27453 :       GEN P2 = red_primeform(D1, modinv_p2);
    3748       27453 :       GEN Q = qfbsqr(P2), R = qfbsqr(Q1);
    3749             :       /* check that p1^2 != p2^{+/-2}, since this leads to
    3750             :        * ambiguities when converting j's to f's */
    3751       27453 :       if (equalii(gel(Q,1), gel(R,1)) && absequalii(gel(Q,2), gel(R,2)))
    3752             :       {
    3753           0 :         dbg_printf(3)("Bad D=%ld, a^2=b^2 problem between modinv_p1=%ld and modinv_p2=%ld\n",
    3754             :                       D1, modinv_p1, modinv_p2);
    3755           0 :         ambiguity = 1;
    3756             :       }
    3757             :       else
    3758             :       { /* generate both p1*p2 and p1*p2^{-1} */
    3759       27453 :         Q2 = qfbcomp(Q1, P2);
    3760       27453 :         P2 = ginv(P2);
    3761       27453 :         Q1 = qfbcomp(Q1, P2);
    3762             :       }
    3763             :     }
    3764             :   }
    3765       48746 :   if (!ambiguity)
    3766             :   {
    3767       48746 :     GEN P = qfbsqr(red_primeform(D1, L0));
    3768       48746 :     if (equalii(gel(P,1), gel(Q1,1))
    3769       47611 :         || (modinv_p2 > 1 && modinv_p1 != modinv_p2
    3770       26521 :                           && equalii(gel(P,1), gel(Q2,1)))) {
    3771        1648 :       dbg_printf(3)("Bad D=%ld, a=b^{+/-2} problem between modinv_N=%ld and L0=%ld\n",
    3772             :                     D1, modinv_N, L0);
    3773        1648 :       ambiguity = 1;
    3774             :     }
    3775             :   }
    3776       48746 :   return gc_long(av, ambiguity);
    3777             : }
    3778             : 
    3779             : static long
    3780      813798 : check_generators(
    3781             :   long *n1_, long *m_,
    3782             :   long D, long h, long n, long subgrp_sz, long L0, long L1)
    3783             : {
    3784      813798 :   long n1, m = primeform_exp_order(L0, n, D, h);
    3785      813798 :   if (m_) *m_ = m;
    3786      813798 :   n1 = n * m;
    3787      813798 :   if (!n1) pari_err_BUG("check_generators");
    3788      813798 :   *n1_ = n1;
    3789      813798 :   if (n1 < subgrp_sz/2 || ( ! L1 && n1 < subgrp_sz))  {
    3790       34044 :     dbg_printf(3)("Bad D1=%ld with n1=%ld, h1=%ld, L1=%ld: "
    3791             :                   "L0 and L1 don't span subgroup of size d in cl(D1)\n",
    3792             :                   D, n, h, L1);
    3793       34044 :     return 0;
    3794             :   }
    3795      779754 :   if (n1 < subgrp_sz && ! (n1 & 1)) {
    3796             :     int res;
    3797             :     /* check whether L1 is generated by L0, use the fact that it has order 2 */
    3798       22697 :     pari_sp av = avma;
    3799       22697 :     GEN D1 = stoi(D);
    3800       22697 :     GEN Q = gpowgs(primeform_u(D1, L0), n1 / 2);
    3801       22697 :     res = gequal(Q, qfi_red(primeform_u(D1, L1)));
    3802       22697 :     set_avma(av);
    3803       22697 :     if (res) {
    3804        6607 :       dbg_printf(3)("Bad D1=%ld, with n1=%ld, h1=%ld, L1=%ld: "
    3805             :                     "L1 generated by L0 in cl(D1)\n", D, n, h, L1);
    3806        6607 :       return 0;
    3807             :     }
    3808             :   }
    3809      773147 :   return 1;
    3810             : }
    3811             : 
    3812             : /* Calculate solutions (p, t) to the norm equation
    3813             :  *   4 p = t^2 - v^2 L^2 D   (*)
    3814             :  * corresponding to the descriminant described by Dinfo.
    3815             :  *
    3816             :  * INPUT:
    3817             :  * - max: length of primes and traces
    3818             :  * - xprimes: p to exclude from primes (if they arise)
    3819             :  * - xcnt: length of xprimes
    3820             :  * - minbits: sum of log2(p) must be larger than this
    3821             :  * - Dinfo: discriminant, invariant and L for which we seek solutions to (*)
    3822             :  *
    3823             :  * OUTPUT:
    3824             :  * - primes: array of p in (*)
    3825             :  * - traces: array of t in (*)
    3826             :  * - totbits: sum of log2(p) for p in primes.
    3827             :  *
    3828             :  * RETURN:
    3829             :  * - the number of primes and traces found (these are always the same).
    3830             :  *
    3831             :  * NOTE: primes and traces are both NULL or both non-NULL.
    3832             :  * xprimes can be zero, in which case it is treated as empty. */
    3833             : static long
    3834       12649 : modpoly_pickD_primes(
    3835             :   ulong *primes, ulong *traces, long max, ulong *xprimes, long xcnt,
    3836             :   long *totbits, long minbits, disc_info *Dinfo)
    3837             : {
    3838             :   double bits;
    3839             :   long D, m, n, vcnt, pfilter, one_prime, inv;
    3840             :   ulong maxp;
    3841             :   ulong a1, a2, v, t, p, a1_start, a1_delta, L0, L1, L, absD;
    3842       12649 :   ulong FF_BITS = BITS_IN_LONG - 2; /* BITS_IN_LONG - NAIL_BITS */
    3843             : 
    3844       12649 :   D = Dinfo->D1; absD = -D;
    3845       12649 :   L0 = Dinfo->L0;
    3846       12649 :   L1 = Dinfo->L1;
    3847       12649 :   L = Dinfo->L;
    3848       12649 :   inv = Dinfo->inv;
    3849             : 
    3850             :   /* make sure pfilter and D don't preclude the possibility of p=(t^2-v^2D)/4 being prime */
    3851       12649 :   pfilter = modinv_pfilter(inv);
    3852       12649 :   if ((pfilter & IQ_FILTER_1MOD3) && ! (D % 3)) return 0;
    3853       12614 :   if ((pfilter & IQ_FILTER_1MOD4) && ! (D & 0xF)) return 0;
    3854             : 
    3855             :   /* Naively estimate the number of primes satisfying 4p=t^2-L^2D with
    3856             :    * t=2 mod L and pfilter. This is roughly
    3857             :    * #{t: t^2 < max p and t=2 mod L} / pi(max p) * filter_density,
    3858             :    * where filter_density is 1, 2, or 4 depending on pfilter.  If this quantity
    3859             :    * is already more than twice the number of bits we need, assume that,
    3860             :    * barring some obstruction, we should have no problem getting enough primes.
    3861             :    * In this case we just verify we can get one prime (which should always be
    3862             :    * true, assuming we chose D properly). */
    3863       12614 :   one_prime = 0;
    3864       12614 :   *totbits = 0;
    3865       12614 :   if (max <= 1 && ! one_prime) {
    3866        9368 :     p = ((pfilter & IQ_FILTER_1MOD3) ? 2 : 1) * ((pfilter & IQ_FILTER_1MOD4) ? 2 : 1);
    3867        9368 :     one_prime = (1UL << ((FF_BITS+1)/2)) * (log2(L*L*(-D))-1)
    3868        9368 :         > p*L*minbits*FF_BITS*M_LN2;
    3869        9368 :     if (one_prime) *totbits = minbits+1;   /* lie */
    3870             :   }
    3871             : 
    3872       12614 :   m = n = 0;
    3873       12614 :   bits = 0.0;
    3874       12614 :   maxp = 0;
    3875       31941 :   for (v = 1; v < 100 && bits < minbits; v++) {
    3876             :     /* Don't allow v dividing the conductor. */
    3877       28478 :     if (ugcd(absD, v) != 1) continue;
    3878             :     /* Avoid v dividing the level. */
    3879       28172 :     if (v > 2 && modinv_is_double_eta(inv) && ugcd(modinv_level(inv), v) != 1)
    3880         953 :       continue;
    3881             :     /* can't get odd p with D=1 mod 8 unless v is even */
    3882       27219 :     if ((v & 1) && (D & 7) == 1) continue;
    3883             :     /* disallow 4 | v for L0=2 (removing this restriction is costly) */
    3884       13466 :     if (L0 == 2 && !(v & 3)) continue;
    3885             :     /* can't get p=3mod4 if v^2D is 0 mod 16 */
    3886       13088 :     if ((pfilter & IQ_FILTER_1MOD4) && !((v*v*D) & 0xF)) continue;
    3887       13005 :     if ((pfilter & IQ_FILTER_1MOD3) && !(v%3) ) continue;
    3888             :     /* avoid L0-volcanos with nonzero height */
    3889       12951 :     if (L0 != 2 && ! (v % L0)) continue;
    3890             :     /* ditto for L1 */
    3891       12930 :     if (L1 && !(v % L1)) continue;
    3892       12930 :     vcnt = 0;
    3893       12930 :     if ((v*v*absD)/4 > (1L<<FF_BITS)/(L*L)) break;
    3894       12847 :     if (both_odd(v,D)) {
    3895           0 :       a1_start = 1;
    3896           0 :       a1_delta = 2;
    3897             :     } else {
    3898       12847 :       a1_start = ((v*v*D) & 7)? 2: 0;
    3899       12847 :       a1_delta = 4;
    3900             :     }
    3901      687616 :     for (a1 = a1_start; bits < minbits; a1 += a1_delta) {
    3902      684167 :       a2 = (a1*a1 + v*v*absD) >> 2;
    3903      684167 :       if (!(a2 % L)) continue;
    3904      588268 :       t = a1*L + 2;
    3905      588268 :       p = a2*L*L + t - 1;
    3906             :       /* double check calculation just in case of overflow or other weirdness */
    3907      588268 :       if (!odd(p) || t*t + v*v*L*L*absD != 4*p)
    3908           0 :         pari_err_BUG("modpoly_pickD_primes");
    3909      588268 :       if (p > (1UL<<FF_BITS)) break;
    3910      587938 :       if (xprimes) {
    3911      373800 :         while (m < xcnt && xprimes[m] < p) m++;
    3912      373374 :         if (m < xcnt && p == xprimes[m]) {
    3913           0 :           dbg_printf(1)("skipping duplicate prime %ld\n", p);
    3914           0 :           continue;
    3915             :         }
    3916             :       }
    3917      587938 :       if (!modinv_good_prime(inv, p) || !uisprime(p)) continue;
    3918       66223 :       if (primes) {
    3919       42152 :         if (n >= max) goto done;
    3920             :         /* TODO: Implement test to filter primes that lead to
    3921             :          * L-valuation != 2 */
    3922       42152 :         primes[n] = p;
    3923       42152 :         traces[n] = t;
    3924             :       }
    3925       66223 :       n++;
    3926       66223 :       vcnt++;
    3927       66223 :       bits += log2(p);
    3928       66223 :       if (p > maxp) maxp = p;
    3929       66223 :       if (one_prime) goto done;
    3930             :     }
    3931        3779 :     if (vcnt)
    3932        3776 :       dbg_printf(3)("%ld primes with v=%ld, maxp=%ld (%.2f bits)\n",
    3933             :                  vcnt, v, maxp, log2(maxp));
    3934             :   }
    3935        3463 : done:
    3936       12614 :   if (!n) {
    3937           9 :     dbg_printf(3)("check_primes failed completely for D=%ld\n", D);
    3938           9 :     return 0;
    3939             :   }
    3940       12605 :   dbg_printf(3)("D=%ld: Found %ld primes totalling %0.2f of %ld bits\n",
    3941             :              D, n, bits, minbits);
    3942       12605 :   if (!*totbits) *totbits = (long)bits;
    3943       12605 :   return n;
    3944             : }
    3945             : 
    3946             : #define MAX_VOLCANO_FLOOR_SIZE 100000000
    3947             : 
    3948             : static long
    3949        3228 : calc_primes_for_discriminants(disc_info Ds[], long Dcnt, long L, long minbits)
    3950             : {
    3951        3228 :   pari_sp av = avma;
    3952             :   long i, j, k, m, n, D1, pcnt, totbits;
    3953             :   ulong *primes, *Dprimes, *Dtraces;
    3954             : 
    3955             :   /* D1 is the discriminant with smallest absolute value among those we found */
    3956        3228 :   D1 = Ds[0].D1;
    3957        9359 :   for (i = 1; i < Dcnt; i++)
    3958        6131 :     if (Ds[i].D1 > D1) D1 = Ds[i].D1;
    3959             : 
    3960             :   /* n is an upper bound on the number of primes we might get. */
    3961        3228 :   n = ceil(minbits / (log2(L * L * (-D1)) - 2)) + 1;
    3962        3228 :   primes = (ulong *) stack_malloc(n * sizeof(*primes));
    3963        3228 :   Dprimes = (ulong *) stack_malloc(n * sizeof(*Dprimes));
    3964        3228 :   Dtraces = (ulong *) stack_malloc(n * sizeof(*Dtraces));
    3965        3246 :   for (i = 0, totbits = 0, pcnt = 0; i < Dcnt && totbits < minbits; i++)
    3966             :   {
    3967        3246 :     long np = modpoly_pickD_primes(Dprimes, Dtraces, n, primes, pcnt,
    3968        3246 :                                    &Ds[i].bits, minbits - totbits, Ds + i);
    3969        3246 :     ulong *T = (ulong *)newblock(2*np);
    3970        3246 :     Ds[i].nprimes = np;
    3971        3246 :     Ds[i].primes = T;    memcpy(T   , Dprimes, np * sizeof(*Dprimes));
    3972        3246 :     Ds[i].traces = T+np; memcpy(T+np, Dtraces, np * sizeof(*Dtraces));
    3973             : 
    3974        3246 :     totbits += Ds[i].bits;
    3975        3246 :     pcnt += np;
    3976             : 
    3977        3246 :     if (totbits >= minbits || i == Dcnt - 1) { Dcnt = i + 1; break; }
    3978             :     /* merge lists */
    3979         589 :     for (j = pcnt - np - 1, k = np - 1, m = pcnt - 1; m >= 0; m--) {
    3980         571 :       if (k >= 0) {
    3981         546 :         if (j >= 0 && primes[j] > Dprimes[k])
    3982         301 :           primes[m] = primes[j--];
    3983             :         else
    3984         245 :           primes[m] = Dprimes[k--];
    3985             :       } else {
    3986          25 :         primes[m] = primes[j--];
    3987             :       }
    3988             :     }
    3989             :   }
    3990        3228 :   if (totbits < minbits) {
    3991           2 :     dbg_printf(1)("Only obtained %ld of %ld bits using %ld discriminants\n",
    3992             :                   totbits, minbits, Dcnt);
    3993           4 :     for (i = 0; i < Dcnt; i++) killblock((GEN)Ds[i].primes);
    3994           2 :     Dcnt = 0;
    3995             :   }
    3996        3228 :   return gc_long(av, Dcnt);
    3997             : }
    3998             : 
    3999             : /* Select discriminant(s) to use when calculating the modular
    4000             :  * polynomial of level L and invariant inv.
    4001             :  *
    4002             :  * INPUT:
    4003             :  * - L: level of modular polynomial (must be odd)
    4004             :  * - inv: invariant of modular polynomial
    4005             :  * - L0: result of select_L0(L, inv)
    4006             :  * - minbits: height of modular polynomial
    4007             :  * - flags: see below
    4008             :  * - tab: result of scanD0(L0)
    4009             :  * - tablen: length of tab
    4010             :  *
    4011             :  * OUTPUT:
    4012             :  * - Ds: the selected discriminant(s)
    4013             :  *
    4014             :  * RETURN:
    4015             :  * - the number of Ds found
    4016             :  *
    4017             :  * The flags parameter is constructed by ORing zero or more of the
    4018             :  * following values:
    4019             :  * - MODPOLY_USE_L1: force use of second class group generator
    4020             :  * - MODPOLY_NO_AUX_L: don't use auxillary class group elements
    4021             :  * - MODPOLY_IGNORE_SPARSE_FACTOR: obtain D for which h(D) > L + 1
    4022             :  *   rather than h(D) > (L + 1)/s */
    4023             : static long
    4024        3228 : modpoly_pickD(disc_info Ds[MODPOLY_MAX_DCNT], long L, long inv,
    4025             :   long L0, long max_L1, long minbits, long flags, D_entry *tab, long tablen)
    4026             : {
    4027        3228 :   pari_sp ltop = avma, btop;
    4028             :   disc_info Dinfo;
    4029             :   pari_timer T;
    4030             :   long modinv_p1, modinv_p2; /* const after next line */
    4031        3228 :   const long modinv_deg = modinv_degree(&modinv_p1, &modinv_p2, inv);
    4032        3228 :   const long pfilter = modinv_pfilter(inv), modinv_N = modinv_level(inv);
    4033             :   long i, k, use_L1, Dcnt, D0_i, d, cost, enum_cost, best_cost, totbits;
    4034        3228 :   const double L_bits = log2(L);
    4035             : 
    4036        3228 :   if (!odd(L)) pari_err_BUG("modpoly_pickD");
    4037             : 
    4038        3228 :   timer_start(&T);
    4039        3228 :   if (flags & MODPOLY_IGNORE_SPARSE_FACTOR) d = L+2;
    4040        3088 :   else d = ceildivuu(L+1, modinv_sparse_factor(inv)) + 1;
    4041             : 
    4042             :   /* Now set level to 0 unless we will need to compute N-isogenies */
    4043        3228 :   dbg_printf(1)("Using L0=%ld for L=%ld, d=%ld, modinv_N=%ld, modinv_deg=%ld\n",
    4044             :                 L0, L, d, modinv_N, modinv_deg);
    4045             : 
    4046             :   /* We use L1 if (L0|L) == 1 or if we are forced to by flags. */
    4047        3228 :   use_L1 = (kross(L0,L) > 0 || (flags & MODPOLY_USE_L1));
    4048             : 
    4049        3228 :   Dcnt = best_cost = totbits = 0;
    4050        3228 :   dbg_printf(3)("use_L1=%ld\n", use_L1);
    4051        3228 :   dbg_printf(3)("minbits = %ld\n", minbits);
    4052             : 
    4053             :   /* Iterate over the fundamental discriminants for L0 */
    4054     1980307 :   for (D0_i = 0; D0_i < tablen; D0_i++)
    4055             :   {
    4056     1977079 :     D_entry D0_entry = tab[D0_i];
    4057     1977079 :     long m, n0, h0, deg, L1, H_cost, twofactor, D0 = D0_entry.D;
    4058             :     double D0_bits;
    4059     3059479 :     if (! modinv_good_disc(inv, D0)) continue;
    4060     1301161 :     dbg_printf(3)("D0=%ld\n", D0);
    4061             :     /* don't allow either modinv_p1 or modinv_p2 to ramify */
    4062     1301161 :     if (kross(D0, L) < 1
    4063      587223 :         || (modinv_p1 > 1 && kross(D0, modinv_p1) < 1)
    4064      579892 :         || (modinv_p2 > 1 && kross(D0, modinv_p2) < 1)) {
    4065      731694 :       dbg_printf(3)("Bad D0=%ld due to nonsplit L or ramified level\n", D0);
    4066      731694 :       continue;
    4067             :     }
    4068      569467 :     deg = D0_entry.h; /* class poly degree */
    4069      569467 :     h0 = ((D0_entry.m & 2) ? 2*deg : deg); /* class number */
    4070             :     /* (D0_entry.m & 1) is 1 if ord(L0) < h0 (hence = h0/2),
    4071             :      *                  is 0 if ord(L0) = h0 */
    4072      569467 :     n0 = h0 / ((D0_entry.m & 1) + 1); /* = ord(L0) */
    4073             : 
    4074             :     /* Look for L1: for each smooth prime p */
    4075      569467 :     L1 = 0;
    4076    13708894 :     for (i = 1 ; i <= SMOOTH_PRIMES; i++)
    4077             :     {
    4078    13260255 :       long p = (long)pari_PRIMES[i];
    4079    13260255 :       if (p <= L0) continue;
    4080             :       /* If 1 + (D0 | p) = 1, i.e. p | D0 */
    4081    12512908 :       if (((D0_entry.m >> (2*i)) & 3) == 1) {
    4082             :         /* XXX: Why (p | L) = -1?  Presumably so (L^2 v^2 D0 | p) = -1? */
    4083      413945 :         if (p <= max_L1 && modinv_N % p && kross(p,L) < 0) { L1 = p; break; }
    4084             :       }
    4085             :     }
    4086      569467 :     if (i > SMOOTH_PRIMES && (n0 < h0 || use_L1))
    4087             :     { /* Didn't find suitable L1 though we need one */
    4088      266478 :       dbg_printf(3)("Bad D0=%ld because there is no good L1\n", D0);
    4089      266478 :       continue;
    4090             :     }
    4091      302989 :     dbg_printf(3)("Good D0=%ld with L1=%ld, n0=%ld, h0=%ld, d=%ld\n",
    4092             :                   D0, L1, n0, h0, d);
    4093             : 
    4094             :     /* We're finished if we have sufficiently many discriminants that satisfy
    4095             :      * the cost requirement */
    4096      302989 :     if (totbits > minbits && best_cost && h0*(L-1) > 3*best_cost) break;
    4097             : 
    4098      302989 :     D0_bits = log2(-D0);
    4099             :     /* If L^2 D0 is too big to fit in a BIL bit integer, skip D0. */
    4100      302989 :     if (D0_bits + 2 * L_bits > (BITS_IN_LONG - 1)) continue;
    4101             : 
    4102             :     /* m is the order of L0^n0 in L^2 D0? */
    4103      302989 :     m = primeform_exp_order(L0, n0, L * L * D0, n0 * (L-1));
    4104      302989 :     if (m < (L-1)/2) {
    4105       84228 :       dbg_printf(3)("Bad D0=%ld because %ld is less than (L-1)/2=%ld\n",
    4106           0 :                     D0, m, (L - 1)/2);
    4107       84228 :       continue;
    4108             :     }
    4109             :     /* Heuristic.  Doesn't end up contributing much. */
    4110      218761 :     H_cost = 2 * deg * deg;
    4111             : 
    4112             :     /* 0xc = 0b1100, so D0_entry.m & 0xc == 1 + (D0 | 2) */
    4113      218761 :     if ((D0 & 7) == 5) /* D0 = 5 (mod 8) */
    4114        6065 :       twofactor = ((D0_entry.m & 0xc) ? 1 : 3);
    4115             :     else
    4116      212696 :       twofactor = 0;
    4117             : 
    4118      218761 :     btop = avma;
    4119             :     /* For each small prime... */
    4120      770017 :     for (i = 0; i <= SMOOTH_PRIMES; i++) {
    4121             :       long h1, h2, D1, D2, n1, n2, dl1, dl20, dl21, p, q, j;
    4122             :       double p_bits;
    4123      769912 :       set_avma(btop);
    4124             :       /* i = 0 corresponds to 1, which we do not want to skip! (i.e. DK = D) */
    4125      769912 :       if (i) {
    4126     1091450 :         if (modinv_odd_conductor(inv) && i == 1) continue;
    4127      540836 :         p = (long)pari_PRIMES[i];
    4128             :         /* Don't allow large factors in the conductor. */
    4129      659537 :         if (p > max_L1) break;
    4130      440881 :         if (p == L0 || p == L1 || p == L || p == modinv_p1 || p == modinv_p2)
    4131      152824 :           continue;
    4132      288057 :         p_bits = log2(p);
    4133             :         /* h1 is the class number of D1 = q^2 D0, where q = p^j (j defined in the loop below) */
    4134      288057 :         h1 = h0 * (p - ((D0_entry.m >> (2*i)) & 0x3) + 1);
    4135             :         /* q is the smallest power of p such that h1 >= d ~ "L + 1". */
    4136      291527 :         for (j = 1, q = p; h1 < d; j++, q *= p, h1 *= p)
    4137             :           ;
    4138      288057 :         D1 = q * q * D0;
    4139             :         /* can't have D1 = 0 mod 16 and hope to get any primes congruent to 3 mod 4 */
    4140      288057 :         if ((pfilter & IQ_FILTER_1MOD4) && !(D1 & 0xF)) continue;
    4141             :       } else {
    4142             :         /* i = 0, corresponds to "p = 1". */
    4143      218761 :         h1 = h0;
    4144      218761 :         D1 = D0;
    4145      218761 :         p = q = j = 1;
    4146      218761 :         p_bits = 0;
    4147             :       }
    4148             :       /* include a factor of 4 if D1 is 5 mod 8 */
    4149             :       /* XXX: No idea why he does this. */
    4150      506748 :       if (twofactor && (q & 1)) {
    4151       15418 :         if (modinv_odd_conductor(inv)) continue;
    4152         119 :         D1 *= 4;
    4153         119 :         h1 *= twofactor;
    4154             :       }
    4155             :       /* heuristic early abort; we may miss good D1's, but this saves time */
    4156      491449 :       if (totbits > minbits && best_cost && h1*(L-1) > 2.2*best_cost) continue;
    4157             : 
    4158             :       /* log2(D0 * (p^j)^2 * L^2 * twofactor) > (BIL - 1) -- params too big. */
    4159      969115 :       if (D0_bits + 2*j*p_bits + 2*L_bits
    4160      483670 :           + (twofactor && (q & 1) ? 2.0 : 0.0) > (BITS_IN_LONG-1)) continue;
    4161             : 
    4162      481895 :       if (! check_generators(&n1, NULL, D1, h1, n0, d, L0, L1)) continue;
    4163             : 
    4164      460278 :       if (n1 >= h1) dl1 = -1; /* fill it in later */
    4165      208758 :       else if ((dl1 = primeform_discrete_log(L0, L, n1, D1)) < 0) continue;
    4166      333551 :       dbg_printf(3)("Good D0=%ld, D1=%ld with q=%ld, L1=%ld, n1=%ld, h1=%ld\n",
    4167             :                     D0, D1, q, L1, n1, h1);
    4168      333551 :       if (modinv_deg && orientation_ambiguity(D1, L0, modinv_p1, modinv_p2, modinv_N))
    4169        1648 :         continue;
    4170             : 
    4171      331903 :       D2 = L * L * D1;
    4172      331903 :       h2 = h1 * (L-1);
    4173             :       /* m is the order of L0^n1 in cl(D2) */
    4174      331903 :       if (!check_generators(&n2, &m, D2, h2, n1, d*(L-1), L0, L1)) continue;
    4175             : 
    4176             :       /* This restriction on m is not necessary, but simplifies life later */
    4177      312869 :       if (m < (L-1)/2 || (!L1 && m < L-1)) {
    4178      150613 :         dbg_printf(3)("Bad D2=%ld for D1=%ld, D0=%ld, with n2=%ld, h2=%ld, L1=%ld, "
    4179             :                       "order of L0^n1 in cl(D2) is too small\n", D2, D1, D0, n2, h2, L1);
    4180      150613 :         continue;
    4181             :       }
    4182      162256 :       dl20 = n1;
    4183      162256 :       dl21 = 0;
    4184      162256 :       if (m < L-1) {
    4185       86991 :         GEN Q1 = qform_primeform2(L, D1), Q2, X;
    4186       86991 :         if (!Q1) pari_err_BUG("modpoly_pickD");
    4187       86991 :         Q2 = primeform_u(stoi(D2), L1);
    4188       86991 :         Q2 = qfbcomp(Q1, Q2); /* we know this element has order L-1 */
    4189       86991 :         Q1 = primeform_u(stoi(D2), L0);
    4190       86991 :         k = ((n2 & 1) ? 2*n2 : n2)/(L-1);
    4191       86991 :         Q1 = gpowgs(Q1, k);
    4192       86991 :         X = qfi_Shanks(Q2, Q1, L-1);
    4193       86991 :         if (!X) {
    4194       14094 :           dbg_printf(3)("Bad D2=%ld for D1=%ld, D0=%ld, with n2=%ld, h2=%ld, L1=%ld, "
    4195             :               "form of norm L^2 not generated by L0 and L1\n",
    4196             :               D2, D1, D0, n2, h2, L1);
    4197       14094 :           continue;
    4198             :         }
    4199       72897 :         dl20 = itos(X) * k;
    4200       72897 :         dl21 = 1;
    4201             :       }
    4202      148162 :       if (! (m < L-1 || n2 < d*(L-1)) && n1 >= d && ! use_L1)
    4203       74771 :         L1 = 0;  /* we don't need L1 */
    4204             : 
    4205      148162 :       if (!L1 && use_L1) {
    4206           0 :         dbg_printf(3)("not using D2=%ld for D1=%ld, D0=%ld, with n2=%ld, h2=%ld, L1=%ld, "
    4207             :                    "because we don't need L1 but must use it\n",
    4208             :                    D2, D1, D0, n2, h2, L1);
    4209           0 :         continue;
    4210             :       }
    4211             :       /* don't allow zero dl21 with L1 for the moment, since
    4212             :        * modpoly doesn't handle it - we may change this in the future */
    4213      148162 :       if (L1 && ! dl21) continue;
    4214      147668 :       dbg_printf(3)("Good D0=%ld, D1=%ld, D2=%ld with s=%ld^%ld, L1=%ld, dl2=%ld, n2=%ld, h2=%ld\n",
    4215             :                  D0, D1, D2, p, j, L1, dl20, n2, h2);
    4216             : 
    4217             :       /* This estimate is heuristic and fiddling with the
    4218             :        * parameters 5 and 0.25 can change things quite a bit. */
    4219      147668 :       enum_cost = n2 * (5 * L0 * L0 + 0.25 * L1 * L1);
    4220      147668 :       cost = enum_cost + H_cost;
    4221      147668 :       if (best_cost && cost > 2.2*best_cost) break;
    4222       37684 :       if (best_cost && cost >= 0.99*best_cost) continue;
    4223             : 
    4224        9403 :       Dinfo.GENcode0 = evaltyp(t_VECSMALL)|_evallg(13);
    4225        9403 :       Dinfo.inv = inv;
    4226        9403 :       Dinfo.L = L;
    4227        9403 :       Dinfo.D0 = D0;
    4228        9403 :       Dinfo.D1 = D1;
    4229        9403 :       Dinfo.L0 = L0;
    4230        9403 :       Dinfo.L1 = L1;
    4231        9403 :       Dinfo.n1 = n1;
    4232        9403 :       Dinfo.n2 = n2;
    4233        9403 :       Dinfo.dl1 = dl1;
    4234        9403 :       Dinfo.dl2_0 = dl20;
    4235        9403 :       Dinfo.dl2_1 = dl21;
    4236        9403 :       Dinfo.cost = cost;
    4237             : 
    4238        9403 :       if (!modpoly_pickD_primes(NULL, NULL, 0, NULL, 0, &Dinfo.bits, minbits, &Dinfo))
    4239          44 :         continue;
    4240        9359 :       dbg_printf(2)("Best D2=%ld, D1=%ld, D0=%ld with s=%ld^%ld, L1=%ld, "
    4241             :                  "n1=%ld, n2=%ld, cost ratio %.2f, bits=%ld\n",
    4242             :                  D2, D1, D0, p, j, L1, n1, n2,
    4243           0 :                  (double)cost/(d*(L-1)), Dinfo.bits);
    4244             :       /* Insert Dinfo into the Ds array.  Ds is sorted by ascending cost. */
    4245       50474 :       for (j = 0; j < Dcnt; j++)
    4246       47233 :         if (Dinfo.cost < Ds[j].cost) break;
    4247        9359 :       if (n2 > MAX_VOLCANO_FLOOR_SIZE && n2*(L1 ? 2 : 1) > 1.2* (d*(L-1)) ) {
    4248           0 :         dbg_printf(3)("Not using D1=%ld, D2=%ld for space reasons\n", D1, D2);
    4249           0 :         continue;
    4250             :       }
    4251        9359 :       if (j == Dcnt && Dcnt == MODPOLY_MAX_DCNT)
    4252           0 :         continue;
    4253        9359 :       totbits += Dinfo.bits;
    4254        9359 :       if (Dcnt == MODPOLY_MAX_DCNT) totbits -= Ds[Dcnt-1].bits;
    4255        9359 :       if (Dcnt < MODPOLY_MAX_DCNT) Dcnt++;
    4256        9359 :       if (n2 > MAX_VOLCANO_FLOOR_SIZE)
    4257           0 :         dbg_printf(3)("totbits=%ld, minbits=%ld\n", totbits, minbits);
    4258       21673 :       for (k = Dcnt-1; k > j; k--) Ds[k] = Ds[k-1];
    4259        9359 :       Ds[k] = Dinfo;
    4260        9359 :       best_cost = (totbits > minbits)? Ds[Dcnt-1].cost: 0;
    4261             :       /* if we were able to use D1 with s = 1, there is no point in
    4262             :        * using any larger D1 for the same D0 */
    4263        9359 :       if (!i) break;
    4264             :     } /* END FOR over small primes */
    4265             :   } /* END WHILE over D0's */
    4266        3228 :   dbg_printf(2)("  checked %ld of %ld fundamental discriminants to find suitable "
    4267             :                 "discriminant (Dcnt = %ld)\n", D0_i, tablen, Dcnt);
    4268        3228 :   if ( ! Dcnt) {
    4269           0 :     dbg_printf(1)("failed completely for L=%ld\n", L);
    4270           0 :     return 0;
    4271             :   }
    4272             : 
    4273        3228 :   Dcnt = calc_primes_for_discriminants(Ds, Dcnt, L, minbits);
    4274             : 
    4275             :   /* fill in any missing dl1's */
    4276        6472 :   for (i = 0 ; i < Dcnt; i++)
    4277        3244 :     if (Ds[i].dl1 < 0 &&
    4278        3220 :        (Ds[i].dl1 = primeform_discrete_log(L0, L, Ds[i].n1, Ds[i].D1)) < 0)
    4279           0 :         pari_err_BUG("modpoly_pickD");
    4280        3228 :   if (DEBUGLEVEL > 1+3) {
    4281           0 :     err_printf("Selected %ld discriminants using %ld msecs\n", Dcnt, timer_delay(&T));
    4282           0 :     for (i = 0 ; i < Dcnt ; i++)
    4283             :     {
    4284           0 :       GEN H = classno(stoi(Ds[i].D0));
    4285           0 :       long h0 = itos(H);
    4286           0 :       err_printf ("    D0=%ld, h(D0)=%ld, D=%ld, L0=%ld, L1=%ld, "
    4287             :           "cost ratio=%.2f, enum ratio=%.2f,",
    4288           0 :           Ds[i].D0, h0, Ds[i].D1, Ds[i].L0, Ds[i].L1,
    4289           0 :           (double)Ds[i].cost/(d*(L-1)),
    4290           0 :           (double)(Ds[i].n2*(Ds[i].L1 ? 2 : 1))/(d*(L-1)));
    4291           0 :       err_printf (" %ld primes, %ld bits\n", Ds[i].nprimes, Ds[i].bits);
    4292             :     }
    4293             :   }
    4294        3228 :   return gc_long(ltop, Dcnt);
    4295             : }
    4296             : 
    4297             : static int
    4298    15420475 : _qsort_cmp(const void *a, const void *b)
    4299             : {
    4300    15420475 :   D_entry *x = (D_entry *)a, *y = (D_entry *)b;
    4301             :   long u, v;
    4302             : 
    4303             :   /* u and v are the class numbers of x and y */
    4304    15420475 :   u = x->h * (!!(x->m & 2) + 1);
    4305    15420475 :   v = y->h * (!!(y->m & 2) + 1);
    4306             :   /* Sort by class number */
    4307    15420475 :   if (u < v) return -1;
    4308    10736035 :   if (u > v) return 1;
    4309             :   /* Sort by discriminant (which is < 0, hence the sign reversal) */
    4310     3230579 :   if (x->D > y->D) return -1;
    4311           0 :   if (x->D < y->D) return 1;
    4312           0 :   return 0;
    4313             : }
    4314             : 
    4315             : /* Build a table containing fundamental D, |D| <= maxD whose class groups
    4316             :  * - are cyclic generated by an element of norm L0
    4317             :  * - have class number at most maxh
    4318             :  * The table is ordered using _qsort_cmp above, which ranks the discriminants
    4319             :  * by class number, then by absolute discriminant.
    4320             :  *
    4321             :  * INPUT:
    4322             :  * - maxd: largest allowed discriminant
    4323             :  * - maxh: largest allowed class number
    4324             :  * - L0: norm of class group generator (2, 3, 5, or 7)
    4325             :  *
    4326             :  * OUTPUT:
    4327             :  * - tablelen: length of return value
    4328             :  *
    4329             :  * RETURN:
    4330             :  * - array of {D, h(D), kronecker symbols for small p} */
    4331             : static D_entry *
    4332        3228 : scanD0(long *tablelen, long *minD, long maxD, long maxh, long L0)
    4333             : {
    4334             :   pari_sp av;
    4335             :   D_entry *tab;
    4336             :   long i, lF, cnt;
    4337             :   GEN F;
    4338             : 
    4339             :   /* NB: As seen in the loop below, the real class number of D can be */
    4340             :   /* 2*maxh if cl(D) is cyclic. */
    4341        3228 :   tab = (D_entry *) stack_malloc((maxD/4)*sizeof(*tab)); /* Overestimate */
    4342        3228 :   F = vecfactorsquarefreeu_coprime(*minD, maxD, mkvecsmall(2));
    4343        3228 :   lF = lg(F);
    4344    32263860 :   for (av = avma, cnt = 0, i = 1; i < lF; i++, set_avma(av))
    4345             :   {
    4346    32260632 :     GEN DD, ordL, f, q = gel(F,i);
    4347             :     long j, k, n, h, L1, d, D;
    4348             :     ulong m;
    4349             : 
    4350    32260632 :     if (!q) continue; /* not square-free */
    4351             :     /* restrict to possibly cyclic class groups */
    4352    13083068 :     k = lg(q) - 1; if (k > 2) continue;
    4353    10193544 :     d = i + *minD - 1; /* q = prime divisors of d */
    4354    10193544 :     if ((d & 3) == 1) continue;
    4355     5129038 :     D = -d; /* d = 3 (mod 4), D = 1 mod 4 fundamental */
    4356     5129038 :     if (kross(D, L0) < 1) continue;
    4357             : 
    4358             :     /* L1 initially the first factor of d if small enough, otherwise ignored */
    4359     2476681 :     L1 = (k > 1 && q[1] <= MAX_L1)? q[1]: 0;
    4360             : 
    4361             :     /* Check if h(D) is too big */
    4362     2476681 :     h = hclassno6u(d) / 6;
    4363     2476681 :     if (h > 2*maxh || (!L1 && h > maxh)) continue;
    4364             : 
    4365             :     /* Check if ord(f) is not big enough to generate at least half the
    4366             :      * class group (where f is the L0-primeform). */
    4367     2299563 :     DD = stoi(D);
    4368     2299563 :     f = primeform_u(DD, L0);
    4369     2299563 :     ordL = qfi_order(qfi_red(f), stoi(h));
    4370     2299563 :     n = itos(ordL);
    4371     2299563 :     if (n < h/2 || (!L1 && n < h)) continue;
    4372             : 
    4373             :     /* If f is big enough, great! Otherwise, for each potential L1,
    4374             :      * do a discrete log to see if it is NOT in the subgroup generated
    4375             :      * by L0; stop as soon as such is found. */
    4376     1977079 :     for (j = 1;; j++) {
    4377     2235158 :       if (n == h || (L1 && !qfi_Shanks(primeform_u(DD, L1), f, n))) {
    4378     1875817 :         dbg_printf(2)("D0=%ld good with L1=%ld\n", D, L1);
    4379     1875817 :         break;
    4380             :       }
    4381      359341 :       if (!L1) break;
    4382      258079 :       L1 = (j <= k && k > 1 && q[j] <= MAX_L1 ? q[j] : 0);
    4383             :     }
    4384             :     /* The first bit of m is set iff f generates a proper subgroup of cl(D)
    4385             :      * (hence implying that we need L1). */
    4386     1977079 :     m = (n < h ? 1 : 0);
    4387             :     /* bits j and j+1 give the 2-bit number 1 + (D|p) where p = prime(j) */
    4388    58810576 :     for (j = 1 ; j <= SMOOTH_PRIMES; j++)
    4389             :     {
    4390    56833497 :       ulong x = (ulong) (1 + kross(D, (long) pari_PRIMES[j]));
    4391    56833497 :       m |= x << (2*j);
    4392             :     }
    4393             : 
    4394             :     /* Insert d, h and m into the table */
    4395     1977079 :     tab[cnt].D = D;
    4396     1977079 :     tab[cnt].h = h;
    4397     1977079 :     tab[cnt].m = m; cnt++;
    4398             :   }
    4399             : 
    4400             :   /* Sort the table */
    4401        3228 :   qsort(tab, cnt, sizeof(*tab), _qsort_cmp);
    4402        3228 :   *tablelen = cnt;
    4403        3228 :   *minD = maxD + 3 - (maxD & 3); /* smallest d >= maxD, d = 3 (mod 4) */
    4404        3228 :   return tab;
    4405             : }
    4406             : 
    4407             : /* Populate Ds with discriminants (and attached data) that can be
    4408             :  * used to calculate the modular polynomial of level L and invariant
    4409             :  * inv.  Return the number of discriminants found. */
    4410             : static long
    4411        3226 : discriminant_with_classno_at_least(disc_info bestD[MODPOLY_MAX_DCNT],
    4412             :   long L, long inv, GEN Q, long ignore_sparse)
    4413             : {
    4414             :   enum { SMALL_L_BOUND = 101 };
    4415        3226 :   long max_max_D = 160000 * (inv ? 2 : 1);
    4416             :   long minD, maxD, maxh, L0, max_L1, minbits, Dcnt, flags, s, d, i, tablen;
    4417             :   D_entry *tab;
    4418        3226 :   double eps, cost, best_eps = -1.0, best_cost = -1.0;
    4419             :   disc_info Ds[MODPOLY_MAX_DCNT];
    4420        3226 :   long best_cnt = 0;
    4421             :   pari_timer T;
    4422        3226 :   timer_start(&T);
    4423             : 
    4424        3226 :   s = modinv_sparse_factor(inv);
    4425        3226 :   d = ceildivuu(L+1, s) + 1;
    4426             : 
    4427             :   /* maxD of 10000 allows us to get a satisfactory discriminant in
    4428             :    * under 250ms in most cases. */
    4429        3226 :   maxD = 10000;
    4430             :   /* Allow the class number to overshoot L by 50%.  Must be at least
    4431             :    * 1.1*L, and higher values don't seem to provide much benefit,
    4432             :    * except when L is small, in which case it's necessary to get any
    4433             :    * discriminant at all in some cases. */
    4434        3226 :   maxh = (L / s < SMALL_L_BOUND) ? 10 * L : 1.5 * L;
    4435             : 
    4436        3226 :   flags = ignore_sparse ? MODPOLY_IGNORE_SPARSE_FACTOR : 0;
    4437        3226 :   L0 = select_L0(L, inv, 0);
    4438        3226 :   max_L1 = L / 2 + 2;    /* for L=11 we need L1=7 for j */
    4439        3226 :   minbits = modpoly_height_bound(L, inv);
    4440        3226 :   if (Q) minbits += expi(Q);
    4441        3226 :   minD = 7;
    4442             : 
    4443        6452 :   while ( ! best_cnt) {
    4444        3228 :     while (maxD <= max_max_D) {
    4445             :       /* TODO: Find a way to re-use tab when we need multiple modpolys */
    4446        3228 :       tab = scanD0(&tablen, &minD, maxD, maxh, L0);
    4447        3228 :       dbg_printf(1)("Found %ld potential fundamental discriminants\n", tablen);
    4448             : 
    4449        3228 :       Dcnt = modpoly_pickD(Ds, L, inv, L0, max_L1, minbits, flags, tab, tablen);
    4450        3228 :       eps = 0.0;
    4451        3228 :       cost = 0.0;
    4452             : 
    4453        3228 :       if (Dcnt) {
    4454        3226 :         long n1 = 0;
    4455        6470 :         for (i = 0; i < Dcnt; i++) {
    4456        3244 :           n1 = maxss(n1, Ds[i].n1);
    4457        3244 :           cost += Ds[i].cost;
    4458             :         }
    4459        3226 :         eps = (n1 * s - L) / (double)L;
    4460             : 
    4461        3226 :         if (best_cost < 0.0 || cost < best_cost) {
    4462        3226 :           if (best_cnt)
    4463           0 :             for (i = 0; i < best_cnt; i++) killblock((GEN)bestD[i].primes);
    4464        3226 :           (void) memcpy(bestD, Ds, Dcnt * sizeof(disc_info));
    4465        3226 :           best_cost = cost;
    4466        3226 :           best_cnt = Dcnt;
    4467        3226 :           best_eps = eps;
    4468             :           /* We're satisfied if n1 is within 5% of L. */
    4469        3226 :           if (L / s <= SMALL_L_BOUND || eps < 0.05) break;
    4470             :         } else {
    4471           0 :           for (i = 0; i < Dcnt; i++) killblock((GEN)Ds[i].primes);
    4472             :         }
    4473             :       } else {
    4474           2 :         if (log2(maxD) > BITS_IN_LONG - 2 * (log2(L) + 2))
    4475             :         {
    4476           0 :           char *err = stack_sprintf("modular polynomial of level %ld and invariant %ld",L,inv);
    4477           0 :           pari_err(e_ARCH, err);
    4478             :         }
    4479             :       }
    4480           2 :       maxD *= 2;
    4481           2 :       minD += 4;
    4482           2 :       dbg_printf(0)("  Doubling discriminant search space (closest: %.1f%%, cost ratio: %.1f)...\n", eps*100, cost/(double)(d*(L-1)));
    4483             :     }
    4484        3226 :     max_max_D *= 2;
    4485             :   }
    4486             : 
    4487        3226 :   if (DEBUGLEVEL > 3) {
    4488           0 :     pari_sp av = avma;
    4489           0 :     err_printf("Found discriminant(s):\n");
    4490           0 :     for (i = 0; i < best_cnt; ++i) {
    4491           0 :       long h = itos(classno(stoi(bestD[i].D1)));
    4492           0 :       set_avma(av);
    4493           0 :       err_printf("  D = %ld, h = %ld, u = %ld, L0 = %ld, L1 = %ld, n1 = %ld, n2 = %ld, cost = %ld\n",
    4494           0 :           bestD[i].D1, h, usqrt(bestD[i].D1 / bestD[i].D0), bestD[i].L0,
    4495           0 :           bestD[i].L1, bestD[i].n1, bestD[i].n2, bestD[i].cost);
    4496             :     }
    4497           0 :     err_printf("(off target by %.1f%%, cost ratio: %.1f)\n",
    4498           0 :                best_eps*100, best_cost/(double)(d*(L-1)));
    4499             :   }
    4500        3226 :   return best_cnt;
    4501             : }

Generated by: LCOV version 1.16