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 - nflist.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.18.1 lcov report (development 30733-eb2d773d38) Lines: 3259 3395 96.0 %
Date: 2026-03-03 09:24:12 Functions: 327 335 97.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 2020  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. It is distributed in the hope that it will be useful, but WITHOUT
       8             : ANY WARRANTY WHATSOEVER.
       9             : 
      10             : Check the License for details. You should have received a copy of it, along
      11             : with the package; see the file 'COPYING'. If not, write to the Free Software
      12             : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      13             : 
      14             : #include "pari.h"
      15             : #include "paripriv.h"
      16             : 
      17             : #define DEBUGLEVEL DEBUGLEVEL_nflist
      18             : 
      19             : /* Code s: if s >= 0 number of complex embeddings; s = -1: all signatures;
      20             :  * s = -2: all signatures separated.
      21             :  * Known groups: C1 = 1T1, C2 = 2T1, C3 = 3T1, S3 = 3T2, C4 = 4T1, V4 = 4T2,
      22             :  * D4 = 4T3, A4 = 4T4, S4 = 4T5, C5 = 5T1, D5 = 5T2, F5 = M20 = 5T3, A5 = 5T4,
      23             :  * C6 = 6T1, S36 = D66 = 6T2, D612 = 6T3, A46 = 6T4, S3C3 = 6T5,
      24             :  * A462 = 6T6, S46P = 6T7, S46M = 6T8, C32C4 = 6T10, S462 = 6T11,
      25             :  * A56 = PSL25 = 6T12, C32D4 = 6T13,
      26             :  * C7 = 7T1, D7 = 7T2, M21 = 7T3, M42 = 7T4, C9 = 9T1, C3C3 = 9T2,
      27             :  * CL and DL for L prime, Cpq for n = pq product of two distinct primes.
      28             :  * A5cond is A5 ordered by twist-minimal conductor.
      29             :  *
      30             :  * For each group G:
      31             :  * - makeG(GEN N, GEN F, long s, long prec):
      32             :  * fields of given Galois group G, absolute discriminant N, signature s, and
      33             :  * auxiliary field (possibly NULL) F.
      34             :  * - makeGvec(GEN X, GEN Xinf, GEN F, long s, long prec):
      35             :  * fields of given Galois group G, absolute discriminant between Xinf and X,
      36             :  * signature s, and auxiliary field (possibly NULL) F.
      37             :  * - makeGresolvent(GEN pol, long flag)
      38             :  * - makeGsome(long s, long n, long prec): find n fields of given Galois group
      39             :  * G and signature s, not necessarily the smallest; n is assumed small. Useful
      40             :  * only when makeG/makeGvec take a long time. */
      41             : 
      42             : /* Relations between discriminants:
      43             : * D = disc of quadratic subfield or resolvent; Dk = disc subfield of degree k.
      44             : * f,g are integers, not necessarily conductors.
      45             : *
      46             : * C_ell: f^(ell-1), conductor f; ell odd prime
      47             : * D_ell: (Df^2)^((ell-1)/2), (f) = cond. over quad. subfield; ell odd prime
      48             : * C_pq: Dp^q Dq^p/gcd(Dp^(q-1),Dq^(p-1))
      49             : * C4: D^3f^2 (D sum of 2 squares); "conductor" Df
      50             : * V4: D^2f^2 (D for any of the 3 max. subfields); conductor lcm(D1,D2)
      51             : * D4: D^2f; "conductor" Df
      52             : * A4: Df^2, D = g^2
      53             : * S4: Df^2
      54             : * F5 = M20: Df^4 or 25D f^4 iff 125|D (what f's ?)
      55             : * C6: D^3D3^2/gcd(D,D3)^2; conductor lcm(D,D3)
      56             : * D6 = D6(12): D^3 D3^2 / gcd(D,D3)^2 * (1 or 4)
      57             : * S3(6) = D6(6): D^3 f^4 = D3^2 D
      58             : * A4(6), S4(6)+: D3 * D4
      59             : * S4(6)-: D*D3*D4 / gcd(g,D)^2*(1,4,16); D4 = D3*g^2, D3 = Df^2, D4 = D3g^2
      60             : *         D*D3*D4 = D^3f^4g^2 = D3^3(g/f)^2 = D3^2*D*g^2=D4^3/(g^4f^2)
      61             : *         Disc = D3^2 D * (g * (1,2,4) / gcd(g,D))^2
      62             : *         16 iff v(D2)=2 and v(g)=2 or 3.
      63             : *         4 iff v(g)=1 or (v(D2)=2 and v(g)=4)
      64             : *         1 or 4 if v(D2)=3 and v(g)=4.
      65             : * C32C4: D D4 f^2
      66             : * S32: disc of 2 S3 subfields: D1F1^2, D2F2^2, D1, D2 fund. disc
      67             : *      disc = (D1D2)^3 / gcd(D1,D2)^4 * lcm(F1,F2)^2 * g^2
      68             : * M21: D^2f^6 (D = g^2) or 7^4 D^2 f^6 iff 49|D
      69             : * M42: Df^6 or 7^2 Df^6 iff 7^4|D or 7^4 Df^6 iff 7^5|D
      70             : * C9: D^4f^6
      71             : * C3xC3: lcm(D3, D3')^3
      72             : * D9: D^4 g^2 f^6 (disc subic subfield = Dg^2)
      73             : *
      74             : * Minimimal discriminants for each group, by s
      75             : * C1: [1]
      76             : * C2: [5, 3]
      77             : * C3: [49, 0]
      78             : * S3: [148, 23]
      79             : * C4: [1125, 0, 125]
      80             : * V4: [1600, 0, 144]
      81             : * D4: [725, 275, 117]
      82             : * A4: [26569, 0, 3136]
      83             : * S4: [1957, 283, 229]
      84             : * C5: [14641, 0, 0]
      85             : * D5: [160801, 0, 2209]
      86             : * F5: [2382032, 0, 35152]
      87             : * A5: [3104644, 0, 18496]
      88             : * C6: [300125, 0, 0, 16807]
      89             : * S36: [810448, 0, 0, 12167]
      90             : * D612: [2738000, 0, 66125, 14283]
      91             : * A46: [25969216, 0, 153664, 0]
      92             : * S3C3: [722000, 0, 0, 9747]
      93             : * A462: [434581, 103243, 31213, 0]
      94             : * S46+: [3356224, 0, 33856, 0]
      95             : * S46-: [7495014493, 0, 3241792, 778688]
      96             : * S32: [27848000, 0, 242000, 309123]
      97             : * C32C4: [55130625, 0, 525625, 0]
      98             : * S462: [1387029, 309123, 28037, 10051]
      99             : * C7: [594823321, 0, 0]
     100             : * D7: [192100033, 0, 0, 357911]
     101             : * M21: [1817487424, 0, 0, 0]
     102             : * M42: [12431698517, 0, 0, 38014691]
     103             : * C9: [16983563041, 0, 0, 0, 0]
     104             : * C3C3: [62523502209, 0, 0, 0, 0]
     105             : * D9: [1624709678881, 0, 0, 0, 775511104]
     106             : * C11: [41426511213649, 0, 0, 0, 0]
     107             : * D11: [3670285774226257, 0, 0, 0, 0, 129891985607] */
     108             : 
     109             : /* FIXME: export */
     110             : static long
     111       34363 : RgVV_nb(GEN v)
     112             : {
     113       34363 :   long i, l = lg(v), n = 0;
     114       69384 :   for (i = 1; i < l; i++) n += lg(gel(v,i)) - 1;
     115       34363 :   return n;
     116             : }
     117             : /* FIXME: export */
     118             : static GEN
     119       36170 : gtoset_shallow(GEN x)
     120             : {
     121       36170 :   GEN p = gen_indexsort_uniq(x, (void*)&cmp_universal, cmp_nodata);
     122       36163 :   return vecpermute(x, p);
     123             : }
     124             : 
     125             : static GEN
     126        2947 : nflist_parapply(const char *s, GEN v, GEN w)
     127             : {
     128             :   GEN L;
     129        2947 :   if (DEBUGLEVEL>=3) err_printf("%s: ",s);
     130        2947 :   L = gen_parapply_percent(snm_closure(is_entry(s), v), w, DEBUGLEVEL>=3);
     131        2947 :   if (DEBUGLEVEL>=3) err_printf("done\n");
     132        2947 :   return L;
     133             : }
     134             : 
     135             : /**************************************************************************/
     136             : /*                        Utility functions                               */
     137             : /**************************************************************************/
     138             : static long
     139          49 : divissquareall(GEN x, GEN y, GEN *f)
     140          49 : { GEN r, q = dvmdii(x, y, &r); return r == gen_0 && Z_issquareall(q,f); }
     141             : static long
     142          21 : divissquare(GEN x, GEN y) { return divissquareall(x, y, NULL); }
     143             : static long
     144          21 : divispowerall(GEN x, GEN y, ulong k, GEN *f)
     145          21 : { GEN r, q = dvmdii(x, y, &r); return r == gen_0 && Z_ispowerall(q,k,f); }
     146             : /* x / y if y | x, else NULL */
     147             : static GEN
     148       27176 : divide(GEN x, GEN y)
     149       27176 : { GEN r, q = dvmdii(x, y, &r); return r == gen_0? q: NULL; }
     150             : 
     151             : /* ceil(X^(1/n)) */
     152             : static long
     153         280 : ceilsqrtn(GEN X, long n)
     154             : {
     155         280 :   pari_sp av = avma;
     156         280 :   ulong x = itou(sqrtnint(X, n));
     157         280 :   if (cmpii(powuu(x, n), X) < 0) x++;
     158         280 :   return gc_long(av, x);
     159             : }
     160             : static long
     161         196 : ceilsqrt(GEN X)
     162             : {
     163         196 :   pari_sp av = avma;
     164             :   GEN r;
     165         196 :   ulong x = itou(sqrtremi(X, &r));
     166         196 :   return gc_long(av, r==gen_0? x: x+1);
     167             : }
     168             : static GEN
     169        1162 : gceilsqrtn(GEN X, long n)
     170             : {
     171        1162 :   GEN x = sqrtnint(X, n);
     172        1162 :   if (cmpii(powiu(x, n), X) < 0) x = addiu(x, 1);
     173        1162 :   return x;
     174             : }
     175             : /* assume X >= 0 or n odd */
     176             : static long
     177         427 : sceilsqrtn(long X, long n)
     178             : {
     179             :   ulong x, Xa;
     180         427 :   if (!X) return 0;
     181         427 :   Xa = labs(X); x = usqrtn(Xa, n);
     182         427 :   if (X > 0 && upowuu(x, n) != Xa) x++;
     183         427 :   return X > 0? (long)x: -(long)x;
     184             : }
     185             : /* ceil((X/Y)^1/n)*/
     186             : static long
     187          84 : ceilsqrtndiv(GEN X, GEN Y, long n)
     188             : {
     189          84 :   pari_sp av = avma;
     190          84 :   ulong x = itou(sqrtnint(divii(X, Y), n));
     191          84 :   if (cmpii(mulii(powuu(x, n), Y), X) < 0) x++;
     192          84 :   return gc_long(av, x);
     193             : }
     194             : long
     195        7151 : ceilsqrtdiv(GEN X, GEN Y)
     196             : {
     197        7151 :   pari_sp av = avma;
     198        7151 :   GEN r, q = dvmdii(X, Y, &r);
     199        7151 :   ulong x = itou((r == gen_0)? sqrtremi(q, &r): sqrti(q));
     200        7151 :   return gc_long(av, r==gen_0? x: x+1);
     201             : }
     202             : static GEN
     203          28 : gceilsqrtdiv(GEN X, GEN Y)
     204             : {
     205          28 :   GEN r, q = dvmdii(X, Y, &r);
     206          28 :   q = (r == gen_0)? sqrtremi(q, &r): sqrti(q);
     207          28 :   return r == gen_0? q: addiu(q, 1);
     208             : }
     209             : static GEN
     210       38234 : gfloorsqrtdiv(GEN X, GEN Y) { return sqrti(divii(X, Y)); }
     211             : /* floor(X^(1/n)) */
     212             : static long
     213        3353 : floorsqrtn(GEN X, long n)
     214        3353 : { pari_sp av = avma; return gc_long(av, itou(sqrtnint(X, n))); }
     215             : static long
     216         196 : floorsqrt(GEN X)
     217         196 : { pari_sp av = avma; return gc_long(av, itou(sqrti(X))); }
     218             : /* floor((X/Y)^(1/n)) */
     219             : static long
     220        1617 : floorsqrtndiv(GEN X, GEN Y, long n)
     221        1617 : { pari_sp av = avma; return gc_long(av, itou(sqrtnint(divii(X,Y), n))); }
     222             : static long
     223       35982 : floorsqrtdiv(GEN X, GEN Y)
     224       35982 : { pari_sp av = avma; return gc_long(av, itou(gfloorsqrtdiv(X, Y))); }
     225             : static GEN
     226        5697 : ceildiv(GEN X, GEN Y)
     227             : {
     228        5697 :   GEN r, q = dvmdii(X, Y, & r);
     229        5698 :   return (r == gen_0)? q: addiu(q, 1);
     230             : }
     231             : 
     232             : static GEN
     233          35 : nfY(GEN T)
     234          35 : { T = shallowcopy(T); setvarn(T,1); return nfinit(T, MEDDEFAULTPREC); }
     235             : static GEN
     236       20189 : bnfY(GEN T)
     237       20189 : { T = shallowcopy(T); setvarn(T,1); return Buchall(T, nf_FORCE, MEDDEFAULTPREC); }
     238             : static GEN
     239       12229 : bnf_get_disc(GEN b) { return nf_get_disc(bnf_get_nf(b)); }
     240             : 
     241             : /* Compute n s.t. d | n <=> d^k | N. Return [n, factor(n)] */
     242             : static GEN
     243        1393 : cored(GEN N, long k)
     244             : {
     245        1393 :   GEN fa = Z_factor(N), P = gel(fa,1), E = gel(fa,2), n = gen_1;
     246        1393 :   long i, c, l = lg(P);
     247             : 
     248        2779 :   for (i = c = 1; i < l; i++)
     249             :   {
     250        1386 :     long e = itou(gel(E,i));
     251        1386 :     if (e >= k)
     252             :     {
     253         833 :       e /= k; n = mulii(n, powiu(gel(P,i), e));
     254         833 :       gel(P,c) = gel(P,i); gel(E,c) = utoipos(e); c++;
     255             :     }
     256             :   }
     257        1393 :   setlg(P,c); setlg(E,c); return mkvec2(n, fa);
     258             : }
     259             : 
     260             : /* return D = nfdisc(T), set d = coredisc */
     261             : static GEN
     262      644767 : nfcoredisc(GEN T, GEN *pd)
     263             : {
     264      644767 :   GEN D = nfdiscfactors(T), d = core(D); /* d = core(|D|) */
     265      644759 :   D = gel(D,1); if (signe(D) < 0) togglesign_safe(&d);
     266      644761 :   if (Mod4(d) != 1) d = shifti(d,2); /* = coredisc(D) */
     267      644766 :   *pd = d; return D;
     268             : }
     269             : static GEN
     270      629202 : nfcoredisc2(GEN T, GEN *pd, GEN *pf)
     271             : {
     272      629202 :   GEN D = nfcoredisc(T, pd);
     273      629202 :   if (pf) *pf = sqrti(diviiexact(D, *pd));
     274      629202 :   return D;
     275             : }
     276             : 
     277             : /* \prod {pr | ell} pr */
     278             : static GEN
     279        2849 : getpell(GEN nf, long ell, long *pteell)
     280             : {
     281        2849 :   GEN P = idealprimedec(nf, utoipos(ell));
     282        2849 :   *pteell = pr_get_e(gel(P,1)); return idealfactorback(nf, P, NULL, 0);
     283             : }
     284             : 
     285             : static void
     286        2912 : checkfield_i(GEN F, long d)
     287        2912 : { if (F && degpol(F) != d) pari_err_TYPE("nflist", F); }
     288             : static GEN
     289         427 : checkfield(GEN F, long d) { checkfield_i(F, d); return nfdisc(F); }
     290             : 
     291             : static long
     292       12677 : pol2s(GEN T) { return (degpol(T) - ZX_sturm_irred(T)) >> 1; }
     293             : 
     294             : static GEN
     295        2940 : sturmseparate(GEN V, long s, long deg)
     296             : {
     297             :   GEN w, C;
     298             :   long l, ls , i;
     299             : 
     300        2940 :   if (s != -2) return V;
     301         280 :   l = lg(V); ls = (deg >> 1) + 2;
     302         280 :   w = cgetg(ls, t_VEC);
     303         280 :   C = cgetg(ls, t_VECSMALL);
     304        1386 :   for (i = 1; i < ls; i++) { gel(w, i) = cgetg(l, t_VEC); C[i] = 1; }
     305       12502 :   for (i = 1; i < l; i++)
     306             :   {
     307       12222 :     long k = pol2s(gel(V, i)) + 1;
     308       12222 :     gmael(w, k, C[k]++) = gel(V, i);
     309             :   }
     310        1386 :   for (i = 1; i < ls; i++) setlg(gel(w, i), C[i]);
     311         280 :   return w;
     312             : }
     313             : 
     314             : /* fa = factorization of positive integer N. Are +N and/or -N fundamental ? */
     315             : static void
     316        2450 : fa_is_fundamental_pm(GEN N, GEN fa, long s, int *p, int *m)
     317             : {
     318        2450 :   GEN P = gel(fa,1), E = gel(fa,2);
     319        2450 :   long l = lg(P), i;
     320             :   ulong r, r4;
     321             : 
     322        2450 :   if (l == 1) { *m = 0; *p = (s <= 0); return; }
     323        2450 :   r = Mod16(N); r4 = r & 3UL;
     324        2450 :   if (!r || r4 == 2) { *p = *m = 0; return; } /* v_2 > 3 or N=2 mod 4 */
     325        1407 :   *p = (s <= 0);
     326        1407 :   *m = s? 1: 0;
     327        1407 :   if (odd(r))
     328             :   {
     329         658 :     if (r4 == 1) { *m = 0; if (!*p) return; }
     330         126 :     else         { *p = 0; if (!*m) return; }
     331         595 :     i = 1;
     332             :   }
     333             :   else
     334             :   { /* P[1] = 2 => 4 | N */
     335         749 :     if (r == 4)       { *p = 0; if (!*m) return; }
     336         357 :     else if (r == 12) { *m = 0; if (!*p) return; }
     337         525 :     i = 2;
     338             :   }
     339        2030 :   for (; i < l; i++)
     340        1008 :     if (itou(gel(E,i)) > 1) { *p = *m = 0; return; }
     341             : }
     342             : /* if flag is set assume the odd part of N is squarefree */
     343             : static void
     344      703137 : uis_fundamental_pm_i(ulong N, long s, int *p, int *m, long flag)
     345             : {
     346             :   ulong r, r4;
     347             : 
     348      703137 :   if (N == 1UL) { *m = 0; *p = (s <= 0); return; }
     349      703137 :   r = N & 15UL; r4 = r & 3UL;
     350      703137 :   if (!r || r4 == 2) { *p = *m = 0; return; } /* v_2 > 3 or N=2 mod 4 */
     351      602990 :   *p = (s <= 0);
     352      602990 :   *m = s? 1: 0;
     353      602990 :   if (odd(r))
     354             :   {
     355      396609 :     if (r4 == 1) { *m = 0; if (!*p) return; }
     356      198359 :     else         { *p = 0; if (!*m) return; }
     357             :   }
     358             :   else
     359             :   { /* P[1] = 2 => 4 | N */
     360      204574 :     if (r == 4)       { *p = 0; if (!*m) return; }
     361      132751 :     else if (r == 12) { *m = 0; if (!*p) return; }
     362      175618 :     N >>= (r == 8? 3: 2); /* odd part */
     363             :   }
     364      488202 :   if (!flag && !uissquarefree(N)) { *p = *m = 0; }
     365             : }
     366             : static void
     367      695733 : uis_fundamental_pm(ulong N, long s, int *p, int *m)
     368      695733 : { uis_fundamental_pm_i(N, s, p, m, 0); }
     369             : 
     370             : static void
     371      308910 : is_fundamental_pm(GEN N, long s, int *p, int *m)
     372             : {
     373             :   ulong r, r4;
     374             : 
     375      308910 :   if (lgefint(N) == 3) { uis_fundamental_pm(N[2], s, p, m); return; }
     376          42 :   r = Mod16(N); r4 = r & 3UL;
     377          42 :   if (!r || r4 == 2) { *p = *m = 0; return; } /* v_2 > 3 or N=2 mod 4 */
     378          35 :   *p = (s <= 0);
     379          35 :   *m = s? 1: 0;
     380          35 :   if (odd(r))
     381             :   {
     382          14 :     if (r4 == 1) { *m = 0; if (!*p) return; }
     383           7 :     else         { *p = 0; if (!*m) return; }
     384             :   }
     385             :   else
     386             :   { /* P[1] = 2 => 4 | N */
     387          21 :     if (r == 4)       { *p = 0; if (!*m) return; }
     388          14 :     else if (r == 12) { *m = 0; if (!*p) return; }
     389          21 :     N = shifti(N, r == 8? -3: -2); /* odd part */
     390             :   }
     391          35 :   if (!Z_issquarefree(N)) { *p = *m = 0; }
     392             : }
     393             : static GEN
     394        3500 : fund_pm(GEN N, int p, int m)
     395             : {
     396        3500 :   if (p && m) return mkvec2(N, negi(N));
     397        3297 :   if (p) return mkvec(N);
     398        2814 :   if (m) return mkvec(negi(N));
     399        2163 :   return NULL;
     400             : }
     401             : static GEN
     402        5243 : ufund_pm(ulong N, int p, int m)
     403             : {
     404        5243 :   if (p && m) return mkvec2(utoipos(N), utoineg(N));
     405        5103 :   if (p) return mkvec(utoipos(N));
     406        4123 :   if (m) return mkvec(utoineg(N));
     407        2849 :   return NULL;
     408             : }
     409             : 
     410             : /* return of fundamental discriminant divisors of N filtering by signature s.
     411             :  * if abs is set, only return their absolute values */
     412             : static GEN
     413        1127 : divisorsdisc_i(GEN N, long s, long abs)
     414             : {
     415             :   GEN D, V;
     416        1127 :   long l, c = 1, i;
     417             : 
     418        1127 :   if (typ(N) == t_VEC)
     419             :   { /* [n, factor(n)]; assume n > 0 */
     420        1008 :     GEN n = gel(N,1), fa = gel(N,2);
     421        1008 :     if (Mod4(n) == 2) N = mkvec2(shifti(n,-1), rowsplice(fa, 1));
     422             :   }
     423             :   else
     424         119 :     if (Mod4(N) == 2) N = shifti(N, -1);
     425        1127 :   D = divisors_factored(N); l = lg(D);
     426        1127 :   V = cgetg(2 * l - 1, t_VEC);
     427        3577 :   for (i = 2; i < l; i++)
     428             :   {
     429        2450 :     GEN d = gel(D, i), A = gel(d, 1);
     430             :     int p, m;
     431        2450 :     fa_is_fundamental_pm(A, gel(d,2), s, &p, &m);
     432        2450 :     if (abs)
     433        1393 :     { if (p || m) gel(V, c++) = A; }
     434             :     else
     435             :     {
     436        1057 :       if (p) gel(V, c++) = gel(d,1);
     437        1057 :       if (m) gel(V, c++) = negi(gel(d,1));
     438             :     }
     439             :   }
     440        1127 :   setlg(V, c); return V;
     441             : }
     442             : static GEN
     443         392 : divisorsdisc(GEN N, long s) { return divisorsdisc_i(N, s, 0); }
     444             : static GEN
     445         735 : divisorsabsdisc(GEN N, long s) { return divisorsdisc_i(N, s, 1); }
     446             : 
     447             : static int
     448        7857 : usum2sq(ulong m)
     449             : {
     450        7857 :   pari_sp av = avma;
     451             :   GEN fa, P, E;
     452        7857 :   long i, v2 = vals(m);
     453        7857 :   if (v2)
     454             :   {
     455        3897 :     if (v2 != 3) return 0;
     456        1133 :     m >>= 3;
     457             :   }
     458        5093 :   if ((m & 3L) != 1) return 0;
     459        4618 :   fa = factoru(m); P = gel(fa, 1); E = gel(fa, 2);
     460        7207 :   for (i = 1; i < lg(P); i++)
     461        4681 :     if (E[i] >= 2 || (P[i] & 3L) == 3) { set_avma(av); return 0; }
     462        2526 :   set_avma(av); return 1;
     463             : }
     464             : static int
     465         329 : sum2sq(GEN m)
     466             : {
     467         329 :   pari_sp av = avma;
     468             :   GEN fa, P, E;
     469             :   long i, v2;
     470         329 :   if (lgefint(m) == 3) return usum2sq(m[2]);
     471          18 :   v2 = vali(m);
     472          18 :   if (v2)
     473             :   {
     474           9 :     if (v2 != 3) return 0;
     475           8 :     m = shifti(m, -3);
     476             :   }
     477          17 :   if (Mod4(m) != 1) return 0;
     478          16 :   fa = Z_factor(m); P = gel(fa, 1); E = gel(fa, 2);
     479          31 :   for (i = 1; i < lg(P); i++)
     480          23 :     if (!equali1(gel(E,i)) || Mod4(gel(P,i)) == 3) { set_avma(av); return 0; }
     481           8 :   set_avma(av); return 1;
     482             : }
     483             : 
     484             : static int
     485      570899 : ok_int(GEN d, GEN X, GEN Xinf)
     486      570899 : { return (abscmpii(d, X) <= 0 && abscmpii(d, Xinf) >= 0); }
     487             : static int
     488        1788 : ok_intu(GEN d, ulong X, ulong Xinf)
     489        1788 : { return (abscmpiu(d, X) <= 0 && abscmpiu(d, Xinf) >= 0); }
     490             : 
     491             : static int
     492         917 : ok_disc(GEN d, GEN X, GEN Xinf)
     493             : {
     494         917 :   if (!Xinf) return absequalii(d, X);
     495         889 :   return ok_int(d, X, Xinf);
     496             : }
     497             : 
     498             : /* G cyclic galoisinit */
     499             : static GEN
     500        2632 : cyclicgalois(GEN bnr, GEN G, long *o)
     501             : {
     502        2632 :   GEN g = galoispermtopol(G, gel(gal_get_gen(G), 1));
     503        2632 :   *o = gal_get_orders(G)[1];
     504        2632 :   return bnrautmatrix(bnr, g); /* order o */
     505             : }
     506             : /* Cl_f / H cyclic of prime order, return i s.t bnr.cyc[i] is generator */
     507             : static long
     508        1288 : cyclicprimegen(GEN H)
     509             : {
     510        1288 :   long i, l = lg(H);
     511        1302 :   for (i = 1; i < l; i++) if (!is_pm1(gcoeff(H,i,i))) return i;
     512             :   return -1;/*LCOV_EXCL_LINE*/
     513             : }
     514             : /* k/Q cyclic and M the bnrautmatrix for the generator s of its Galois group
     515             :  * (action on bnr = Cl_f(k)). vH a vector of congruence subgroups for bnr,
     516             :  * attached to abelian extensions K/k of prime degree, assumed to be Galois
     517             :  * over Q [sf = f and sH = H]. Filter out the H corresponding to K/Q abelian */
     518             : static void
     519        1260 : nonabelianfilter(GEN vH, GEN M)
     520             : {
     521        1260 :   long i, c, l = lg(vH);
     522        2548 :   for (i = c = 1; i < l; i++)
     523             :   {
     524        1288 :     GEN v, H = gel(vH,i);
     525        1288 :     long k = cyclicprimegen(H);
     526        1288 :     v = shallowcopy(gel(M,k));
     527        1288 :     gel(v,k) = subiu(gel(v,k), 1);
     528        1288 :     if (!hnf_invimage(H, v)) gel(vH, c++) = H;
     529             :   }
     530        1260 :   setlg(vH, c);
     531        1260 : }
     532             : 
     533             : 
     534             : /* bnf attached to K. Cyclic extensions L/K of degree d and exact conductor
     535             :  * F; if F = [F,Finf]~, check that Finf | conductor | F;
     536             :  * check that |disc L/Q| in [Xinf,X] if not NULL. If G != NULL,
     537             :  * then K/Q = <s> is cyclic, we assume s.F = F and
     538             :  * G = [galoisinit(bnf), flag], with flag > 0 (resp. 0) to insist L be
     539             :  * Galois / Q (resp. not Galois). If flag = 2, insist that L/Q is non abelian.
     540             :  * In the non-Galois case, keep only one among isomorphic extensions attached
     541             :  * to sigma.H; sigma in Gal(K/Q). For simplicity assume the base is cyclic;
     542             :  * will extend it later if needed. */
     543             : static GEN
     544      184635 : mybnrclassfield_X(GEN bnf, GEN F, long d, GEN X, GEN Xinf, GEN G)
     545             : {
     546      184635 :   GEN gd = utoipos(d), Finf = NULL, bnr, L;
     547             :   long i, j, c, l;
     548             : 
     549      184626 :   if (typ(F) == t_COL) { Finf = gel(F,1); F = gel(F,2); }
     550      184626 :   bnr = bnrinitmod(bnf, F, 0, gd);
     551      184652 :   L = subgrouplist0(bnr, mkvec(gd), Finf? 1: 0); l = lg(L);
     552      184642 :   if (Finf)
     553             :   {
     554        2135 :     GEN Fi = idealinv(bnr, Finf);
     555        2282 :     for (i = c = 1; i < l; i++)
     556             :     { /* for now assume that F and Finf are finite */
     557         147 :       GEN f = gel(bnrconductor_raw(bnr, gel(L,i)), 1);
     558         147 :       if (equali1(Q_denom(idealmul(bnr, f, Fi)))) gel(L,c++) = gel(L,i);
     559             :     }
     560        2135 :     setlg(L, c); l = c;
     561             :   }
     562      184642 :   if (l == 1) return L;
     563       38059 :   if (!uisprime(d))
     564             :   {
     565         189 :     for (i = j = 1; i < l; i++)
     566          98 :       if (lg(smithclean(ZM_snf(gel(L,i)))) == 2) gel(L,j++) = gel(L,i);
     567          91 :     setlg(L, l = j); if (l == 1) return L;
     568             :   }
     569       38017 :   if (G)
     570             :   {
     571             :     GEN M;
     572        8540 :     long o, gal = itou(gel(G,2));
     573        8540 :     if (l == 2)
     574             :     {  /* => L[1] is fixed: must be Galois */
     575        8071 :       if (!gal) { setlg(L,1); return L; }
     576        1211 :       if (gal == 2)
     577             :       {
     578        1211 :         M = cyclicgalois(bnr, gel(G,1), &o);
     579        1211 :         nonabelianfilter(L, M);
     580             :       }
     581             :     }
     582             :     else
     583             :     {
     584        1421 :       M = cyclicgalois(bnr, gel(G,1), &o); /* assume cyclic for now */
     585        1421 :       if (gal)
     586             :       {
     587         224 :         for (i = j = 1; i < l; i++)
     588             :         {
     589         175 :           GEN H = gel(L,i);
     590         175 :           if (ZM_equal(bnrgaloisapply(bnr, M, H), H)) gel(L,j++) = H;
     591             :         }
     592          49 :         setlg(L, l = j);
     593          49 :         if (gal == 2) nonabelianfilter(L, M);
     594             :       }
     595             :       else
     596             :       {
     597        3766 :         for (i = 1; i < l; i++)
     598             :         {
     599        2394 :           GEN H = gel(L,i), K = bnrgaloisapply(bnr, M, H);
     600             :           long k;
     601             : 
     602             :           /* \sigma H = H <=> Galois : delete */
     603        2394 :           if (ZM_equal(K, H)) { L = vecsplice(L,i--); l--; continue; }
     604             :           /* else delete the rest of Galois orbit */
     605         952 :           for (j = 1; j < o; j++)
     606             :           {
     607         476 :             for (k = i+1; k < l; k++)
     608         476 :               if (ZM_equal(K, gel(L,k))) { L = vecsplice(L,k); l--; break; }
     609         476 :             if (j != o-1) K = bnrgaloisapply(bnr, M, K);
     610             :           }
     611             :         }
     612             :       }
     613             :     }
     614        2632 :     if ((l = lg(L)) == 1) return L;
     615             :   }
     616       31157 :   if (X)
     617             :   {
     618        1834 :     for (i = j = 1; i < l; i++)
     619             :     {
     620         917 :       GEN D = gel(bnrdisc(bnr, gel(L,i), 0), 3);
     621         917 :       if (ok_disc(D, X, Xinf)) gel(L,j++) = gel(L,i);
     622             :     }
     623         917 :     setlg(L, j); if (j == 1) return L;
     624             :   }
     625       30905 :   return shallowconcat1(bnrclassfield(bnr, L, 0, MEDDEFAULTPREC));
     626             : }
     627             : static GEN
     628          28 : mybnrclassfield_N(GEN bnf, GEN F, GEN N, long d)
     629          28 : { return mybnrclassfield_X(bnf, F, d, N, NULL, NULL); }
     630             : static GEN
     631      145268 : mybnrclassfield(GEN bnf, GEN F, long d)
     632      145268 : { return mybnrclassfield_X(bnf, F, d, NULL, NULL, NULL); }
     633             : 
     634             : /* N > 1 */
     635             : static int
     636        6949 : checkcondell_i(GEN N, long ell, GEN D2, GEN *pP)
     637             : {
     638             :   GEN fa, P, E;
     639             :   long l, i, e;
     640             : 
     641        6949 :   if (typ(N) == t_VEC)
     642             :   {
     643        4534 :     fa = gel(N,2); P = gel(fa, 1); E = gel(fa, 2);
     644        4534 :     i = ZV_search(P, utoipos(ell));
     645        4537 :     if (!i) e = 0;
     646             :     else
     647             :     {
     648         923 :       e = itou(gel(E,i)); if (e != 2) return 0;
     649         161 :       P = vecsplice(P, i);
     650         161 :       E = vecsplice(E, i);
     651             :     }
     652             :   }
     653             :   else
     654             :   {
     655        2415 :     e = Z_lvalrem(N, ell, &N);
     656        2415 :     if (e != 0 && e != 2) return 0;
     657        2065 :     fa = Z_factor(N); P = gel(fa, 1); E = gel(fa, 2);
     658             :   }
     659        5840 :   l = lg(P);
     660        7163 :   for (i = 1; i < l; i++)
     661             :   {
     662        5922 :     GEN p = gel(P,i);
     663             :     long r;
     664        5922 :     if (!equaliu(gel(E,i), 1)) return 0;
     665        5367 :     r = umodiu(p, ell);
     666        5371 :     if (!D2) { if (r != 1) return 0; }
     667             :     else
     668             :     {
     669        2027 :       r -= kronecker(D2, p);
     670        2030 :       if (r && r != ell) return 0;
     671             :     }
     672             :   }
     673        1241 :   *pP = P; return 1;
     674             : }
     675             : /* ell odd prime, N potential conductor for C_ell field, *pP contains
     676             :  * the prime divisors of N different from ell */
     677             : static int
     678        4753 : checkcondCL(GEN N, long ell, GEN *pP)
     679        4753 : { GEN n = typ(N) == t_VEC? gel(N, 1): N;
     680        4753 :   return odd(Mod4(n)) && !equali1(n) && checkcondell_i(N, ell, NULL, pP); }
     681             : /* D2 fundamental discriminant, ell odd prime, N potential conductor for
     682             :  * D_ell field over Q(sqrt(D2)) */
     683             : static int
     684       10437 : checkcondDL(GEN D2, GEN N, long ell, GEN *pP)
     685             : {
     686             :   ulong N4;
     687       10437 :   if (!umodiu(D2, ell))
     688             :   {
     689        1771 :     long v = Z_lvalrem(N, ell, &N);
     690        1771 :     if (v && v > 2) return 0;
     691             :   }
     692       10437 :   if (equali1(N)) { *pP = cgetg(1,t_VEC); return 1; }
     693        3850 :   N4 = Mod4(N);
     694        3850 :   return N4 && (N4 != 2 || ell == 3) && checkcondell_i(N, ell, D2, pP);
     695             : }
     696             : 
     697             : static GEN
     698       57610 : myshallowconcat1(GEN V)
     699             : {
     700       57610 :   if (lg(V) == 1) return V;
     701       16653 :   return shallowconcat1(V);
     702             : }
     703             : 
     704             : static GEN
     705       31679 : _nfsubfields(GEN pol, long d) { return nfsubfields0(pol, d, 1); }
     706             : static GEN
     707       28459 : _nfsubfields1(GEN pol, long d) { return gel(_nfsubfields(pol, d), 1); }
     708             : static GEN
     709          63 : mynfsubfields(GEN pol, long d)
     710             : {
     711          63 :   GEN V = _nfsubfields(pol, d), W;
     712          63 :   long l = lg(V), i;
     713          63 :   W = cgetg(l, t_VEC);
     714         273 :   for (i = 1; i < l; i++) gel(W,i) = polredabs(gel(V,i));
     715          63 :   return W;
     716             : }
     717             : static GEN
     718         217 : mynfsubfield(GEN pol, long d)
     719             : {
     720         217 :   if (d == 2 && (degpol(pol) & 3) == 2)
     721          70 :     return quadpoly_i(quaddisc(ZX_disc(pol)));
     722         147 :   return polredabs(gel(_nfsubfields(pol, d), 1));
     723             : }
     724             : 
     725             : /* global checks to be done:
     726             : -- in nflist: if s > deg / 2, return empty.
     727             : -- in nfresolvent: check polynomial of correct degree.
     728             : */
     729             : 
     730             : /***************************************************************/
     731             : 
     732             : static GEN
     733          63 : makeC1(GEN N, GEN field, long s)
     734             : {
     735          63 :   checkfield_i(field, 1);
     736          63 :   if (!equali1(N)) return NULL;
     737          63 :   return mkvec(s != -2? pol_x(0): mkvec(pol_x(0)));
     738             : }
     739             : static GEN
     740          21 : makeC1resolvent(long flag)
     741          21 : { return odd(flag)? mkvec2(pol_x(0), gen_1): pol_x(0); }
     742             : static GEN
     743          28 : makeC1vec(GEN Xinf, GEN field, long s) { return makeC1(Xinf, field, s); }
     744             : 
     745             : /**********************************************************************/
     746             : /*                                 C2                                 */
     747             : /**********************************************************************/
     748             : static GEN
     749         140 : makeC2(GEN N, GEN field, long s)
     750             : {
     751         140 :   GEN V = NULL;
     752             :   long l, i;
     753             :   int p, m;
     754             : 
     755         140 :   checkfield_i(field, 1);
     756         140 :   if (equali1(N) || Mod4(N) == 2) return NULL;
     757         112 :   is_fundamental_pm(N, s, &p, &m);
     758         112 :   if (!(V = fund_pm(N, p, m))) return NULL;
     759          98 :   l = lg(V);
     760         224 :   for (i = 1; i < l; i++) gel(V, i) = quadpoly_i(gel(V, i));
     761          98 :   return sturmseparate(V, s, 2);
     762             : }
     763             : 
     764             : static GEN
     765          14 : makeC2resolvent(GEN pol, long flag)
     766          14 : { return odd(flag)? mkvec2(pol_x(0), absi_shallow(nfdisc(pol))): pol_x(0); }
     767             : 
     768             : static GEN
     769         182 : makeC2vec(GEN X, GEN Xinf, GEN field, long s)
     770             : {
     771         182 :   long M, cv, cw, l = itou(subii(X, Xinf)) + 1;
     772             :   GEN v, w;
     773             : 
     774         182 :   checkfield_i(field, 1);
     775         182 :   v = (s <= 0)? cgetg(l, t_VEC): NULL;
     776         182 :   w = s? cgetg(l, t_VEC): NULL;
     777      305592 :   for (M = equali1(Xinf)? 2: 1, cv = cw = 1; M < l; M++)
     778             :   {
     779      305410 :     GEN N = addiu(Xinf, M);
     780             :     int p, m;
     781      305410 :     is_fundamental_pm(N, s, &p, &m);
     782      305410 :     if (p) gel(v, cv++) = quadpoly_i(N);
     783      305410 :     if (m) gel(w, cw++) = quadpoly_i(negi(N));
     784             :   }
     785         182 :   if (cv == 1 && cw == 1) return NULL;
     786         182 :   switch (s)
     787             :   {
     788          56 :     case 0:  setlg(v, cv); return v;
     789          56 :     case 1:  setlg(w, cw); return w;
     790          63 :     case -1: setlg(v, cv); setlg(w, cw); return shallowconcat(v, w);
     791           7 :     default: setlg(v, cv); setlg(w, cw); return mkvec2(v, w);
     792             :   }
     793             : }
     794             : 
     795             : /**********************************************************************/
     796             : /*                                 C3                                 */
     797             : /**********************************************************************/
     798             : /* \prod x[i]^e[i], e[i] in {0,1} */
     799             : static GEN
     800       23968 : eltlist2(GEN nf, GEN x)
     801             : {
     802       23968 :   long i, j, c, l = lg(x);
     803             :   GEN v;
     804       23968 :   if (l == 1) return mkvec(gen_1);
     805       23968 :   v = cgetg((1 << (l-1))+1, t_VEC);
     806       23968 :   gel(v,1) = gen_1;
     807       23968 :   gel(v,2) = gel(x,1);
     808       33748 :   for (i = c = 2; i < l; i++, c <<= 1)
     809       30162 :     for (j = 1; j <= c; j++) gel(v, c + j) = nfmul(nf, gel(v,j), gel(x,i));
     810       23969 :   return v;
     811             : }
     812             : /* { x[1][1] * \prod_i>=2 x[i][e_i], (e) in {1,2}^(#x-1)} */
     813             : static GEN
     814         112 : mullist2(GEN x)
     815             : {
     816         112 :   long i, j, c, l = lg(x);
     817             :   GEN v;
     818         112 :   if (l == 2) return mkvec(gmael(x,1,1));
     819          14 :   v = cgetg((1 << (l-2))+1, t_VEC);
     820          14 :   gel(v,1) = gel(v,2) = gmael(x,1,1);
     821          28 :   for (i = 2, c = 1; i < l; i++, c <<= 1)
     822          28 :     for (j = 1; j <= c; j++)
     823             :     {
     824          14 :       gel(v, c + j) = gmul(gel(v, j), gmael(x,i,2));
     825          14 :       gel(v, j) = gmul(gel(v, j), gmael(x,i,1));
     826             :     }
     827          14 :   return v;
     828             : }
     829             : 
     830             : static GEN
     831         126 : makepolC3(GEN n, GEN u, long fl3)
     832             : {
     833         126 :   GEN T = cgetg(6, t_POL), n3, nu27;
     834         126 :   T[1] = evalsigne(1) | evalvarn(0);
     835         126 :   gel(T, 5) = gen_1;
     836         126 :   gel(T, 4) = fl3 ? gen_m1 : gen_0;
     837         126 :   if (!fl3)
     838          49 :   { n3 = divis(n, -3); nu27 = mulii(n, u); }
     839             :   else
     840          77 :   { n3 = divis(subiu(n, 1), -3); nu27 = addiu(mulii(n, subiu(u, 3)), 1); }
     841         126 :   gel(T, 3) = n3;
     842         126 :   gel(T, 2) = divis(nu27, -27); return T;
     843             : }
     844             : 
     845             : static GEN
     846         126 : decp(GEN Q, GEN t, GEN p)
     847             : {
     848             :   GEN u, v, z;
     849         126 :   if (equaliu(p, 3)) { u = utoineg(3); v = utoipos(3); }
     850             :   else
     851             :   {
     852          91 :     GEN uv = qfbsolve(Q, shifti(p, 2), 2);
     853          91 :     u = gel(uv,1); if (umodiu(u, 3) == 1) togglesign(u);
     854          91 :     v = muliu(gel(uv,2), 3); if (signe(v) < 0) togglesign(v);
     855             :   }
     856         126 :   z = gadd(gmul(v, t), shifti(subii(u, v), -1));
     857         126 :   return mkvec2(z, conj_i(z));
     858             : }
     859             : 
     860             : static int
     861         357 : checkcondC3(GEN n, GEN *pP)
     862             : {
     863         357 :   GEN fa = NULL, P, E;
     864             :   long l, i, n27;
     865             : 
     866         357 :   *pP = NULL;
     867         357 :   if (typ(n) == t_VEC) { fa = gel(n,2); n = gel(n,1); }
     868         357 :   if (cmpiu(n, 7) < 0 || !mpodd(n)) return 0;
     869         133 :   n27 = umodiu(n, 27);
     870         133 :   switch(n27 % 3)
     871             :   {
     872           7 :     case 2: return 0;
     873          77 :     case 1: i = 1; break;
     874          49 :     default: i = 2; if (n27 != 9 && n27 != 18) return 0;
     875             :   }
     876         112 :   if (!fa) fa = Z_factor(n);
     877         112 :   P = gel(fa, 1); E = gel(fa, 2); l = lg(P);
     878         203 :   for (; i < l; i++)
     879          91 :     if (umodiu(gel(P,i), 3) != 1 || !equali1(gel(E,i))) return 0;
     880         112 :   *pP = P; return 1;
     881             : }
     882             : 
     883             : static GEN
     884         112 : makeC3_i(GEN sqN, GEN P)
     885             : {
     886         112 :   GEN v, t, Q = mkqfb(gen_1, gen_0, utoipos(27), utoineg(108));
     887         112 :   long i, j, l, n = lg(P)-1, fl3 = umodiu(gel(P,1), 3);
     888             : 
     889         112 :   t = quadgen0(utoineg(3), 1); v = cgetg(n+1, t_VEC);
     890         238 :   for (i = 1; i <= n; i++) gel(v,i) = decp(Q, t, gel(P,i));
     891         112 :   v = mullist2(v); l = lg(v);
     892         238 :   for (j = 1; j < l; j++) gel(v,j) = makepolC3(sqN, gtrace(gel(v,j)), fl3);
     893         112 :   return v;
     894             : }
     895             : /* makeC3(f^2, 0) */
     896             : static GEN
     897         322 : makeC3_f(GEN f)
     898             : {
     899             :   GEN P;
     900         322 :   return checkcondC3(f, &P)? makeC3_i(f, P): cgetg(1, t_VEC);
     901             : }
     902             : static GEN
     903          70 : vecs(long ns, GEN x)
     904          70 : { GEN v = const_vec(ns, cgetg(1,t_VEC)); gel(v,1) = x; return v; }
     905             : static GEN
     906          14 : vecs14(GEN x, GEN y) { GEN v = cgetg(1,t_VEC); return mkvec4(x,v,v,y); }
     907             : 
     908             : static GEN
     909          77 : makeC3(GEN N, GEN field, long s)
     910             : {
     911             :   GEN v, f, P;
     912             : 
     913          77 :   checkfield_i(field, 1);
     914          77 :   if (s > 0 || cmpiu(N, 49) < 0 || !Z_issquareall(N, &f)
     915          77 :       || !checkcondC3(f, &P)) return NULL;
     916          14 :   v = makeC3_i(f, P); return s == -2 ? vecs(2, v): v;
     917             : }
     918             : 
     919             : static GEN
     920          14 : makeC3resolvent(GEN pol, long flag)
     921          14 : { return odd(flag)? mkvec2(pol_x(0), sqrti(nfdisc(pol))): pol_x(0); }
     922             : 
     923             : GEN
     924        4191 : nflist_C3_worker(GEN gv, GEN T)
     925             : {
     926        4191 :   long v = itos(gv), sX = T[1], sXinf = T[2], c, r, u;
     927        4191 :   long v227 = 27 * v * v, limu = usqrt((sX << 2) - v227);
     928        4191 :   GEN V = cgetg(limu + 2, t_VEC);
     929             : 
     930        4191 :   if (odd(limu - v)) limu--; /* make sure u = v (mod 2) */
     931     1504355 :   for (u = -limu, r = smodss(u, 9), c = 1; u <= limu; u += 2, r += 2)
     932             :   {
     933     1500299 :     if (r >= 9) r -= 9; /* r = u % 9 */
     934     1500299 :     if (r == 2 || r == 5 || r == 6 || r == 8) /* u = 2 (mod 3) or 6 (mod 9) */
     935             :     {
     936             :       long e;
     937      680497 :       if (ugcd(labs(u), v) > 2) continue;
     938      481303 :       e = (u * u + v227) >> 2; /* conductor, disc = e^2 */
     939      481303 :       if (e < sXinf) continue;
     940      481303 :       if (r == 6) e /= 9; /* 9 | e */
     941      481303 :       if (!uissquarefree(e)) continue;
     942      400592 :       gel(V, c++) = r==6? mkvecsmall4(1, 0, -3 * e, -e * u / 3)
     943      396737 :                         : mkvecsmall4(1, -1, (1-e) / 3, -(1 + e * (u-3)) / 27 );
     944             :     }
     945             :   }
     946        4056 :   setlg(V, c); return V;
     947             : }
     948             : 
     949             : static GEN
     950         217 : zvV_to_ZXV(GEN v)
     951             : {
     952         217 :   long i, l = lg(v);
     953         217 :   GEN w = cgetg(l, t_VEC);
     954      336917 :   for (i = 1; i < l; i++) gel(w,i) = gtopoly(gel(v,i), 0);
     955         217 :   return w;
     956             : }
     957             : static GEN
     958         196 : C3vec(GEN V, long s)
     959             : {
     960         196 :   if (s != -2) return zvV_to_ZXV(V);
     961           7 :   retmkvec2(zvV_to_ZXV(V), cgetg(1,t_VEC));
     962             : }
     963             : 
     964             : /* t a C3 t_VECSMALL generated by C3_worker. Return its conductor f */
     965             : static long
     966      415044 : uC3pol_f(GEN t) { return - t[2] - 3 * t[3]; }
     967             : /* t a C3 t_POL = gtopoly(C3_worker t_VECSMALL) */
     968             : static GEN
     969         861 : C3pol_f(GEN t) { return subii(mulsi(-3, gel(t,3)), gel(t,4)); }
     970             : /* C3vec for discriminant f^2, f in [sX,sXinf] */
     971             : static GEN
     972         231 : C3vec_F(long sX, long sXinf, GEN *pF)
     973             : {
     974         231 :   GEN v, F, perm, T = mkvecsmall2(sX, sXinf);
     975         231 :   long i, l, lim = usqrt((sX << 2) / 27);
     976         231 :   v = nflist_parapply("_nflist_C3_worker", mkvec(T), identity_ZV(lim));
     977         231 :   v = myshallowconcat1(v); l = lg(v); if (l == 1) return NULL;
     978         231 :   F = cgetg(l, t_VECSMALL);
     979      415275 :   for (i = 1; i < l; i++) F[i] = uC3pol_f(gel(v,i));
     980         231 :   perm = vecsmall_indexsort(F);
     981         231 :   if (pF) *pF = vecsmallpermute(F, perm);
     982         231 :   return vecpermute(v, perm);
     983             : }
     984             : static GEN
     985         224 : makeC3vec(GEN X, GEN Xinf, GEN field, long s)
     986             : {
     987             :   GEN v;
     988         224 :   checkfield_i(field, 1);
     989         224 :   if (s > 0 || !(v = C3vec_F(floorsqrt(X), ceilsqrt(Xinf), NULL))) return NULL;
     990         196 :   return C3vec(v, s);
     991             : }
     992             : 
     993             : /**********************************************************************/
     994             : /*                                 S3                                 */
     995             : /**********************************************************************/
     996             : /* Quadratic resolvent field. */
     997             : 
     998             : static GEN makeDL(long ell, GEN N, GEN field, long s);
     999             : static GEN makeDLvec(long ell, GEN X, GEN Xinf, GEN field, long s);
    1000             : 
    1001             : /* Cubic programs from KB and HC */
    1002             : #define min(a, b) ((a) >= (b) ? b : a)
    1003             : #define max(a, b) ((a) >= (b) ? a : b)
    1004             : 
    1005             : static GEN
    1006     1095962 : checkU(long a, long b, long c, long d, long P, long Q, long R, long D)
    1007             : {
    1008     1095962 :   long t, f = cgcd(cgcd(P, Q), R);
    1009             :   GEN F;
    1010             : 
    1011     1089517 :   if (odd(f)) { long e = D & 15L; if (e == 0 || e == 12) return NULL; }
    1012      243961 :   else if ((D & 7L) == 0) return NULL;
    1013      819431 :   if (f % 3 == 0)
    1014             :   {
    1015       86099 :     if ((a % 9 == 0) || (a % 3 && (d % 9 == 0))) return NULL;
    1016       77546 :     if ((a % 3) && (d % 3))
    1017             :     {
    1018       47951 :       long e = (a - d) % 3 ? - 1 : 1;
    1019       47951 :       if ((a + c - e * (b + d)) % 9 == 0) return NULL;
    1020             :     }
    1021       62277 :     if (!uissquarefree(f / 9)) return NULL;
    1022             :   }
    1023      733332 :   else if (D % 27 == 0 || !uissquarefree(f)) return NULL;
    1024     1577421 :   t = labs(D) / (f * f); t >>= vals(t); while (t % 3 == 0) t /= 3;
    1025      732114 :   if (cgcd(t, f) > 1 || !uissquarefree(t)) return NULL;
    1026      689354 :   F = cgetg(6, t_POL); F[1] = evalsigne(1)|evalvarn(0);
    1027      689094 :   gel(F,2) = stoi(d * a * a);
    1028      685454 :   gel(F,3) = stoi(c * a);
    1029      687559 :   gel(F,4) = stoi(b);
    1030      685872 :   gel(F,5) = gen_1; return F;
    1031             : }
    1032             : 
    1033             : /* ceil(m/d), assume d != 0 */
    1034             : static long
    1035     2164989 : sceildiv(long m, long d)
    1036             : {
    1037             :   long q;
    1038     2164989 :   if (d == 1) return m;
    1039     1922831 :   if (!m) return 0;
    1040     1921067 :   if (d < 0) { d = -d; m = -m; }
    1041     1921067 :   if (m < 0) return -((-m) / d);
    1042      376736 :   q = m / d; return m%d? q+1: q;
    1043             : }
    1044             : /* floor(m/d), assume d != 0 */
    1045             : static long
    1046     1191087 : sfloordiv(long m, long d)
    1047             : {
    1048             :   long q;
    1049     1191087 :   if (d == 1) return m;
    1050     1071429 :   if (!m) return 0;
    1051     1056762 :   if (d < 0) { d = -d; m = -m; }
    1052     1056762 :   if (m > 0) return m / d;
    1053      123349 :   q = -((-m) / d); return (-m)%d? q-1: q;
    1054             : }
    1055             : 
    1056             : GEN
    1057         427 : nflist_S3R_worker(GEN ga, GEN S)
    1058             : {
    1059         427 :   long a = itos(ga), a3 = 3 * a, a9 = 9 * a, b, c, d, ct = 1;
    1060         427 :   long x = S[1], xinf = S[2], sqx = S[3], cplus = S[4], cminus = S[5];
    1061         427 :   long cmin = S[6], Dmin = S[7], Dsup = S[8], bsup = S[9], binf = S[10];
    1062         427 :   long csupa = usqrtn(cplus / a, 3), cinfa = sceilsqrtn(sceildiv(cminus, a), 3);
    1063         427 :   long dsupa = Dsup / a, dinfa = sceildiv(Dmin, a);
    1064         427 :   GEN RET = cgetg(x / 3, t_VEC);
    1065             : 
    1066       10786 :   for (b = binf; b <= bsup; b++)
    1067             :   {
    1068       10359 :     long cinf = cinfa, csup = csupa, dinfb = dinfa, dsupb = dsupa;
    1069       10359 :     long bb = b * b, b3 = 3 * b, gcdab = cgcd(a, b);
    1070       10362 :     if (b)
    1071             :     {
    1072        9937 :       long bbb = bb * b, sqxb = sqx / labs(b), m, M;
    1073        9937 :       if (b < 0)
    1074             :       {
    1075        4667 :         cinf = -sqxb; csup = -1;
    1076        4667 :         M = sfloordiv(cminus,bbb);
    1077        4667 :         m = sceildiv(cplus, bbb);
    1078             :       }
    1079             :       else
    1080             :       {
    1081        5270 :         cinf = cmin; csup = minss(csup, sqxb);
    1082        5270 :         M = cplus / bbb;
    1083        5270 :         m = sceildiv(cminus, bbb);
    1084             :       }
    1085        9937 :       dsupb = minss(dsupb, M);
    1086        9936 :       dinfb = maxss(dinfb, m); cinf = maxss(cinfa, cinf);
    1087             :     }
    1088      241891 :     for (c = cinf; c <= csup; c++)
    1089             :     {
    1090      230417 :       long dsup, dinf, gcdabc = cgcd(gcdab, c);
    1091      230466 :       long bc = b * c, cc = c * c, P = bb - a3 * c;
    1092      230466 :       dsup = minss(dsupb, sfloordiv(bc, a9)); /* Q >= 0 */
    1093             :       /* bc-9ad <= 4x / 3c^2 */
    1094      230954 :       dinf = c? maxss(dinfb, sceildiv(bc - ((4 * x) / (cc * 3)), a9)): dinfb;
    1095     2765095 :       for (d = dinf; d <= dsup; d++)
    1096             :       {
    1097             :         long Q, R, D, DF;
    1098             :         GEN F;
    1099     2533568 :         if (cgcd(gcdabc, d) > 1) continue;
    1100     2383265 :         Q = bc - a9 * d; if (Q < 0 || Q > P) continue;
    1101      881212 :         if (Q == 0 && b <= 0) continue;
    1102      872359 :         R = cc - b3 * d; if (P > R) continue;
    1103      512938 :         D = 4 * P * R - Q * Q; DF = D / 3; if (DF > x || DF < xinf) continue;
    1104      230290 :         if (P == Q && (Q == R || labs(b) >= labs(3 * a - b))) continue;
    1105      221884 :         if (P == R && (a > labs(d) || (a == labs(d) && labs(b) >= labs(c))))
    1106        2464 :           continue;
    1107      219420 :         if ((F = checkU(a, b, c, d, P, Q, R, D))) gel(RET, ct++) = F;
    1108             :       }
    1109             :     }
    1110             :   }
    1111         427 :   setlg(RET, ct); return RET;
    1112             : }
    1113             : 
    1114             : /* x >= xinf >= 1 */
    1115             : static GEN
    1116         203 : cubicreal(long x, long xinf)
    1117             : {
    1118             :   double sqx, sqx4, sq13, sq3x;
    1119             :   long A, bsup, binf, cmin, cplus, cminus, Dmin, Dsup;
    1120             :   GEN V, S;
    1121             : 
    1122         203 :   if (x < 148) return NULL;
    1123         182 :   sqx = sqrt((double)x); sq3x = sqrt((double)(3 * x)); sqx4 = sqrt(sqx);
    1124         182 :   sq13 = sqrt(13.);
    1125         182 :   cplus = ((-35 + 13 * sq13) * x) / 216;
    1126         182 :   cminus = ceil((-(35 + 13 * sq13) * x) / 216);
    1127         182 :   cmin = ceil(-sq3x / 4);
    1128         182 :   Dmin = ceil(-4./27 * sqx);
    1129         182 :   Dsup = sq3x / 36;
    1130         182 :   A = floor(sqx4 * 2. / sqrt(27));
    1131         182 :   bsup = floor(sqx4 * 2. / sqrt(3));
    1132         182 :   binf = ceil(-sqx4);
    1133         182 :   S = mkvecsmalln(10, x, xinf, (long)sqx, cplus, cminus, cmin, Dmin, Dsup,
    1134             :                   bsup, binf);
    1135         182 :   V = nflist_parapply("_nflist_S3R_worker", mkvec(S), identity_ZV(A));
    1136         182 :   V = myshallowconcat1(V); return lg(V) == 1? NULL: V;
    1137             : }
    1138             : 
    1139             : GEN
    1140        1027 : nflist_S3I_worker(GEN ga, GEN S)
    1141             : {
    1142        1027 :   long a = itos(ga), a3 = a * 3, a9 = a * 9, b, c, d, ct = 1;
    1143        1027 :   long x = S[1], xinf = S[2], cplus = S[3], Dsup = S[4], limb = S[5];
    1144        1027 :   long x4 = x * 4, csupa = usqrtn(cplus / a, 3), dsupa = Dsup / a;
    1145        1027 :   GEN RET = cgetg(x, t_VEC);
    1146             : 
    1147       19452 :   for (b = 0; b <= limb; b++)
    1148             :   {
    1149       18423 :     long b3 = b * 3, bb = b * b, gcdab = cgcd(a, b);
    1150       18426 :     long apb = a + b, amb = a - b;
    1151       18426 :     long dsupb = b? minuu(dsupa, cplus / (bb * b)): dsupa;
    1152       18427 :     long csup = b? min(csupa, 4 * Dsup / b): csupa;
    1153      989325 :     for (c = -csup; c <= csup; c++)
    1154             :     {
    1155      972932 :       long dsup = dsupb, dinf = b? -dsupb: 1, gcdabc = cgcd(gcdab, c);
    1156      972166 :       long bc = b * c, cc = c * c, P = bb - a3 * c;
    1157      972166 :       if (c)
    1158             :       { /* c^2|bc-9ad| <= 4x */
    1159      955856 :         long t = x4 / cc;
    1160      955856 :         dsup = minss(dsup, sfloordiv(bc + t, a));
    1161      957931 :         dinf = maxss(dinf, sceildiv(bc - t, a));
    1162             :       }
    1163      975347 :       dinf = maxss(dinf, sceildiv(-amb * (amb + c) + 1, a));
    1164      973470 :       dsup = minss(dsup, (apb * (apb + c) - 1) / a);
    1165    21395404 :       for (d = dinf; d <= dsup; d++)
    1166             :       {
    1167             :         GEN F;
    1168             :         long Q, R, D, DF;
    1169    20424506 :         if (!d || cgcd(gcdabc, d) > 1) continue;
    1170    18703379 :         if (d * (d - b) + a * (c - a) <= 0) continue;
    1171    12414742 :         Q = bc - a9 * d;
    1172    12414742 :         R = cc - b3 * d; D = 4 * P * R - Q * Q; DF = D / 3;
    1173    12414742 :         if (DF > -xinf || DF < -x) continue;
    1174      875243 :         if ((F = checkU(a, b, c, d, P, Q, R, D))) gel(RET, ct++) = F;
    1175             :       }
    1176             :     }
    1177             :   }
    1178        1029 :   setlg(RET, ct); return RET;
    1179             : }
    1180             : 
    1181             : static GEN
    1182         175 : cubicimag(long x, long xinf)
    1183             : {
    1184             :   double sqx, sqx4;
    1185             :   long lima, limb, Dsup, cplus;
    1186             :   GEN V, S;
    1187             : 
    1188         175 :   if (x < 31) return NULL;
    1189         168 :   sqx = sqrt((double)x / 27); sqx4 = sqrt(sqx);
    1190         168 :   cplus = (11 + 5 * sqrt(5.)) / 8 * x;
    1191         168 :   Dsup = 3 * sqx;
    1192         168 :   lima = 2 * sqx4;
    1193         168 :   limb = sqrt(3.) * 2 * sqx4;
    1194         168 :   S = mkvecsmall5(x, xinf, cplus, Dsup, limb);
    1195         168 :   V = nflist_parapply("_nflist_S3I_worker", mkvec(S), identity_ZV(lima));
    1196         168 :   V = myshallowconcat1(V); return lg(V) == 1? NULL: V;
    1197             : }
    1198             : 
    1199             : static GEN
    1200          14 : makeS3resolvent(GEN T, long flag)
    1201             : {
    1202          14 :   GEN P, d, f = NULL;
    1203          14 :   (void)nfcoredisc2(T, &d, odd(flag)? &f: NULL);
    1204          14 :   P = quadpoly_i(d); return f? mkvec2(P, f): P;
    1205             : }
    1206             : 
    1207             : static GEN
    1208        1316 : makeS3vec(GEN X, GEN Xinf, GEN field, long s)
    1209             : {
    1210             :   GEN R, I;
    1211             :   long x, xinf;
    1212             : 
    1213        1316 :   if (field) return makeDLvec(3, X, Xinf, field, s);
    1214         245 :   x = itos(X); xinf = itos(Xinf);
    1215         245 :   R = (s <= 0)? cubicreal(x, xinf): NULL;
    1216         245 :   I = s? cubicimag(x, xinf): NULL;
    1217         245 :   switch (s)
    1218             :   {
    1219          70 :     case 0: return R;
    1220          42 :     case 1: return I;
    1221         119 :     case -1: return R? (I? shallowconcat(R, I): R): I;
    1222          14 :     default: if (!R && !I) return NULL; /* -2 */
    1223          14 :              return mkvec2(R? R: cgetg(1,t_VEC), I? I: cgetg(1,t_VEC));
    1224             :   }
    1225             : }
    1226             : 
    1227             : /**********************************************************************/
    1228             : /*                                 C4                                 */
    1229             : /**********************************************************************/
    1230             : 
    1231             : static GEN
    1232       23669 : makepolC4(GEN S, GEN T)
    1233             : {
    1234       23669 :   GEN V = cgetg(7, t_POL);
    1235       23663 :   V[1] = evalsigne(1)|evalvarn(0);
    1236       23663 :   gel(V, 6) = gen_1;
    1237       23663 :   gel(V, 5) = gen_0;
    1238       23663 :   gel(V, 4) = S;
    1239       23663 :   gel(V, 3) = gen_0;
    1240       23663 :   gel(V, 2) = T; return V;
    1241             : }
    1242             : 
    1243             : static GEN
    1244       27666 : C4qfbsolve(GEN Q, GEN D)
    1245             : {
    1246       27666 :   GEN v = qfbsolve(Q, D, 1), w;
    1247       27695 :   long i, c, n = lg(v) - 1;
    1248             : 
    1249       27695 :   w = cgetg(2 * n + 1, t_VEC);
    1250       82426 :   for (i = c = 1; i <= n; i++)
    1251             :   {
    1252       54747 :     GEN BC = gel(v, i), B = gel(BC,1), C = gel(BC,2);
    1253       54747 :     gel(w, c++) = absi_shallow(B);
    1254       54759 :     if (!absequalii(B, C)) gel(w, c++) = absi_shallow(C);
    1255             :   }
    1256       27679 :   setlg(w, c); return gtoset_shallow(w);
    1257             : }
    1258             : 
    1259             : /* D squarefree in [D,factor(D)] form, D = B^2 + C^2,
    1260             :  * A*(odd part of D) = n2 = prod_{odd p | n} p, v2 = v2(n) */
    1261             : static GEN
    1262       27665 : polsubC4_D(GEN Q, GEN A, GEN Dfa, GEN n2, long v2, long s, long fli)
    1263             : {
    1264       27665 :   GEN v, S, mS, AD, A2D, D = gel(Dfa,1), vB = C4qfbsolve(Q, Dfa);
    1265       27664 :   long i, c, l = lg(vB), A4 = Mod4(A); /* 1 or 3 */
    1266             : 
    1267       27662 :   AD = mpodd(D)? n2: shifti(n2, 1);
    1268       27672 :   A2D = mulii(A, AD);
    1269       27651 :   S = mulsi(-2, AD); mS = negi(S);
    1270       27656 :   v = cgetg(2 * l - 1, t_VEC);
    1271       82370 :   for (i = c = 1; i < l; i++)
    1272             :   {
    1273       54709 :     GEN B = gel(vB, i), T;
    1274       54709 :     long B4 = Mod4(B);
    1275       54715 :     int p = (s <= 0), m = !!s;
    1276       54715 :     if (v2 <= 2 && odd(B4)) continue;
    1277       31108 :     if (!v2)
    1278       19166 :     { if (((A4 + B4) & 3) == 1) m = 0; else p = 0; }
    1279       11942 :     else if (fli)
    1280             :     {
    1281       11942 :       if (v2 == 3)
    1282        4540 :       { if (!odd(B4)) continue; }
    1283        7402 :       else if (v2 == 2)
    1284        4470 :       { if (((A4 + B4) & 3) == 1) p = 0; else m = 0; }
    1285             :     }
    1286       28849 :     if (!p && !m) continue;
    1287       21791 :     T = mulii(A2D, subii(D, sqri(B)));
    1288       21714 :     if (p) gel(v, c++) = makepolC4(S, T);
    1289       21715 :     if (m) gel(v, c++) = makepolC4(mS, T);
    1290             :   }
    1291       27661 :   setlg(v, c); return v;
    1292             : }
    1293             : 
    1294             : 
    1295             : /* vector of distinct primes -> squarefree famat */
    1296             : static GEN
    1297        8120 : P2fa(GEN P) { return mkmat2(P, const_col(lg(P)-1, gen_1)); }
    1298             : /* vector of distinct primes -> [factorback, P2fa] */
    1299             : static GEN
    1300         294 : P2Nfa(GEN P) { return mkvec2(ZV_prod(P), P2fa(P)); }
    1301             : /* P = prime divisors of f different from ell; nf = Q or quadratic */
    1302             : static GEN
    1303        7224 : Pell2prfa(GEN nf, GEN P, long ell, GEN f)
    1304             : {
    1305        7224 :   long v = Z_lval(f, ell);
    1306        7224 :   if (v) P = ZV_sort_shallow(vec_append(P, utoipos(ell)));
    1307        7224 :   P = nf_pV_to_prV(nf, P); settyp(P, t_COL); P = P2fa(P);
    1308        7224 :   if (v)
    1309             :   { /* add pr^{2e} for all pr | ell */
    1310         196 :     long i, l = lg(gel(P,1));
    1311         420 :     for (i = 1; i < l; i++)
    1312             :     {
    1313         224 :       GEN pr = gcoeff(P,i,1);
    1314         224 :       if (equaliu(pr_get_p(pr), ell)) gcoeff(P,i,2) = utoipos(v * pr_get_e(pr));
    1315             :     }
    1316             :   }
    1317        7224 :   return P;
    1318             : }
    1319             : static int
    1320       45775 : ZV_is_1(GEN x, long i0)
    1321             : {
    1322       45775 :   long i, l = lg(x);
    1323      117502 :   for (i = i0; i < l; i++) if (!equali1(gel(x,i))) return 0;
    1324       35096 :   return 1;
    1325             : }
    1326             : static int
    1327       41460 : zv_is_1(GEN x, long i0)
    1328             : {
    1329       41460 :   long i, l = lg(x);
    1330       51379 :   for (i = i0; i < l; i++) if (x[i] != 1) return 0;
    1331       40466 :   return 1;
    1332             : }
    1333             : 
    1334             : /* n > 0, D sqfree, sum2sq(odd(D)? D: 4*D) is true */
    1335             : static GEN
    1336       60351 : polsubcycloC4_i(GEN n, long s, long fli, GEN D)
    1337             : {
    1338       60351 :   GEN fa = NULL, P, Q, v, n2;
    1339             :   long v2;
    1340             : 
    1341       60351 :   if (typ(n) == t_VEC) { fa = gel(n,2); n = gel(n,1); }
    1342       60351 :   if (s == 1 || equali1(n)) return NULL;
    1343             :   /* s = -1, 0 or 2 */
    1344       60333 :   v2 = vali(n); if (fli && (v2 == 1 || v2 > 4)) return NULL;
    1345       44165 :   if (!fa) fa = Z_factor(n);
    1346       44371 :   P = gel(fa,1);
    1347       44371 :   if (fli && !ZV_is_1(gel(fa,2), v2? 2: 1)) return NULL;
    1348       33737 :   n2 = ZV_prod(v2? vecsplice(P, 1): P); /* odd part of rad(n) */
    1349       33699 :   Q = mkqfb(gen_1, gen_0, gen_1, utoineg(4));
    1350       33693 :   if (D)
    1351             :   {
    1352             :     GEN A, PD, LD;
    1353       33399 :     if (fli && mpodd(D) == (v2 == 4)) return NULL;
    1354       27008 :     if (!(A = divide(n2, mpodd(D) ? D : gmul2n(D, -1)))) return NULL;
    1355       27029 :     (void)Z_smoothen(D, P, &PD, &LD);
    1356       27049 :     D = mkvec2(D, mkmat2(PD, LD));
    1357       27040 :     v = polsubC4_D(Q, A, D, n2, v2, s, fli);
    1358             :   }
    1359             :   else
    1360             :   {
    1361         294 :     long c, i, lv, l = lg(P);
    1362         294 :     GEN M2 = NULL;
    1363         294 :     c = (v2 && v2 < 4)? 2:  1; /* leave 2 in P if 16 | n */
    1364         294 :     if (c == 2) M2 = mkmat2(mkcol(gen_2),mkcol(gen_1));
    1365         672 :     for (i = v2? 2: 1; i < l; i++) /* odd prime divisors of n */
    1366         378 :       if (Mod4(gel(P,i)) == 1) gel(P, c++) = gel(P,i);
    1367         294 :     setlg(P, c);
    1368         294 :     v = divisors_factored(P2Nfa(P)); lv = lg(v);
    1369        1169 :     for (i = c = 1; i < lv; i++)
    1370             :     {
    1371         875 :       GEN A, D = gel(v,i), d = gel(D,1);
    1372         875 :       if (M2) /* replace (odd) D by 2*D */
    1373             :       {
    1374          84 :         gel(D,1) = shifti(d,1);
    1375          84 :         gel(D,2) = famat_mul(M2, gel(D,2));
    1376         791 :       } else if (i == 1) continue; /* ommit D = 1 */
    1377         623 :       A = diviiexact(n2, mpodd(d)? d: shifti(d,-1));
    1378         623 :       gel(v,c++) = polsubC4_D(Q, A, D, n2, v2, s, fli);
    1379             :     }
    1380         294 :     if (c == 1) return NULL;
    1381         245 :     setlg(v, c); v = shallowconcat1(v);
    1382             :   }
    1383       27288 :   return v;
    1384             : }
    1385             : static GEN
    1386          63 : polsubcycloC4(GEN n, long s)
    1387             : {
    1388             :   long i, l, c;
    1389          63 :   GEN D = divisors_factored(n);
    1390          63 :   l = lg(D);
    1391         357 :   for (i = 2, c = 1; i < l; i++)
    1392             :   {
    1393         294 :     GEN v = polsubcycloC4_i(gel(D,i), s, 1, NULL);
    1394         294 :     if (v) gel(D,c++) = v;
    1395             :   }
    1396          63 :   setlg(D, c); return myshallowconcat1(D);
    1397             : }
    1398             : 
    1399             : /* x^2 + a */
    1400             : static GEN
    1401        6299 : X2p(GEN a) { return deg2pol_shallow(gen_1, gen_0, a, 0); }
    1402             : /* x^2 - a */
    1403             : static GEN
    1404        1883 : X2m(GEN a) { return deg2pol_shallow(gen_1, gen_0, negi(a), 0); }
    1405             : /* y^2 - a */
    1406             : static GEN
    1407        4906 : Y2m(GEN a) { return deg2pol_shallow(gen_1, gen_0, negi(a), 1); }
    1408             : 
    1409             : static GEN
    1410         644 : makeC4(GEN N, GEN field, long s)
    1411             : {
    1412             :   GEN D;
    1413             :   long i, c;
    1414             : 
    1415         644 :   if (s == 1) return NULL;
    1416         630 :   if (field)
    1417             :   {
    1418           7 :     GEN d = checkfield(field, 2);
    1419           7 :     if (signe(d) < 0 || !divissquare(N, powiu(d,3))) return NULL;
    1420           7 :     D = mkvec(d);
    1421             :   }
    1422         623 :   else D = divisorsabsdisc(cored(N, 3), 0);
    1423         952 :   for (i = c = 1; i < lg(D); i++)
    1424             :   {
    1425         322 :     GEN cond, v, d = gel(D, i);
    1426         322 :     if (sum2sq(d) && Z_issquareall(divii(N, powiu(d, 3)), &cond)
    1427         126 :         && (v = polsubcycloC4_i(mulii(d,cond),s,1, mpodd(d)? d: shifti(d,-2))))
    1428          84 :           gel(D, c++) = v;
    1429             :   }
    1430         630 :   if (c == 1) return NULL;
    1431          84 :   setlg(D, c); return sturmseparate(myshallowconcat1(D), s, 4);
    1432             : }
    1433             : 
    1434             : static GEN
    1435         210 : condrel_i(GEN P, GEN pol)
    1436             : {
    1437         210 :   GEN bnf = bnfY(P), T = gcoeff(nffactor(bnf, pol), 1, 1);
    1438         210 :   GEN f = gel(rnfconductor0(bnf, T, 2), 1);
    1439         210 :   GEN id = gel(f, 1), arch = gel(f, 2), co = gcoeff(id, 1, 1);
    1440         210 :   if (ZM_isscalar(id, co)) id = co;
    1441         210 :   return mkvec2(P, gequal0(arch) ? id : mkvec2(id, arch));
    1442             : }
    1443             : static GEN
    1444         196 : condrel(GEN P, GEN pol, long flag)
    1445         196 : { return odd(flag)? condrel_i(P, pol): P; }
    1446             : static GEN
    1447          21 : condrel_dummy(GEN P, long flag)
    1448          21 : { return odd(flag)? mkvec2(P, gen_1): P; }
    1449             : static GEN
    1450         112 : condrelresolvent(GEN pol, long d, long flag)
    1451         112 : { return condrel(mynfsubfield(pol, d), pol, flag); }
    1452             : 
    1453             : 
    1454             : static GEN
    1455          14 : makeC4resolvent(GEN pol, long flag)
    1456             : {
    1457          14 :   GEN d; (void)nfcoredisc(pol, &d);
    1458          14 :   return condrel(quadpoly_i(d), pol, flag);
    1459             : }
    1460             : 
    1461             : static GEN
    1462        2253 : C4vec(GEN X, GEN Xinf, GEN m, long s)
    1463             : {
    1464        2253 :   GEN v, M, inf, m3 = powiu(m, 3), limf = gfloorsqrtdiv(X, m3);
    1465             :   long l, n, c;
    1466             :   pari_sp av;
    1467        2248 :   inf = cmpiu(Xinf, 500) >= 0? gceilsqrtdiv(Xinf, m3): gen_1;
    1468        2248 :   l = itos(subii(limf, inf)) + 2;
    1469        2249 :   M = mpodd(m)? m: shifti(m, -2); av = avma;
    1470             : 
    1471        2248 :   v = const_vec(l-1, cgetg(1,t_VEC));
    1472       62243 :   for (n = c = 1; n < l; n++)
    1473             :   {
    1474       59990 :     GEN w, cond = addui(n-1, inf);
    1475       59939 :     if ((w = polsubcycloC4_i(mulii(m, cond), s, 1, M))) gel(v, c++) = w;
    1476       59996 :     if ((n & 0xfff) == 0 && gc_needed(av, 3))
    1477             :     { /* let parisizemax handle some of it */
    1478           0 :       if (DEBUGMEM>1) pari_warn(warnmem,"C4vec, n = %ld/%ld", n, l-1);
    1479           0 :       v = gc_GEN(av, v);
    1480             :     }
    1481             :   }
    1482        2253 :   setlg(v, c); return myshallowconcat1(v);
    1483             : }
    1484             : 
    1485             : GEN
    1486        2246 : nflist_C4vec_worker(GEN m, GEN X, GEN Xinf, GEN gs)
    1487             : {
    1488        2246 :   pari_sp av = avma;
    1489        2246 :   return gc_GEN(av, C4vec(X, Xinf, m, itos(gs)));
    1490             : }
    1491             : 
    1492             : static GEN
    1493         133 : makeC4vec_i(GEN X, GEN Xinf, GEN field, long s)
    1494             : {
    1495             :   GEN v;
    1496         133 :   long limD = floorsqrtn(X,3), m, c, snew = s == -2 ? -1 : s;
    1497         133 :   if (s == 1) return NULL;
    1498         119 :   if (field)
    1499             :   {
    1500           7 :     GEN gm = checkfield(field, 2);
    1501           7 :     return sum2sq(gm)? C4vec(X, Xinf, gm, snew): NULL;
    1502             :   }
    1503         112 :   v = cgetg(limD >> 1, t_VEC);
    1504        7658 :   for (m = 5, c = 1; m <= limD; m += odd(m) ? 3 : 1)
    1505        7546 :     if (usum2sq(m)) gel(v, c++) = utoipos(m);
    1506         112 :   setlg(v, c);
    1507         112 :   v = nflist_parapply("_nflist_C4vec_worker", mkvec3(X, Xinf, stoi(snew)), v);
    1508         112 :   return myshallowconcat1(v);
    1509             : }
    1510             : static GEN
    1511         133 : makeC4vec(GEN X, GEN Xinf, GEN field, long s)
    1512             : {
    1513         133 :   GEN v = makeC4vec_i(X, Xinf, field, s);
    1514         133 :   return v? sturmseparate(v, s, 4): NULL;
    1515             : }
    1516             : 
    1517             : /**********************************************************************/
    1518             : /*                                 V4                                 */
    1519             : /**********************************************************************/
    1520             : 
    1521             : static GEN
    1522          49 : makeV4(GEN N, GEN field, long s)
    1523             : {
    1524             :   GEN V, R;
    1525          49 :   long lV, i1, i2, c = 1;
    1526          49 :   if (s == 1) return NULL;
    1527          42 :   if (field)
    1528             :   {
    1529           7 :     GEN D = checkfield(field, 2);
    1530           7 :     if (signe(D) < 0) pari_err_TYPE("makeV4 [real quadratic subfield]", field);
    1531           7 :     V = mkvec(D);
    1532             :   }
    1533          35 :   else V = divisorsdisc(N, -1);
    1534          42 :   lV = lg(V); R = cgetg((lV - 1) * (lV - 2) >> 1, t_VEC);
    1535          98 :   for (i1 = 1; i1 < lV; i1++)
    1536             :   {
    1537          56 :     GEN V2, D1 = gel(V, i1);
    1538          56 :     if (s == 0 && signe(D1) < 0) continue;
    1539          56 :     if (cmpii(sqri(D1), N) > 0) continue;
    1540          56 :     V2 = divisorsdisc(diviiexact(N, absi_shallow(D1)), -1);
    1541         448 :     for (i2 = 1; i2 < lg(V2); i2++)
    1542             :     {
    1543         392 :       GEN D2 = gel(V2, i2), D3, D12;
    1544         392 :       if (s == 0 && signe(D2) < 0) continue;
    1545         392 :       if (s > 0 && signe(D1) > 0 && signe(D2) > 0) continue;
    1546         392 :       if ((!field && cmpii(D1, D2) >= 0) || equalii(D1, D2)) continue;
    1547         189 :       D12 = mulii(D1, D2); D3 = coredisc(D12);
    1548         189 :       if (cmpii(D2, D3) < 0 && !equalii(D1, D3)
    1549          70 :           && absequalii(mulii(D12, D3), N))
    1550          21 :         gel(R, c++) = mkpoln(5, gen_1, gen_0, mulsi(-2, addii(D1, D2)),
    1551             :                               gen_0, sqri(subii(D1, D2)));
    1552             :     }
    1553             :   }
    1554          42 :   if (c == 1) return NULL;
    1555          14 :   setlg(R, c); return sturmseparate(R, s, 4);
    1556             : }
    1557             : 
    1558             : static GEN
    1559          21 : makeV4resolvent(GEN pol, long flag)
    1560             : {
    1561          21 :   GEN P, V = mynfsubfields(pol, 2);
    1562             :   long i;
    1563          21 :   if (lg(V) != 4) pari_err_BUG("makeV4resolvent");
    1564          21 :   if (flag >= 2)
    1565             :   {
    1566          14 :     if (flag == 2) return V;
    1567           7 :     return mkvec3(condrel_i(gel(V, 1), pol),
    1568           7 :                   condrel_i(gel(V, 2), pol),
    1569           7 :                   condrel_i(gel(V, 3), pol));
    1570             :   }
    1571           7 :   for (i = 1; i <= 3; i++) { P = gel(V, i); if (signe(ZX_disc(P)) > 0) break; }
    1572           7 :   return condrel(P, pol, flag);
    1573             : }
    1574             : 
    1575             : static GEN
    1576      226730 : polV4(long d1, long d2)
    1577      226730 : { return mkpoln(5, gen_1, gen_0, mulss(-2, d1+d2), gen_0, sqrs(d1-d2)); }
    1578             : 
    1579             : GEN
    1580        5021 : nflist_V4_worker(GEN D1, GEN X, GEN Xinf, GEN gs)
    1581             : {
    1582        5021 :   pari_sp av = avma, av2;
    1583             :   GEN V, W;
    1584        5021 :   long d2a, e1 = signe(D1), d1 = itos(D1), d1a = labs(d1);
    1585        5021 :   long limg, limg2, s2 = -1, s = itos(gs);
    1586        5021 :   long limD2 = itos(sqrti(divis(X, d1a)));
    1587        5021 :   long limQ = floorsqrtdiv(X, sqru(d1a));
    1588             : 
    1589        5020 :   limg2 = limg = usqrt(d1a);
    1590        5020 :   if (!odd(d1a))
    1591             :   { /* limg2 = sqrt(d1a * 4), to be used when d2 is also even */
    1592        1729 :     long r = d1a - limg*limg;
    1593        1729 :     limg2 *= 2; if (r >= limg) limg2++;
    1594             :   }
    1595             : 
    1596        5016 :   if (s == 2 && e1 > 0) s2 = 1; /* forbid d2 > 0 */
    1597        4029 :   else if (!s) s2 = 0; /* forbid d2 < 0 */
    1598        5016 :   W = vectrunc_init(2 * limD2);
    1599        5009 :   V = e1 < 0? W: vectrunc_init(2 * limD2); av2 = avma;
    1600     2963082 :   for (d2a = d1a; d2a <= limD2; d2a++, set_avma(av2))
    1601             :   {
    1602             :     long g, d2ag, LIMg;
    1603             :     GEN D3, d1d2a, d3;
    1604             :     int p, m;
    1605     2952218 :     if (odd(d2a)) LIMg = limg;
    1606             :     else
    1607             :     {
    1608     3294167 :       if ((d2a & 3) == 2 || !(d2a & 15)) continue; /* v2(d2) = 1 or >= 4 */
    1609      575430 :       LIMg = limg2;
    1610             :     }
    1611     2061749 :     g = ugcd(d2a, d1a); if (g > LIMg) continue;
    1612     1895353 :     d2ag = d2a / g; if (d2ag > limQ) continue;
    1613      338643 :     uis_fundamental_pm(d2a, s2, &p, &m);
    1614      368300 :     if (!p && !m) continue;
    1615      248026 :     d3 = muluu(d1a / g, d2ag); d1d2a = muluu(d1a, d2a);
    1616      246439 :     if (p)
    1617             :     { /* D2 = d2a is fundamental */
    1618      138520 :       setsigne(d3, e1);
    1619      138520 :       D3 = Mod4(d3) > 1? shifti(d3, 2): d3; /* now D3 = coredisc(D1*D2) */
    1620      138833 :       if (abscmpiu(D3, d2a) > 0 && ok_int(mulii(d1d2a, D3), X, Xinf))
    1621      114190 :       { vectrunc_append(V,  polV4(d1, d2a)); av2 = avma; }
    1622             :     }
    1623      246613 :     if (m)
    1624             :     { /* D2 = - d2a is fundamental */
    1625             :       int fl;
    1626      136062 :       setsigne(d3, -e1);
    1627      136062 :       D3 = Mod4(d3) > 1? shifti(d3, 2): d3; /* now D3 = coredisc(D1*D2) */
    1628      136721 :       fl = abscmpiu(D3, d2a);
    1629      136069 :       if (fl < 0 || (!fl && e1 > 0)) continue;
    1630      127078 :       if (ok_int(mulii(d1d2a, D3), X, Xinf))
    1631      115411 :       { set_avma(av2); vectrunc_append(W, polV4(d1, -d2a)); av2 = avma; }
    1632             :     }
    1633             :   }
    1634        5000 :   return gc_GEN(av, mkvec2(e1 < 0? cgetg(1, t_VEC): V, W));
    1635             : }
    1636             : 
    1637             : static GEN
    1638         280 : Sextract(GEN v, long ind)
    1639             : {
    1640             :   long j, l;
    1641         280 :   GEN w = cgetg_copy(v, &l);
    1642       14525 :   for (j = 1; j < l; j++) gel(w, j) = gmael(v, j, ind);
    1643         280 :   return myshallowconcat1(w);
    1644             : }
    1645             : static GEN
    1646          42 : makeV4vec(GEN X, GEN Xinf, GEN field, long s)
    1647             : {
    1648             :   long s2, d, dinf, dsup, l, c;
    1649             :   GEN v;
    1650             : 
    1651          42 :   if (s == 1) return NULL;
    1652          35 :   if (field)
    1653             :   {
    1654           7 :     GEN D = checkfield(field, 2), DSQ = sqri(D);
    1655           7 :     if (signe(D) < 0) pari_err_TYPE("makeV4 [real quadratic subfield]", field);
    1656           7 :     if (cmpii(DSQ, X) > 0) return NULL;
    1657           7 :     dinf = itos(D); dsup = dinf; l = 2; s2 = 0;
    1658             :   }
    1659             :   else
    1660          28 :   { dinf = 3; dsup = floorsqrtn(X,3); l = dsup << 1; s2 = s? -1: 0; }
    1661          35 :   v = cgetg(l, t_VEC); c = 1;
    1662        9800 :   for (d = dinf; d <= dsup; d++)
    1663             :   {
    1664             :     int p, m;
    1665        9765 :     uis_fundamental_pm(d, s2, &p, &m);
    1666        9765 :     if (m) gel(v, c++) = utoineg(d);
    1667        9765 :     if (p) gel(v, c++) = utoipos(d);
    1668             :   }
    1669          35 :   setlg(v, c);
    1670          35 :   v = nflist_parapply("_nflist_V4_worker", mkvec3(X, Xinf, stoi(s)), v);
    1671          35 :   switch (s)
    1672             :   {
    1673           7 :     case 0: return Sextract(v,1);
    1674           7 :     case 2: return Sextract(v,2);
    1675          14 :     case -1: return shallowconcat(Sextract(v,1), Sextract(v,2));
    1676           7 :     default: return mkvec3(Sextract(v,1), cgetg(1, t_VEC), Sextract(v,2));
    1677             :   }
    1678             : }
    1679             : 
    1680             : /**********************************************************************/
    1681             : /*                                 D4                                 */
    1682             : /**********************************************************************/
    1683             : static GEN
    1684         175 : archD40() { return mkvec(cgetg(1, t_VECSMALL)); }
    1685             : 
    1686             : static GEN
    1687         175 : archD41() { return mkvec2(mkvecsmall(2), mkvecsmall(1)); }
    1688             : 
    1689             : static GEN
    1690         182 : archD42() { return mkvec(mkvecsmall2(1, 2)); }
    1691             : 
    1692             : static GEN
    1693         238 : getarchD4(long s)
    1694             : {
    1695         238 :   switch (s)
    1696             :   {
    1697          28 :     case 0: return archD40();
    1698          28 :     case 1: return archD41();
    1699          35 :     case 2: return archD42();
    1700         147 :     default: return shallowconcat1(mkvec3(archD40(), archD41(), archD42()));
    1701             :   }
    1702             :   return gen_0;
    1703             : }
    1704             : 
    1705             : /* x = [N, a;0, m] quadratic ideal in HNF, apply quadratic automorphism */
    1706             : static GEN
    1707       42238 : aut2(GEN x, long oddD)
    1708             : {
    1709       42238 :   GEN N = gcoeff(x,1,1), t = subii(N, gcoeff(x,1,2)), m = gcoeff(x,2,2);
    1710       42234 :   if (oddD) t = addii(t, m);
    1711       42233 :   return mkmat2(gel(x,1), mkcol2(modii(t, N), m));
    1712             : }
    1713             : /* I a vector of quadratic ideals of same norm */
    1714             : static GEN
    1715      177327 : authI(GEN nf, GEN I, GEN *pstable, GEN D)
    1716             : {
    1717      177327 :   long l = lg(I), i, oddD;
    1718             :   GEN v, w;
    1719             : 
    1720      177327 :   if (l == 1) { *pstable = NULL; return I; }
    1721       84775 :   if (l == 2) { *pstable = mkvecsmall(1); return I; }
    1722       66708 :   if (l == 3) { *pstable = mkvecsmall2(0,0); gel(I,2) = NULL; return I; }
    1723       18821 :   v = w = shallowcopy(I); *pstable = zero_zv(l-1); oddD = mpodd(D);
    1724       18830 :   if (typ(gcoeff(gel(I,1), 1, 1)) != t_INT) /* vector of factorizations */
    1725             :   {
    1726           7 :     w = cgetg(l, t_VEC);
    1727          28 :     for (i = 1; i < l; i++) gel(w,i) = idealfactorback(nf,gel(v,i),NULL,0);
    1728             :   }
    1729             : 
    1730       98739 :   for (i = 1; i < l; i++)
    1731             :   {
    1732       79912 :     GEN a = gel(w, i), b;
    1733             :     long j;
    1734       79912 :     if (!a) continue;
    1735       42238 :     b = aut2(a, oddD);
    1736       42236 :     if (ZM_equal(b, a)) { (*pstable)[i] = 1; continue; }
    1737       90981 :     for (j = i + 1; j < l; j++)
    1738       90982 :       if (ZM_equal(b, gel(w,j))) { gel(v,j) = gel(w,j) = NULL; break;}
    1739       37673 :     if (j == l) pari_err_BUG("makeD4 [conjugate not found]");
    1740             :   }
    1741       18827 :   return v;
    1742             : }
    1743             : 
    1744             : /* kronecker(D, cond) != -1, Arch a vector of arch in t_VECSMALL form */
    1745             : static GEN
    1746      177328 : polD4onecond(GEN bnf, GEN G, GEN D, GEN I, GEN Arch)
    1747             : {
    1748             :   GEN stable, v0, v1, v2;
    1749      177328 :   long j, k, m, l, lA, ok = 0, r1 = signe(D) > 0? 2: 0;
    1750             : 
    1751      177328 :   v0 = v1 = v2 = cgetg(1,t_VEC);
    1752      177327 :   I = authI(bnf, I, &stable, D); l = lg(I); lA = lg(Arch);
    1753      371083 :   for (j = 1; j < l; j++)
    1754             :   {
    1755      193752 :     GEN id = gel(I, j);
    1756      193752 :     if (!id) continue;
    1757      246474 :     for (k = 1; k < lA; k++)
    1758             :     {
    1759      138291 :       GEN arch = gel(Arch, k), R = NULL;
    1760      138291 :       long st = lg(arch)-1, lR;
    1761      138291 :       if (stable[j])
    1762             :       {
    1763       33047 :         if (st == 1 && arch[1] == 1) continue;
    1764       27993 :         if (st != 1) R = mybnrclassfield_X(bnf, mkvec2(id,arch), 2,NULL,NULL,G);
    1765             :       }
    1766      133236 :       if (!R) R = mybnrclassfield(bnf, mkvec2(id, arch), 2);
    1767      133229 :       lR = lg(R); if (lR == 1) continue;
    1768       26495 :       ok = 1;
    1769       54404 :       for (m = 1; m < lR; m++)
    1770             :       {
    1771       27909 :         GEN P = rnfequation(bnf, gel(R, m));
    1772       27909 :         if (st == 0 && r1) v0 = vec_append(v0, P);
    1773       26460 :         else if (st == 1) v1 = vec_append(v1, P);
    1774       21987 :         else v2 = vec_append(v2, P);
    1775             :       }
    1776             :     }
    1777             :   }
    1778      177331 :   return ok? mkvec3(v0, v1, v2): NULL;
    1779             : }
    1780             : 
    1781             : static GEN
    1782         154 : makeD4(GEN N, GEN field, long s)
    1783             : {
    1784             :   pari_sp av2;
    1785         154 :   GEN vD, v, v0, v1, v2, archempty, listarch = getarchD4(s);
    1786             :   long l, i;
    1787             : 
    1788         154 :   if (field)
    1789             :   {
    1790          21 :     GEN D = checkfield(field, 2);
    1791          21 :     if ((signe(D) < 0 && (s == 0 || s == 1)) || !dvdii(N, sqri(D)))
    1792           7 :       return NULL;
    1793          14 :     vD = mkvec(D);
    1794             :   }
    1795             :   else
    1796         133 :     vD = divisorsdisc(cored(N,2), (s == 0 || s == 1)? 0 : -1);
    1797         147 :   archempty = mkvec(cgetg(1, t_VECSMALL));
    1798         147 :   l = lg(vD); av2 = avma;
    1799         147 :   v0 = const_vec(l-1, cgetg(1,t_VEC));
    1800         147 :   v1 = const_vec(l-1, cgetg(1,t_VEC));
    1801         147 :   v2 = const_vec(l-1, cgetg(1,t_VEC));
    1802         196 :   for (i = 1; i < l; i++)
    1803             :   {
    1804          49 :     GEN bnf, G, I, Arch, RET, D = gel(vD, i);
    1805          49 :     pari_sp av3 = avma;
    1806          49 :     long cond = itou(divii(N, sqri(D)));
    1807             : 
    1808          49 :     set_avma(av3);
    1809          49 :     if (kroiu(D, cond) == -1) continue;
    1810          49 :     bnf = Buchall(Y2m(D), nf_FORCE, MEDDEFAULTPREC);
    1811          49 :     I = ideals_by_norm(bnf_get_nf(bnf), utoipos(cond));
    1812          49 :     Arch = signe(D) > 0 ? listarch : archempty;
    1813             :     /* restrict to fields which are not Galois over Q [eliminate V4/C4] */
    1814          49 :     G = s != 1? mkvec2(galoisinit(bnf, NULL), gen_0): NULL;
    1815          49 :     if (!(RET = polD4onecond(bnf, G, D, I, Arch)))
    1816          21 :     { set_avma(av3); continue; }
    1817          28 :     gel(v0,i) = gel(RET,1);
    1818          28 :     gel(v1,i) = gel(RET,2);
    1819          28 :     gel(v2,i) = gel(RET,3);
    1820          28 :     if (gc_needed(av2, 2))
    1821             :     {
    1822           0 :       if (DEBUGMEM>1) pari_warn(warnmem,"makeD4");
    1823           0 :       (void)gc_all(av2, 3, &v0,&v1,&v2);
    1824             :     }
    1825             :   }
    1826         147 :   if      (s == 0) v = myshallowconcat1(v0);
    1827         133 :   else if (s == 1) v = myshallowconcat1(v1);
    1828         119 :   else if (s == 2) v = myshallowconcat1(v2);
    1829             :   else
    1830             :   {
    1831         105 :     v0 = myshallowconcat1(v0);
    1832         105 :     v1 = myshallowconcat1(v1);
    1833         105 :     v2 = myshallowconcat1(v2); v = mkvec3(v0, v1, v2);
    1834         105 :     if (s == -1) v = myshallowconcat1(v);
    1835             :   }
    1836         147 :   return v;
    1837             : }
    1838             : 
    1839             : GEN
    1840        3699 : nflist_D4_worker(GEN D, GEN X, GEN Xinf, GEN listarch)
    1841             : {
    1842        3699 :   pari_sp av = avma, av2;
    1843        3699 :   GEN bnf, G, vI, v0, v1, v2, Arch, D2 = sqri(D);
    1844        3694 :   long c0, c1, c2, cond, l = itos(divii(X, D2)) + 1;
    1845        3695 :   long lmin = itos(ceildiv(Xinf, D2));
    1846             : 
    1847        3695 :   bnf = Buchall(Y2m(D), nf_FORCE, MEDDEFAULTPREC);
    1848        3703 :   vI = ideallist(bnf, l-1);
    1849        3703 :   Arch = signe(D) > 0 ? listarch : mkvec(cgetg(1,t_VECSMALL));
    1850        3703 :   G = lg(Arch) != 3? mkvec2(galoisinit(bnf, NULL), gen_0): NULL;
    1851        3703 :   av2 = avma;
    1852        3703 :   v0 = const_vec(l-1, cgetg(1,t_VEC));
    1853        3703 :   v1 = const_vec(l-1, cgetg(1,t_VEC));
    1854        3703 :   v2 = const_vec(l-1, cgetg(1,t_VEC)); c0 = c1 = c2 = 1;
    1855      265660 :   for (cond = lmin; cond < l; cond++)
    1856             :   {
    1857      261957 :     pari_sp av3 = avma;
    1858             :     GEN R, R1, R2, R3;
    1859      261957 :     if (kroiu(D, cond) == -1) continue;
    1860      177273 :     if (!(R = polD4onecond(bnf, G, D, gel(vI, cond), Arch)))
    1861      155815 :     { set_avma(av3); continue; }
    1862       21467 :     R1 = gel(R,1); if (lg(R1) > 1) gel(v0, c0++) = R1;
    1863       21467 :     R2 = gel(R,2); if (lg(R2) > 1) gel(v1, c1++) = R2;
    1864       21467 :     R3 = gel(R,3); if (lg(R3) > 1) gel(v2, c2++) = R3;
    1865       21467 :     if (gc_needed(av,1))
    1866             :     {
    1867           0 :       if (DEBUGMEM>1) pari_warn(warnmem,"makeD4vec, cond = %ld/%ld",cond,l-1);
    1868           0 :       (void)gc_all(av2, 3, &v0,&v1,&v2);
    1869             :     }
    1870             :   }
    1871        3703 :   setlg(v0,c0); v0 = myshallowconcat1(v0);
    1872        3703 :   setlg(v1,c1); v1 = myshallowconcat1(v1);
    1873        3703 :   setlg(v2,c2); v2 = myshallowconcat1(v2);
    1874        3703 :   return gc_GEN(av, mkvec3(v0, v1, v2));
    1875             : }
    1876             : 
    1877             : static GEN
    1878          84 : makeD4vec(GEN X, GEN Xinf, GEN field, long s)
    1879             : {
    1880             :   long s2, limdinf, limdsup, c, da;
    1881             :   GEN v, D;
    1882             : 
    1883          84 :   if (field)
    1884             :   {
    1885           7 :     GEN D = checkfield(field, 2);
    1886           7 :     if (cmpii(sqri(D), X) > 0) return NULL;
    1887           7 :     limdsup = limdinf = labs(itos(D));
    1888           7 :     s2 = signe(D) < 0? 1: 0;
    1889             :   }
    1890             :   else
    1891             :   {
    1892          77 :     limdinf = 3; limdsup = itou(sqrti(X));
    1893          77 :     s2 = (s == 0 || s == 1) ? 0 : -1;
    1894             :   }
    1895          84 :   D = cgetg(2 * limdsup + 1, t_VEC); c = 1;
    1896        7378 :   for (da = limdinf; da <= limdsup; da++)
    1897             :   {
    1898             :     int p, m;
    1899        7294 :     uis_fundamental_pm(da, s2, &p, &m);
    1900        7294 :     if (p) gel(D, c++) = utoipos(da);
    1901        7294 :     if (m) gel(D, c++) = utoineg(da);
    1902             :   }
    1903          84 :   setlg(D, c);
    1904          84 :   v = nflist_parapply("_nflist_D4_worker", mkvec3(X, Xinf, getarchD4(s)), D);
    1905          84 :   if (s >= 0) v = Sextract(v,s+1);
    1906             :   else
    1907             :   {
    1908          35 :     v = mkvec3(Sextract(v,1), Sextract(v,2), Sextract(v,3));
    1909          35 :     if (s == -1) v = shallowconcat1(v);
    1910             :   }
    1911          84 :   return v;
    1912             : }
    1913             : 
    1914             : /**********************************************************************/
    1915             : /*                              A4 and S4                             */
    1916             : /**********************************************************************/
    1917             : /* FIXME: export */
    1918             : static GEN
    1919      110133 : to_principal_unit(GEN nf, GEN x, GEN pr, GEN sprk)
    1920             : {
    1921      110133 :   if (pr_get_f(pr) != 1)
    1922             :   {
    1923       33256 :     GEN prk = gel(sprk,3);
    1924       33256 :     x = nfpowmodideal(nf, x, gmael(sprk,5,1), prk);
    1925             :   }
    1926      110135 :   return x;
    1927             : }
    1928             : static long
    1929      110122 : ZV_iseven(GEN zlog)
    1930             : {
    1931      110122 :   long i, l = lg(zlog);
    1932      166802 :   for (i = 1; i < l; i++)
    1933      140347 :     if (mpodd(gel(zlog,i))) return 0;
    1934       26455 :   return 1;
    1935             : }
    1936             : 
    1937             : /* x^2 = t (mod bid) solvable ? */
    1938             : static int
    1939      110137 : issolvable(GEN nf, GEN t, GEN sprk)
    1940             : {
    1941      110137 :   GEN pr = sprk_get_pr(sprk);
    1942      110136 :   (void)nfvalrem(nf, t, pr, &t);
    1943      110133 :   t = to_principal_unit(nf, t, pr, sprk);
    1944      110135 :   return ZV_iseven(sprk_log_prk1(nf, t, sprk));
    1945             : }
    1946             : 
    1947             : /* true nf, cubic field */
    1948             : static GEN
    1949       23968 : makeGid(GEN nf)
    1950             : {
    1951       23968 :   GEN P = idealprimedec(nf, gen_2), Sprk;
    1952       23968 :   GEN bid4 = cgetg(1, t_VEC), bid6 = cgetg(1, t_VEC);
    1953       23968 :   long l = lg(P), i, parity = mpodd(nf_get_disc(nf));
    1954       23968 :   if (l == 3)
    1955             :   {
    1956       11991 :     if (parity) /* ensure f(P[1]/2) = 2 */
    1957        6293 :     { swap(gel(P,1), gel(P,2)); }
    1958             :     else /* make sure e(P[1]/2) = 2 */
    1959        5698 :     { if (pr_get_e(gel(P,1)) == 1) swap(gel(P,1), gel(P,2)); }
    1960             :   }
    1961       23968 :   Sprk = cgetg(l, t_VEC);
    1962       62950 :   for (i = 1; i < l; i++) gel(Sprk, i) = log_prk_init(nf, gel(P,i), 2, gen_2);
    1963       23968 :   if (!parity)
    1964             :   {
    1965        9604 :     bid4 = log_prk_init(nf, gel(P,1), 4, gen_2);
    1966        9604 :     if (l == 2) bid6 = log_prk_init(nf, gel(P,1), 6, gen_2);
    1967             :   }
    1968       23968 :   return mkvecn(3, Sprk, bid4, bid6);
    1969             : }
    1970             : 
    1971             : static long
    1972       58329 : r2(GEN v)
    1973             : {
    1974       58329 :   long i, l = lg(v);
    1975       63579 :   for (i = 1; i < l; i++) if (mpodd(gel(v,i))) break;
    1976       58329 :   return i - 1;
    1977             : }
    1978             : 
    1979             : /* list of virtual units whose norm is a square */
    1980             : static GEN
    1981       23967 : makevunits(GEN bnf)
    1982             : {
    1983       23967 :   GEN cyc = bnf_get_cyc(bnf), G = bnf_get_gen(bnf), nf = bnf_get_nf(bnf), v;
    1984       23967 :   long rc = r2(cyc), l, i;
    1985             : 
    1986       23967 :   v = cgetg(rc + 1, t_VEC);
    1987       26445 :   for (i = 1; i <= rc; i++)
    1988             :   {
    1989        2478 :     GEN g = idealpows(nf, gel(G, i), itos(gel(cyc, i)) >> 1);
    1990        2478 :     g = idealsqr(nf, idealred(nf, g));
    1991        2478 :     g = bnfisprincipal0(bnf, g, nf_GEN | nf_FORCE);
    1992        2478 :     gel(v, i) = gel(g, 2);
    1993             :   }
    1994       23967 :   v = shallowconcat(v, bnf_get_fu(bnf)); l = lg(v);
    1995       57714 :   for (i = 1; i < l; i++)
    1996             :   {
    1997       33746 :     GEN u = gel(v,i);
    1998       33746 :     if (signe(nfnorm(nf, u)) < 0) gel(v,i) = gneg(u); /*norm is a square now*/
    1999             :   }
    2000       23968 :   return eltlist2(nf, v);
    2001             : }
    2002             : 
    2003             : static GEN
    2004         707 : A4clean3(GEN v, long c)
    2005             : {
    2006         707 :   if (c)
    2007             :   {
    2008         266 :     GEN w = gtoset_shallow(vecslice(v, 1, c)); /* #w /= 3 */
    2009         266 :     if (c != lg(v)-1) w = shallowconcat(w, vecslice(v, c+1, lg(v)-1));
    2010         266 :     v = w;
    2011             :   }
    2012         707 :   return v;
    2013             : }
    2014             : 
    2015             : /* nf cubic field, possible local factors for ideals of square norm p^2 */
    2016             : static GEN
    2017       11396 : cubictypedec(GEN nf, GEN p)
    2018             : {
    2019       11396 :   GEN P = idealprimedec(nf, p);
    2020       11396 :   switch (lg(P))
    2021             :   {
    2022        7616 :     case 2: return NULL;
    2023        2723 :     case 3: if (pr_get_f(gel(P,2)) == 2)
    2024        1568 :               return mkvec(idealhnf_shallow(nf, gel(P,2)));
    2025        1155 :             return mkvec(idealmul(nf, gel(P, 1), gel(P, 2)));
    2026        1057 :     default: return mkvec3(idealmul(nf, gel(P, 1), gel(P, 2)),
    2027        1057 :                            idealmul(nf, gel(P, 2), gel(P, 3)),
    2028        1057 :                            idealmul(nf, gel(P, 3), gel(P, 1)));
    2029             :   }
    2030             : }
    2031             : 
    2032             : /* x = gen_1 or in HNF */
    2033             : static int
    2034       27418 : oddnorm(GEN x) { return typ(x) == t_INT || mpodd(gcoeff(x,1,1)); }
    2035             : 
    2036             : /* return k < 4, s.t 2^(2k) = discriminant of quadratic extension over cubic */
    2037             : static long
    2038       57631 : quadcubpow(GEN bnf, GEN Gid, GEN ideal, GEN a)
    2039             : {
    2040       57631 :   GEN nf = bnf_get_nf(bnf), Sprk = gel(Gid,1);
    2041             :   long t;
    2042       57631 :   if (mpodd(nf_get_disc(nf)))
    2043       37569 :     switch (lg(Sprk))
    2044             :     { /* 2 = P3, P2*P1, P1*P1*P1 */
    2045       20608 :       case 2: return issolvable(nf, a, gel(Sprk,1))? 0: 3; /* ideal is odd */
    2046       13139 :       case 3:
    2047       13139 :         t = issolvable(nf, a, gel(Sprk,2))? 2: 3;
    2048       13139 :         if (oddnorm(ideal) && issolvable(nf, a, gel(Sprk,1))) t -= 2;
    2049       13139 :         return t;
    2050        3822 :       default:
    2051        3822 :         t = 3;
    2052        3822 :         if (oddnorm(ideal))
    2053             :         {
    2054        3374 :           if (issolvable(nf,a,gel(Sprk,1))) t--;
    2055        3374 :           if (issolvable(nf,a,gel(Sprk,2))) t--;
    2056        3374 :           if (issolvable(nf,a,gel(Sprk,3))) t--;
    2057             :         }
    2058             :         else
    2059             :         { /* exactly 2 of the 3 primes divide ideal, test solvability by 3rd */
    2060         448 :           if (!idealval(nf,ideal,sprk_get_pr(gel(Sprk,1))))
    2061          28 :           { if (issolvable(nf,a,gel(Sprk,1))) t--; }
    2062         420 :           else if (!idealval(nf,ideal,sprk_get_pr(gel(Sprk,2))))
    2063          28 :           { if (issolvable(nf,a,gel(Sprk,2))) t--; }
    2064             :           else
    2065         392 :           { if (issolvable(nf,a,gel(Sprk,3))) t--; }
    2066             :         }
    2067        3822 :         return t;
    2068             :     }
    2069       20062 :   if (lg(Sprk) == 3)
    2070             :   { /* 2 = P1^2 P2 */
    2071       10458 :     if (!oddnorm(ideal)) return 3;
    2072        9926 :     t = issolvable(nf, a, gel(Sprk,2))? 2: 3;
    2073        9926 :     if (issolvable(nf, a, gel(Gid,2))) t -= 2; /* solvable mod P1^4 */
    2074        9107 :     else if (issolvable(nf, a, gel(Sprk,1))) t--; /* solvable mod P1^2 */
    2075        9925 :     return t;
    2076             :   }
    2077             :   else
    2078             :   { /* 2 = P1^3, ideal must be odd */
    2079        9604 :     if (issolvable(nf, a, gel(Gid,3)))  return 0; /* solvable mod pr^6 */
    2080        8568 :     if (issolvable(nf, a, gel(Gid,2)))  return 1; /* solvable mod pr^4 */
    2081        6041 :     if (issolvable(nf, a, gel(Sprk,1))) return 2; /* solvable mod pr^2 */
    2082        6041 :     return 3;
    2083             :   }
    2084             : }
    2085             : 
    2086             : /* idealfactorback for { I } x W[1] x ... assuming all W[i] have d entries */
    2087             : static GEN
    2088       34362 : idlist(GEN nf, GEN I, GEN W)
    2089             : {
    2090       34362 :   long i, j, d, l = lg(W);
    2091             :   GEN v, w;
    2092       34362 :   if (l == 1) return mkvec(I? I: gen_1);
    2093          63 :   w = gel(W,1); d = lg(w)-1;
    2094          63 :   if (!I) v = w;
    2095             :   else
    2096             :   {
    2097           7 :     v = cgetg(d + 1, t_VEC);
    2098          28 :     for (j = 1; j <= d; j++) gel(v,j) = idealmul(nf, I, gel(w,j));
    2099             :   }
    2100          98 :   for (i = 2; i < l; i++)
    2101             :   {
    2102          35 :     long nv = lg(v)-1, c, k;
    2103          35 :     GEN V = cgetg(d*nv + 1, t_VEC);
    2104          35 :     w = gel(W,i);
    2105         224 :     for (j = c = 1; j <= nv; j++)
    2106         756 :       for (k = 1; k <= d; k++) gel(V, c++) = idealmul(nf, gel(v,j), gel(w,k));
    2107          35 :     v = V;
    2108             :   }
    2109          63 :   return v;
    2110             : }
    2111             : 
    2112             : static GEN
    2113        4172 : issquareclass(GEN bnf, GEN x, long rc)
    2114             : {
    2115        4172 :   GEN v, d, cyc = bnf_get_cyc(bnf), nf = bnf_get_nf(bnf);
    2116        4172 :   GEN e = isprincipal(bnf, x);
    2117        4172 :   long l = lg(cyc), j;
    2118             : 
    2119        4172 :   v = cgetg(l, t_VEC);
    2120        4277 :   for (j = 1; j <= rc; j++)
    2121             :   {
    2122         287 :     if (mpodd(gel(e,j))) return NULL;
    2123         105 :     gel(v, j) = subii(gel(cyc,j), gel(e,j));
    2124             :   }
    2125        4081 :   for (; j < l; j++)
    2126             :   {
    2127          91 :     GEN t = subii(gel(cyc,j), gel(e,j));
    2128          91 :     if (mpodd(t)) t = addii(t, gel(cyc,j));
    2129          91 :     gel(v, j) = t;
    2130             :   }
    2131             :   /* all exponents are even */
    2132        3990 :   x = isprincipalfact(bnf, x, bnf_get_gen(bnf), v, nf_GENMAT | nf_FORCE);
    2133             :   /* reduce generator mod squares */
    2134        3990 :   x = gel(x,2); x = nffactorback(nf, gel(x,1), ZV_to_Flv(gel(x,2), 2));
    2135        3990 :   x = nfmul(nf, x, nfsqr(nf, idealredmodpower(nf, x, 2, 0)));
    2136        3990 :   x = Q_remove_denom(x, &d); return d? gmul(x, d): x;
    2137             : }
    2138             : /* v a vector of ideals of same norm */
    2139             : static GEN
    2140       35020 : S4makeidclass(GEN bnf, GEN v, long rc)
    2141             : {
    2142       35020 :   long j, c, l = lg(v);
    2143       35020 :   GEN w = cgetg(l, t_VEC);
    2144       70574 :   for (j = c = 1; j < l; j++)
    2145             :   {
    2146       35553 :     GEN N, a, I = gel(v,j);
    2147       35553 :     if (typ(I) == t_INT) a = gen_1;
    2148             :     else
    2149             :     {
    2150        4172 :       if (!(a = issquareclass(bnf, I, rc))) continue; /* I^2 = (a)(mod K^*)^2 */
    2151        3990 :       N = nfnorm(bnf,a);
    2152        3990 :       if (signe(N) < 0) a = gneg(a);/* Norm(a)=|N| is a square */
    2153             :     }
    2154       35371 :     gel(w, c++) = mkvec2(I, a);
    2155             :   }
    2156       35021 :   setlg(w, c); return w;
    2157             : }
    2158             : 
    2159             : /* L squarefree outside of 2, v2(L) <= 4, P = prime divisors of L.
    2160             :  * Write L = N*2^v2, v2 <= 4, N odd sqfree.
    2161             :  * List of squarefree ideals A of norm N^2 (and 4N^2 if v2 > 1) */
    2162             : static GEN
    2163       40425 : S4makeid(GEN bnf, long isA4, long v2, GEN P)
    2164             : {
    2165       40425 :   GEN V, V3, v, id, w, d2, nf = bnf_get_nf(bnf);
    2166             :   long c, c3, i, k, l, n2, rc;
    2167             : 
    2168       40425 :   l = lg(P); V = cgetg(l, t_VEC); V3 = cgetg(l, t_VEC);
    2169       43546 :   for (i = v2? 2: 1, c = c3 = 1; i < l; i++)
    2170             :   {
    2171        9184 :     GEN p = gel(P, i), d = cubictypedec(nf, p);
    2172        9183 :     if (!d) return NULL;
    2173        3121 :     if (lg(d) == 4) gel(V3, c3++) = d; else gel(V,c++) = gel(d, 1);
    2174             :   }
    2175       34362 :   d2 = (v2 > 1)? cubictypedec(nf, gen_2): NULL;
    2176       34362 :   if (isA4)
    2177             :   { /* choose representative in C3 orbit */
    2178        3899 :     if (c3 > 1) gel(V, c++) = gmael(V3, --c3, 1);
    2179        3073 :     else if (d2 && lg(d2) == 4) d2 = mkvec(gel(d2,1));
    2180             :   }
    2181       34362 :   setlg(V,c); setlg(V3,c3);
    2182       34363 :   id = c > 1? idealfactorback(nf, V, NULL, 0): NULL;
    2183       34363 :   v = idlist(nf, id, V3); rc = r2(bnf_get_cyc(bnf));
    2184       34362 :   if (!d2) return mkvec(S4makeidclass(bnf, v, rc));
    2185         658 :   n2 = lg(d2)-1; l = lg(v); w = cgetg(n2 * (l-1) + 1, t_VEC);
    2186        1316 :   for (i = c = 1; i < l; i++)
    2187        1344 :     for (k = 1; k <= n2; k++) gel(w, c++) = idealmul(nf, gel(v,i), gel(d2,k));
    2188         658 :   return mkvec2(v2 == 4? cgetg(1,t_VEC): S4makeidclass(bnf, v, rc),
    2189             :                 S4makeidclass(bnf, w, rc));
    2190             : }
    2191             : 
    2192             : static int
    2193       65782 : checkS4data(GEN x)
    2194       65782 : { return lg(x) == 6 && typ(gel(x, 5)) == t_VECSMALL; }
    2195             : 
    2196             : static GEN
    2197       65782 : S4data(GEN pol, long s)
    2198             : {
    2199             :   GEN bnf, nf, lvunit, Gid, sgnu;
    2200             :   long isA4;
    2201             : 
    2202       65782 :   if (checkS4data(pol)) return pol;
    2203       23958 :   bnf = Buchall(pol, nf_FORCE, MEDDEFAULTPREC);
    2204       23968 :   nf = bnf_get_nf(bnf); Gid = makeGid(nf);
    2205       23967 :   lvunit = makevunits(bnf); isA4 = Z_issquare(nf_get_disc(nf));
    2206       23967 :   sgnu = (s != -1 && nf_get_r1(nf) == 3)? nfsign(nf, lvunit): gen_0;
    2207       23967 :   return mkvecn(5, bnf, lvunit, Gid, sgnu, mkvecsmall(isA4));
    2208             : }
    2209             : static GEN
    2210       23848 : S4_get_disc(GEN S) { return nf_get_disc(bnf_get_nf(gel(S,1))); }
    2211             : 
    2212             : static int
    2213         700 : cmp2(void *E,GEN x,GEN y)
    2214         700 : { (void)E; return  signe(gel(x,2))==0 ? 1: signe(gel(y,2))==0 ? -1: cmpii(gel(x,2), gel(y,2)); }
    2215             : 
    2216             : /* Find quartic A4 or S4-extensions of Q with resolvent pol and square root of
    2217             :  * norm of relative discriminant = L; disc(K/Q) = L^2 nfdisc(pol).
    2218             :  * Here s = -1 or (0, 1, 2) */
    2219             : static GEN
    2220       41943 : makeA4S4(GEN pol, GEN L, long s)
    2221             : {
    2222       41943 :   GEN DATA = S4data(pol, s), bnf = gel(DATA, 1), nf = bnf_get_nf(bnf);
    2223       41943 :   GEN lvunit = gel(DATA, 2), Gid = gel(DATA, 3), sgnunit = gel(DATA, 4);
    2224       41943 :   GEN sgnal0 = NULL, vI, V, P, L2;
    2225       41943 :   long nu, l, c, c1, i, j, k, v2, r1 = nf_get_r1(nf), isA4 = gel(DATA, 5)[1];
    2226             : 
    2227       41944 :   if (s != -1 && ((r1 == 1 && s != 1) || (r1 == 3 && s == 1))) return NULL;
    2228       40467 :   if (typ(L) == t_VEC)
    2229       38990 :   { P = gel(L,1); L = gel(L,2); v2 = vali(L); }
    2230             :   else
    2231             :   {
    2232             :     GEN fa;
    2233        1477 :     v2 = vali(L); if (v2 > 4) return NULL;
    2234        1477 :     fa = Z_factor(L); if (!ZV_is_1(gel(fa,2), v2? 2: 1)) return NULL;
    2235        1435 :     P = gel(fa,1);
    2236             :   }
    2237       40425 :   L2 = v2? shifti(L, -v2): L;
    2238       40425 :   vI = S4makeid(bnf, isA4, v2, P); if (!vI) return NULL;
    2239       34363 :   l = lg(vI); nu = lg(lvunit) - 1;
    2240       34363 :   V = cgetg(RgVV_nb(vI) * nu + 1, t_VEC); c = 1; c1 = 0;
    2241       69383 :   for (k = 1; k < l; k++) /* l = 2 or 3 */
    2242             :   {
    2243       35021 :     GEN I = gel(vI, k);
    2244       35021 :     int norm1 = k == 1 && equali1(L2);
    2245       70392 :     for (j = 1; j < lg(I); j++)
    2246             :     {
    2247       35371 :       GEN ideal = gmael(I, j, 1), al0 = gmael(I, j, 2);
    2248       35371 :       if (s != -1 && r1 == 3) sgnal0 = nfsign(nf, al0);
    2249      103680 :       for (i = norm1? 2 : 1; i <= nu; i++)
    2250             :       {
    2251             :         GEN T, a1, a2, a3, a;
    2252       68309 :         if (sgnal0 && !!s == zv_equal0(Flv_add(sgnal0, gel(sgnunit,i), 2)))
    2253       10682 :           continue;
    2254       57627 :         a = nfmul(nf, al0, gel(lvunit, i));
    2255       57631 :         if (v2 != quadcubpow(bnf, Gid, ideal, a) + (k == 1? 0 : 1)) continue;
    2256        7350 :         if (isA4 && norm1) c1++;
    2257        7350 :         a = nf_to_scalar_or_alg(nf, a);
    2258        7350 :         T = QXQ_charpoly(a, nf_get_pol(nf), 0);
    2259        7350 :         a1 = gel(T,4); a2 = gel(T,3); a3 = negi(gel(T,2));
    2260        7350 :         T = mkpoln(5, gen_1, gen_0, shifti(a1,1), mulsi(-8,sqrti(a3)),
    2261             :                    subii(sqri(a1), shifti(a2, 2)));
    2262        7350 :         gel(V, c++) = isA4? polredabs(T): T;
    2263             :       }
    2264             :     }
    2265             :   }
    2266       34362 :   if (c == 1) return NULL;
    2267        6167 :   setlg(V, c); return isA4? A4clean3(V, c1): V;
    2268             : }
    2269             : 
    2270             : /* A4 fields of square root discriminant = N and "signature" s */
    2271             : static GEN
    2272          49 : makeA4_i(GEN N2, GEN field, long s)
    2273             : {
    2274             :   GEN N, v;
    2275          49 :   if (s == 1 || !Z_issquareall(N2, &N)) return NULL;
    2276          42 :   if (field)
    2277             :   {
    2278           7 :     GEN D = checkfield(field, 3), d, cond;
    2279           7 :     if (!Z_issquareall(D, &d) || !(cond = divide(N,d))
    2280           7 :         || !(v = makeA4S4(field, cond, s))) return NULL;
    2281             :   }
    2282             :   else
    2283             :   {
    2284          35 :     GEN D = divisors(N);
    2285          35 :     long i, cv, l = lg(D);
    2286          35 :     v = cgetg(l, t_VEC);
    2287         119 :     for (i = cv = 1; i < l; i++)
    2288             :     {
    2289          84 :       GEN w, m = gel(D, i), n = gel(D, l-i), C = makeC3_f(m);
    2290          84 :       long j, c, lC = lg(C);
    2291          91 :       for (j = c = 1; j < lC; j++)
    2292           7 :         if ((w = makeA4S4(gel(C,j), n, s))) gel(C,c++) = w;
    2293          84 :       if (c == 1) continue;
    2294           7 :       setlg(C,c); gel(v,cv++) = shallowconcat1(C);
    2295             :     }
    2296          35 :     setlg(v,cv); v = myshallowconcat1(v);
    2297             :   }
    2298          42 :   return v;
    2299             : }
    2300             : static GEN
    2301          49 : makeA4(GEN N, GEN field, long s)
    2302             : {
    2303          49 :   GEN v = makeA4_i(N, field, maxss(s, -1));
    2304          49 :   return v? sturmseparate(v, s, 4): NULL;
    2305             : }
    2306             : 
    2307             : static GEN
    2308          77 : makeS4_i(GEN N, GEN field, long s)
    2309             : {
    2310             :   GEN v;
    2311          77 :   if (field)
    2312             :   {
    2313          28 :     GEN q, f, D = checkfield(field, 3);
    2314          28 :     if (!(q = divide(N, D))) return NULL;
    2315          28 :     setsigne(q, s == 2? -signe(q): 1);
    2316          28 :     if (!Z_issquareall(q, &f) || !(v = makeA4S4(field, f, s))) return NULL;
    2317             :   }
    2318             :   else
    2319             :   {
    2320          49 :     GEN f, M = divisors(N);
    2321          49 :     long i, cv, l = lg(M);
    2322          49 :     v = cgetg(l, t_VEC); if (!odd(s)) s = 0;
    2323         112 :     for (i = cv = 1; i < l; i++)
    2324          63 :       if (Z_issquareall(gel(M, l-i), &f))
    2325             :       {
    2326             :         GEN w, D;
    2327             :         long j, c, lD;
    2328          49 :         if (!(D = makeDL(3, gel(M,i), NULL, s))) continue;
    2329           7 :         lD = lg(D);
    2330          14 :         for (j = c = 1; j < lD; j++)
    2331           7 :           if ((w = makeA4S4(gel(D,j), f, s))) gel(D, c++) = w;
    2332           7 :         if (c == 1) continue;
    2333           7 :         setlg(D, c); gel(v, cv++) = shallowconcat1(D);
    2334             :       }
    2335          49 :     if (cv == 1) return NULL;
    2336           7 :     setlg(v,cv); v = shallowconcat1(v);
    2337             :   }
    2338          35 :   return v;
    2339             : }
    2340             : static GEN
    2341          77 : makeS4(GEN N, GEN field, long s)
    2342             : {
    2343          77 :   GEN v = makeS4_i(N, field, maxss(s, -1));
    2344          77 :   return v? sturmseparate(v, s, 4): NULL;
    2345             : }
    2346             : 
    2347             : static long
    2348          63 : gal_get_order(GEN G) { return degpol(gal_get_pol(G)); }
    2349             : 
    2350             : /* P is monic */
    2351             : static GEN
    2352          28 : makeA4S4resolvent(GEN P, long flag)
    2353             : {
    2354          28 :   GEN R, a0 = gel(P,2), a1 = gel(P,3), a2 = gel(P,4), a3 = gel(P,5);
    2355          28 :   GEN b0 = subii(mulii(a0, subii(shifti(a2,2), sqri(a3))), sqri(a1));
    2356          28 :   GEN b1 = subii(mulii(a3, a1), shifti(a0,2));
    2357          28 :   R = mkpoln(4, gen_1, negi(a2), b1, b0); setvarn(R, varn(P));
    2358          28 :   R = polredabs(R);
    2359          28 :   return flag? mkvec2(R, sqrti(divii(nfdisc(P), nfdisc(R)))): R;
    2360             : }
    2361             : 
    2362             : static GEN
    2363       41593 : A4S4_fa(GEN DATA, GEN fa, long cond, long s)
    2364             : {
    2365       41593 :   pari_sp av = avma;
    2366       41593 :   GEN w, P = gel(fa,1), E = gel(fa,2);
    2367       41593 :   if (odd(cond))
    2368       30548 :   { if (!zv_is_1(E, 1)) return gc_NULL(av); }
    2369             :   else
    2370       11045 :     if (E[1] > 4 || !zv_is_1(E, 2)) return gc_NULL(av);
    2371       40467 :   if (!(w = makeA4S4(DATA, mkvec2(Flv_to_ZV(P), utoipos(cond)), s)))
    2372       34593 :     return gc_NULL(av);
    2373        5873 :   return gc_GEN(av, w);
    2374             : }
    2375             : static GEN
    2376       22706 : nflist_A4S4_worker_i(GEN P3, GEN X, GEN Xinf, long s)
    2377             : {
    2378       22706 :   GEN v, w, F, DATA = S4data(P3, s), D3 = absi_shallow(S4_get_disc(DATA));
    2379       22714 :   long i, c, f, linf, limf = floorsqrtdiv(X, D3);
    2380             : 
    2381       22714 :   linf = cmpii(Xinf, shifti(D3, 2)) >= 0? ceilsqrtdiv(Xinf, D3): 1;
    2382       22714 :   v = cgetg(limf - linf + 2, t_VEC);
    2383       22715 :   F = vecfactoru_i(linf, limf);
    2384       59576 :   for (f = linf, i = c = 1; f <= limf; f++, i++)
    2385       36861 :     if ((w = A4S4_fa(DATA, gel(F,i), f, s))) gel(v, c++) = w;
    2386       22715 :   setlg(v, c); return myshallowconcat1(v);
    2387             : }
    2388             : GEN
    2389       22692 : nflist_A4S4_worker(GEN P3, GEN X, GEN Xinf, GEN gs)
    2390             : {
    2391       22692 :   pari_sp av = avma;
    2392       22692 :   return gc_GEN(av, nflist_A4S4_worker_i(P3, X, Xinf, gs[1]));
    2393             : }
    2394             : 
    2395             : static GEN
    2396          91 : makeA4S4vec(long A4, GEN X, GEN Xinf, GEN field, long s)
    2397             : {
    2398          91 :   long snew = s == -2? -1: s;
    2399             :   GEN v;
    2400             : 
    2401          91 :   if (field)
    2402             :   {
    2403          21 :     GEN D = checkfield(field, 3);
    2404          21 :     long sD = signe(D);
    2405          21 :     if (A4 != Z_issquare(D) || abscmpii(D, X) > 0 ||
    2406          14 :         (sD > 0 && snew == 1) || (sD < 0 && !odd(snew)))
    2407           7 :           return NULL;
    2408          14 :     v = nflist_A4S4_worker_i(field, X, Xinf, snew);
    2409             :   }
    2410             :   else
    2411             :   {
    2412          35 :     v = A4? makeC3vec(X, gen_1, NULL, 0)
    2413          70 :           : makeS3vec(X, gen_1, NULL, odd(snew)? snew: 0);
    2414          70 :     if (!v) return NULL;
    2415          70 :     v = nflist_parapply("_nflist_A4S4_worker",
    2416             :                              mkvec3(X,Xinf,mkvecsmall(snew)), v);
    2417          70 :     v = myshallowconcat1(v);
    2418             :   }
    2419          84 :   return sturmseparate(v, s, 4);
    2420             : }
    2421             : 
    2422             : /**********************************************************************/
    2423             : /*                                 C5                                 */
    2424             : /**********************************************************************/
    2425             : /* elements in B have the same norm */
    2426             : static void
    2427         518 : C5cleanB(GEN nf, GEN aut, GEN B)
    2428             : {
    2429         518 :   long l = lg(B), c, i, j, k;
    2430         518 :   GEN W = const_vecsmall(l - 1, 1);
    2431        2590 :   for (i = c = 1; i < l; i++)
    2432             :   {
    2433             :     GEN bi, d;
    2434        2072 :     if (!W[i]) continue;
    2435         518 :     gel(B, c++) = gel(B,i);
    2436         518 :     bi = Q_remove_denom(nfinv(nf, gel(B,i)), &d); /*1/b = bi / d */
    2437        2072 :     for (j = 1; j <= 3; j++)
    2438             :     {
    2439        1554 :       bi = galoisapply(nf, aut, bi);
    2440        3108 :       for (k = i + 1; k < l; k++)
    2441             :       {
    2442             :         GEN a;
    2443        3108 :         if (!W[k]) continue;
    2444        2485 :         a = nfmuli(nf, bi, gel(B,k)); /* bi/d * B[k] has norm 1 or -1 */
    2445        2485 :         if (absequalii(content(a), d)) { W[k] = 0; break; }
    2446             :       }
    2447             :     }
    2448             :   }
    2449         518 :   setlg(B, c);
    2450         518 : }
    2451             : 
    2452             : static GEN
    2453        2219 : makepolC5(GEN nf, GEN e, GEN b, GEN aut)
    2454             : {
    2455        2219 :   GEN b1 = galoisapply(nf, aut, b), t1 = nfmuli(nf, b, b1);
    2456        2219 :   GEN b2 = galoisapply(nf, aut, b1);
    2457        2219 :   GEN t2 = nfmuli(nf, t1, nfmuli(nf, b1, b2));
    2458        2219 :   GEN v = cgetg(8, t_POL);
    2459        2219 :   v[1] = evalsigne(1) | evalvarn(0);
    2460        2219 :   gel(v, 7) = gen_1;
    2461        2219 :   gel(v, 6) = gen_0;
    2462        2219 :   gel(v, 5) = mulsi(-10, e);
    2463        2219 :   gel(v, 4) = mulsi(-5, mulii(e, nftrace(nf, t1)));
    2464        2219 :   gel(v, 3) = mului(5, mulii(e, subii(e, nftrace(nf,t2))));
    2465        2219 :   gel(v, 2) = mulii(negi(e), nftrace(nf, nfmuli(nf, t1, t2)));
    2466        2219 :   if (umodiu(e, 5)) v = ZX_Z_translate(v, gen_m1);
    2467        2219 :   return ZX_Z_divexact(ZX_z_unscale(v, 5), utoipos(3125));
    2468             : }
    2469             : 
    2470             : /* b a pr-unit; multiply by a unit so that z u = 1 (mod pr5^2) */
    2471             : static GEN
    2472        2219 : C5prim(GEN nf, GEN pr5, GEN z, GEN eps, GEN b)
    2473             : {
    2474        2219 :   GEN pol = nf_get_pol(nf);
    2475             :   long k, j;
    2476        2219 :   if (typ(b) != t_POL) b = scalarpol_shallow(b, varn(pol));
    2477        3836 :   for (j = 0; j <= 1; j++)
    2478             :   {
    2479        3836 :     GEN g = j ? b : ZXQ_mul(b, eps, pol);
    2480       28837 :     for (k = 0; k <= 9; k++)
    2481             :     {
    2482       27220 :       if (idealval(nf, gsubgs(g, 1), pr5) > 1) return g;
    2483       24970 :       if (k < 9) g = ZXQ_mul(g, z, pol);
    2484             :     }
    2485             :   }
    2486           0 :   pari_err_BUG("C5prim");
    2487             :   return NULL; /* LCOV_EXCL_LINE */
    2488             : }
    2489             : 
    2490             : static GEN
    2491         105 : C5bnf()
    2492             : {
    2493         105 :   GEN bnf = Buchall(polcyclo(5,1), nf_FORCE, MEDDEFAULTPREC), nf = bnf_get_nf(bnf);
    2494         105 :   GEN aut = poltobasis(nf, pol_xn(2, 1));
    2495         105 :   GEN p5 = idealprimedec_galois(nf, utoipos(5));
    2496         105 :   return mkvec3(bnf, aut, p5);
    2497             : }
    2498             : 
    2499             : static GEN
    2500        4654 : polsubcycloC5_i(GEN N, GEN T)
    2501             : {
    2502             :   GEN bnf, nf, pol, B, aut, z, eps, p5, N5, P;
    2503             :   long fl5, i, l, v;
    2504             : 
    2505        4654 :   if (!checkcondCL(N, 5, &P)) return NULL;
    2506         598 :   if (typ(N) == t_VEC) N = gel(N,1);
    2507         598 :   if (!T) T = C5bnf();
    2508         598 :   bnf = gel(T, 1); nf = bnf_get_nf(bnf); pol = nf_get_pol(nf);
    2509         602 :   aut = gel(T, 2);
    2510         602 :   p5 = gel(T, 3); v = varn(pol);
    2511         602 :   z = monomial(gen_m1, 1, v); /* tu */
    2512         602 :   eps = deg1pol_shallow(gen_1, gen_1, v); /* fu */
    2513         602 :   N5 = divis_rem(N, 25, &fl5); if (fl5) N5 = N; /* fl5 is set if 5 \nmid N */
    2514         602 :   N5 = mkvec2(N5, P2fa(P));
    2515         602 :   B = bnfisintnorm(bnf, N5); l = lg(B);
    2516        2821 :   for (i = 1; i < l; i++) gel(B, i) = C5prim(nf, p5, z, eps, gel(B, i));
    2517         602 :   if (fl5)
    2518             :   {
    2519         518 :     B = matalgtobasis(nf, B);
    2520         518 :     C5cleanB(nf, aut, B);
    2521             :   }
    2522             :   else
    2523             :   {
    2524          84 :     GEN b5 =  mkpoln(4, gen_m1, gen_1, gen_1, gen_m1); /* norm 25 */
    2525          84 :     setvarn(b5, v); B = matalgtobasis(nf, RgXQV_RgXQ_mul(B, b5, pol));
    2526             :   }
    2527        2821 :   for (i = 1; i < l; i++) gel(B, i) = makepolC5(nf, N, gel(B, i), aut);
    2528         602 :   return B;
    2529             : }
    2530             : 
    2531             : static GEN
    2532          63 : makeC5(GEN N, GEN field, long s)
    2533             : {
    2534             :   GEN sqN, v;
    2535          63 :   checkfield_i(field, 1);
    2536          63 :   if (s > 0 || !Z_ispowerall(N, 4, &sqN)
    2537          63 :      || !(v = polsubcycloC5_i(sqN, NULL))) return NULL;
    2538          28 :   return s == -2? vecs(3,v): v;
    2539             : }
    2540             : 
    2541             : GEN
    2542        4589 : nflist_C5_worker(GEN N, GEN T)
    2543             : {
    2544        4589 :   pari_sp av = avma;
    2545        4589 :   GEN v = polsubcycloC5_i(N, T);
    2546        4588 :   if (!v) retgc_const(av, cgetg(1, t_VEC));
    2547         560 :   return gc_GEN(av, v);
    2548             : }
    2549             : 
    2550             : static GEN
    2551          77 : makeC5vec(GEN X, GEN Xinf, GEN field, long s)
    2552             : {
    2553             :   GEN v, F, bnfC5;
    2554             :   long x, xinf, i, l;
    2555             : 
    2556          77 :   checkfield_i(field, 1); if (s > 0) return NULL;
    2557          63 :   xinf = ceilsqrtn(Xinf, 4);
    2558          63 :   x = floorsqrtn(X, 4); bnfC5 = C5bnf();
    2559          63 :   if (!odd(xinf)) xinf++;
    2560          63 :   if (!odd(x)) x--;
    2561          63 :   F = vecfactoroddu_i(xinf, x); l = lg(F);
    2562        4662 :   for (i = 1; i < l; i++)
    2563        4599 :     gel(F,i) = mkvec2(utoipos(xinf + ((i - 1) << 1)), zm_to_ZM(gel(F,i)));
    2564          63 :   v = nflist_parapply("_nflist_C5_worker", mkvec(bnfC5), F);
    2565          63 :   v = myshallowconcat1(v); return s == -2? vecs(3, v): v;
    2566             : }
    2567             : 
    2568             : /**********************************************************************/
    2569             : /*                            CL (ell prime)                          */
    2570             : /**********************************************************************/
    2571             : /* polredabs iff |nfdisc(pol)| = N */
    2572             : static GEN
    2573         105 : ZX_red_disc(GEN pol, GEN N)
    2574             : {
    2575         105 :   GEN d, B = nfbasis(mkvec2(pol, utoipos(500000)), &d);
    2576         105 :   return absequalii(d, N)? polredabs(mkvec2(pol,B)): NULL;
    2577             : }
    2578             : /* polredabs iff Xinf <= |nfdisc(pol)| <= X */
    2579             : static GEN
    2580         749 : ZX_red_disc2(GEN pol, GEN Xinf, GEN X)
    2581             : {
    2582         749 :   GEN d, B = nfbasis(mkvec2(pol, utoipos(500000)), &d);
    2583         749 :   if (abscmpii(d, X) > 0 || abscmpii(d, Xinf) < 0) return NULL;
    2584         504 :   return polredabs(mkvec2(pol,B));
    2585             : }
    2586             : 
    2587             : /* make CL(f^(ell-1), 0) */
    2588             : static GEN
    2589          98 : makeCL_f(long ell, GEN F)
    2590             : {
    2591          98 :   GEN bnf, P, f = typ(F) == t_VEC? gel(F,1): F;
    2592          98 :   if (!checkcondCL(F, ell, &P)) return cgetg(1,t_VEC);
    2593          56 :   bnf = bnfY(pol_x(1));
    2594          56 :   P = Pell2prfa(bnf_get_nf(bnf), P, ell, f);
    2595          56 :   return mybnrclassfield(bnf, P, ell);
    2596             : }
    2597             : /* ell odd prime */
    2598             : static GEN
    2599         105 : makeCL(long ell, GEN N, GEN field, long s)
    2600             : {
    2601             :   GEN F, v;
    2602         105 :   checkfield_i(field, 1);
    2603         105 :   if (s > 0 || !Z_ispowerall(N, ell-1, &F)) return NULL;
    2604          77 :   v = makeCL_f(ell, F); return s != -2? v: vecs((ell-1)/2, v);
    2605             : }
    2606             : 
    2607             : static GEN
    2608          49 : makeCLresolvent(long ell, GEN pol, long flag)
    2609             : {
    2610          49 :   if (!odd(flag)) return pol_x(0);
    2611          28 :   return mkvec2(pol_x(0), sqrtnint(checkfield(pol, ell), ell-1));
    2612             : }
    2613             : 
    2614             : static GEN
    2615       11415 : RgXV_polred(GEN x)
    2616       11716 : { pari_APPLY_same(polredabs(gel(x,i))); }
    2617             : 
    2618             : GEN
    2619       11403 : nflist_CL_worker(GEN f, GEN bnf, GEN gell)
    2620             : {
    2621       11403 :   pari_sp av = avma;
    2622       11403 :   return gc_upto(av, RgXV_polred(mybnrclassfield(bnf, f, gell[1])));
    2623             : }
    2624             : 
    2625             : static GEN
    2626         238 : makeCLvec(long ell, GEN X, GEN Xinf, GEN field, long s)
    2627             : {
    2628         238 :   long em1 = ell - 1, x, xinf, f;
    2629             :   GEN v, bnf, F;
    2630             : 
    2631         238 :   checkfield_i(field, 1); if (s > 0) return NULL;
    2632         196 :   xinf = ceilsqrtn(Xinf, em1);
    2633         196 :   x = floorsqrtn(X, em1); bnf = bnfY(pol_x(1));
    2634         196 :   F = cgetg(x - xinf + 2, t_VEC);
    2635       11613 :   for (f = xinf; f <= x; f++)
    2636       11417 :     gel(F, f - xinf + 1) = utoipos(f);
    2637         196 :   v = nflist_parapply("_nflist_CL_worker", mkvec2(bnf, mkvecsmall(ell)), F);
    2638         196 :   v = myshallowconcat1(v); return s == -2? vecs(em1>>1, v): v;
    2639             : }
    2640             : 
    2641             : /**********************************************************************/
    2642             : /*                       Cpq (p, q distinct primes)                   */
    2643             : /**********************************************************************/
    2644             : 
    2645             : static long
    2646         231 : isCp(GEN D, long p)
    2647             : {
    2648             :   GEN fa, P, E;
    2649             :   long l, i, e;
    2650         231 :   if (cmpiu(D, 2*p + 1) <= 0) return 0;
    2651         168 :   e = Z_lvalrem(D, p, &D);
    2652         168 :   if (e && e != 2*(p - 1)) return 0;
    2653             :   /* D now coprime to p */
    2654          42 :   if (!Z_ispowerall(D, p-1, &D)) return 0;
    2655             :   /* D must now be squarefree with prime divisors = 1 mod p */
    2656          14 :   fa = Z_factor(D); P = gel(fa, 1); E = gel(fa, 2); l = lg(P);
    2657          28 :   for (i = 1; i < l; i++)
    2658          14 :     if (umodiu(gel(P,i), p) != 1 || !equali1(gel(E,i))) return 0;
    2659          14 :   return 1;
    2660             : }
    2661             : 
    2662             : static void
    2663          35 : nfsort(GEN *pLq, GEN *pLqD)
    2664             : {
    2665             :   long l, i;
    2666          35 :   GEN L = *pLq, D = cgetg_copy(L, &l), V;
    2667        2338 :   for (i = 1; i < l; i++) gel(D, i) = absi(nfdisc(gel(L, i)));
    2668          35 :   V = ZV_indexsort(D);
    2669          35 :   *pLq = vecpermute(L, V);
    2670          35 :   *pLqD = vecpermute(D, V);
    2671          35 : }
    2672             : 
    2673             : static GEN
    2674         224 : nfshorten(GEN L, GEN D, GEN Y)
    2675             : {
    2676         224 :   long l = lg(D), i;
    2677         917 :   for (i = 1; i < l; i++)
    2678         889 :     if (cmpii(gel(D,i), Y) > 0) break;
    2679         224 :   return vecslice(L, 1, i-1);
    2680             : }
    2681             : 
    2682             : static long
    2683         112 : Cpq_snew(long q, long p, long s)
    2684             : {
    2685         112 :   if (q > 2) return s > 0 ? 10 : -1;
    2686         105 :   if (s == 0) return 0;
    2687          91 :   if (s == p) return 1;
    2688          84 :   if (s < 0) return -1;
    2689          42 :   return 10;
    2690             : }
    2691             : static GEN
    2692         126 : divis_if_dvd(GEN F, ulong p)
    2693             : {
    2694             :   long r;
    2695         126 :   GEN q = divis_rem(F, p, &r);
    2696         126 :   return r? F: q;
    2697             : }
    2698             : 
    2699             : static GEN
    2700          49 : makeCpq(long q, long p, GEN N, GEN field, long s)
    2701             : {
    2702          49 :   GEN L, D = NULL, Dfi = NULL;
    2703          49 :   long i, snew, flp = 0, flq = 0, lD, l = 1;
    2704             : 
    2705          49 :   if (q == p) pari_err_IMPL("makeCpq with p = q");
    2706          49 :   if (q > p) lswap(p, q);
    2707          49 :   snew = Cpq_snew(q, p, s); if (snew == 10) return NULL;
    2708          35 :   if (field)
    2709             :   {
    2710           7 :     if (degpol(field) == p) { D = mkvec(nfdisc(field)); flp = 1; }
    2711             :     else
    2712             :     {
    2713           7 :       checkfield_i(field, q);
    2714           7 :       if (q == 2
    2715           7 :           && (snew >= 0 && sturm(field) != 2 - 2*snew)) return NULL;
    2716           7 :       flq = 1; Dfi = absi(nfdisc(field));
    2717             :     }
    2718             :   }
    2719          35 :   if (!flp) D = divisors(cored(N, q));
    2720          35 :   lD = lg(D); L = cgetg(lD, t_VEC);
    2721         266 :   for (i = 1; i < lD; i++)
    2722             :   {
    2723         231 :     GEN Dp = gel(D, i);
    2724         231 :     if (isCp(Dp, p))
    2725             :     {
    2726          14 :       GEN cond = sqrtnint(Dp, p - 1), Q = divii(N, powis(Dp, q));
    2727             :       GEN S, fq, E, A;
    2728          14 :       long j, lE, lS = 1;
    2729          14 :       if (Z_ispowerall(Q, q - 1, &A))
    2730             :       {
    2731          14 :         cond = divis_if_dvd(cond, p);
    2732          14 :         E = divisors(cond); lE = lg(E);
    2733          14 :         S = cgetg(lE, t_VEC);
    2734          42 :         for (j = 1; j < lE; j++)
    2735             :         {
    2736          28 :           GEN m = gel(E, j);
    2737          28 :           if (Z_ispowerall(mulii(A, powiu(m, p - 1)), p, &fq)
    2738          14 :               && equalii(gcdii(fq, cond), m))
    2739             :           {
    2740          14 :             GEN Dq = powiu(fq, q - 1);
    2741          14 :             if (!flq)
    2742           7 :               gel(S, lS++) = nflist(mkvec2s(q, 1), Dq, snew, NULL);
    2743           7 :             else if (equalii(Dq, Dfi))
    2744           7 :               gel(S, lS++) = mkvec(field);
    2745             :           }
    2746             :         }
    2747          14 :         setlg(S, lS);
    2748          14 :         S = myshallowconcat1(S); lS = lg(S);
    2749          14 :         if (lS > 1)
    2750             :         {
    2751          14 :           GEN Lp = nflist(mkvec2s(p, 1), Dp, -1, NULL);
    2752          14 :           long lLp = lg(Lp);
    2753          14 :           GEN T = cgetg(lLp, t_VEC);
    2754          28 :           for (j = 1; j < lLp; j++)
    2755             :           {
    2756          14 :             GEN Lpj = gel(Lp, j), S2 = cgetg(lS, t_VEC);
    2757             :             long k;
    2758          28 :             for (k = 1; k < lS; k++) gel(S2,k) = ZX_composedsum(Lpj, gel(S,k));
    2759          14 :             gel(T, j) = S2;
    2760             :           }
    2761          14 :           gel(L,l++) = myshallowconcat1(T);
    2762             :         }
    2763             :       }
    2764             :     }
    2765             :   }
    2766          35 :   setlg(L, l); L = myshallowconcat1(L);
    2767          35 :   if (s != -2) return L;
    2768           7 :   if (q > 2) return vecs((p*q-1)>>1, L);
    2769           7 :   return sturmseparate(L, s, p*q);
    2770             : }
    2771             : 
    2772             : static GEN
    2773          63 : makeCpqvec(long q, long p, GEN X, GEN Xinf, GEN field, long s)
    2774             : {
    2775          63 :   GEN Lp, Lq = gen_0, LqD, R = cgetg(1, t_VEC);
    2776          63 :   long i, snew, flp = 0, flq = 0;
    2777             : 
    2778          63 :   if (q == p) pari_err_IMPL("makeCpqvec with p = q");
    2779          63 :   if (q > p) { long tmp = p; p = q; q = tmp; }
    2780          63 :   snew = Cpq_snew(q, p, s); if (snew == 10) return cgetg(1, t_VEC);
    2781          35 :   if (field)
    2782             :   {
    2783           7 :     if (degpol(field) == p)
    2784           0 :     { Lp = mkvec(field); flp = 1; }
    2785             :     else
    2786             :     {
    2787           7 :       checkfield_i(field, q);
    2788           7 :       Lq = mkvec(field); flq = 1;
    2789           7 :       if (q == 2)
    2790             :       {
    2791           7 :         if (snew >= 0 && sturm(field) != 2 - 2*snew)
    2792           0 :           return cgetg(1, t_VEC);
    2793             :       }
    2794             :     }
    2795             :   }
    2796          35 :   if (!flp)
    2797          35 :     Lp = nflist(mkvec2s(p, 1), mkvec2(gen_1, sqrtnint(X, q)), -1, NULL);
    2798          35 :   if (!flq)
    2799          28 :     Lq = nflist(mkvec2s(q, 1), mkvec2(gen_1, sqrtnint(X, p)), snew, NULL);
    2800          35 :   nfsort(&Lq, &LqD);
    2801         147 :   for (i = 1; i < lg(Lp); i++)
    2802             :   {
    2803         112 :     GEN S = cgetg(1, t_VEC), P = gel(Lp, i), Dp = nfdisc(P);
    2804         112 :     GEN cond = sqrtnint(Dp, p - 1), Dpq = gpowgs(Dp, q), E;
    2805             :     long k;
    2806         112 :     cond = divis_if_dvd(cond, p);
    2807         112 :     E = divisors(cond);
    2808         336 :     for (k = 1; k < lg(E); k++)
    2809             :     {
    2810         224 :       GEN m = gel(E, k), mqm = powiu(m, q - 1), mB = powiu(mqm, p - 1);
    2811         224 :       GEN lim = sqrtnint(divii(mulii(mB, X), Dpq), p);
    2812         224 :       GEN Lqsh = nfshorten(Lq, LqD, lim);
    2813         224 :       long j, lq = lg(Lqsh), ct = 1;
    2814         224 :       GEN Ssh = cgetg(lq, t_VEC);
    2815         917 :       for (j = 1; j < lq; j++)
    2816             :       {
    2817         693 :         GEN Q = gel(Lqsh, j), Dq = gel(LqD, j), fq = sqrtnint(Dq, q - 1);
    2818         693 :         if (equalii(gcdii(cond, fq), m)
    2819         112 :             && gcmp(gdiv(mulii(Dpq, powiu(Dq, p)), mB), Xinf) >= 0)
    2820         112 :           gel(Ssh, ct++) = ZX_composedsum(P, Q);
    2821             :       }
    2822         224 :       setlg(Ssh, ct); S = shallowconcat(S, Ssh);
    2823             :     }
    2824         112 :     R = shallowconcat(R, S);
    2825             :   }
    2826          35 :   if (s != -2) return R;
    2827           7 :   if (q > 2) return vecs((p*q-1)>>1, R);
    2828           7 :   return sturmseparate(R, s, p*q);
    2829             : }
    2830             : 
    2831             : /* find the single t_POL of degree p in L */
    2832             : static GEN
    2833          49 : find_by_deg(GEN L, long p)
    2834             : {
    2835          49 :   long l = lg(L), i;
    2836          49 :   GEN T = NULL;
    2837         245 :   for (i = 1; i < l; i++)
    2838         196 :     if (degpol(gel(L,i)) == p)
    2839             :     {
    2840          49 :       if (T) return NULL;
    2841          49 :       T = gel(L,i);
    2842             :     }
    2843          49 :   return T;
    2844             : }
    2845             : 
    2846             : static GEN
    2847          28 : makeCpqresolvent_i(long p, long q, GEN pol, long flag)
    2848             : {
    2849          28 :   GEN Lpq = nfsubfields0(pol, 0, 1), Lp, Lq;
    2850             : 
    2851          28 :   Lq = find_by_deg(Lpq, q);
    2852          28 :   if (!Lq) pari_err_TYPE("nfresolvent (C_pq)", pol);
    2853          28 :   if (!flag) return Lq;
    2854             : 
    2855          21 :   Lp = find_by_deg(Lpq, p);
    2856          21 :   if (!Lp) pari_err_TYPE("nfresolvent (C_pq)", pol);
    2857          21 :   if (flag >= 2) return mkvec2(Lq, Lp);
    2858           7 :   return mkvec2(Lq, sqrtnint(nfdisc(Lp), p-1));
    2859             : }
    2860             : static GEN
    2861          28 : makeCpqresolvent(long p, long q, GEN pol, long flag)
    2862             : {
    2863          28 :   pari_sp av = avma;
    2864          28 :   return gc_GEN(av, makeCpqresolvent_i(p, q, pol, flag));
    2865             : }
    2866             : 
    2867             : static GEN
    2868           0 : makeCpqsome(long p, long q, long s)
    2869             : {
    2870           0 :   pari_sp av = avma;
    2871           0 :   long i, j, ct = 1, snew = Cpq_snew(q, p, s);
    2872           0 :   GEN Lp = nflist(mkvec2s(p, 1), NULL, -1, NULL);
    2873           0 :   GEN Lq = nflist(mkvec2s(q, 1), NULL, snew, NULL);
    2874           0 :   GEN S = cgetg(13, t_VEC);
    2875           0 :   long lLp = minss(4, lg(Lp)), lLq = minss(5, lg(Lq));
    2876           0 :   for (i = 1; i < lLp; i++)
    2877             :   {
    2878           0 :     GEN P = gel(Lp, i);
    2879           0 :     for (j = 1; j < lLq; j++)
    2880           0 :       gel(S, ct++) = ZX_composedsum(P, gel(Lq, j));
    2881             :   }
    2882           0 :   setlg(S, ct); return gc_GEN(av, S);
    2883             : }
    2884             : 
    2885             : /**********************************************************************/
    2886             : /*                            DL (ell prime)                          */
    2887             : /**********************************************************************/
    2888             : /* For metacyclic groups; assume G is Galois and non-abelian */
    2889             : static GEN
    2890         952 : getpol(GEN nf, GEN T)
    2891             : {
    2892         952 :   GEN G = galoisinit(rnfequation(nf, T), NULL);
    2893         952 :   return galoisfixedfield(G, vecsplice(gal_get_gen(G), 1), 1, 0);
    2894             : }
    2895             : 
    2896             : static GEN
    2897        1428 : makeDL(long ell, GEN N, GEN field, long s)
    2898             : {
    2899        1428 :   GEN v, vD, F = N;
    2900        1428 :   long i, l, c, si = 0, pow = (ell - 1) >> 1;
    2901             : 
    2902        1428 :   if (s > 0 && s != pow) return NULL;
    2903        1393 :   if (ell != 3 && !Z_ispowerall(N, pow, &F)) return NULL;
    2904        1393 :   if (field)
    2905             :   {
    2906          42 :     GEN q, D = checkfield(field, 2);
    2907          42 :     si = signe(D);
    2908          42 :     if ((s > 0 && si > 0) || (!s && si < 0)) return NULL;
    2909          42 :     D = absi_shallow(D);
    2910          42 :     if (!(q = divide(F, D))) return NULL;
    2911          42 :     vD = mkvec2(q, D);
    2912             :   }
    2913        1351 :   else vD = divisors(F);
    2914        1393 :   l = lg(vD); v = cgetg(2 * l, t_VEC);
    2915       14476 :   for (i = 2, c = 1; i < l; i++) /* omit 1 */
    2916             :   {
    2917       13083 :     GEN LD, f, M = gel(vD, i);
    2918             :     int p, m;
    2919             :     long j;
    2920       15232 :     if (!Z_issquareall(gel(vD, l-i), &f)) continue;
    2921        3388 :     is_fundamental_pm(M, s, &p, &m);
    2922        3388 :     if (si < 0) p = 0;
    2923        3388 :     if (si > 0) m = 0;
    2924        3388 :     if (!(LD = fund_pm(M, p, m))) continue;
    2925        2653 :     for (j = 1; j < lg(LD); j++)
    2926             :     {
    2927        1414 :       GEN D = gel(LD, j), R, bnf, P, G, pol;
    2928             :       long k, lR;
    2929        1890 :       if (!checkcondDL(D, f, ell, &P)) continue;
    2930         735 :       pol = Y2m(gel(LD,j)); bnf = bnfY(pol);
    2931         735 :       G = mkvec2(galoisinit(pol,NULL), gen_2);
    2932         735 :       P = Pell2prfa(bnf_get_nf(bnf), P, ell, f);
    2933         735 :       R = mybnrclassfield_X(bnf, P, ell, NULL, NULL, G);
    2934         735 :       lR = lg(R); if (lR == 1) continue;
    2935             :       /* L/Q degree ell subfield of R; d(L) = F^pow, F = D f^2 */
    2936         518 :       for (k = 1; k < lR; k++) gel(R,k) = polredabs(getpol(bnf, gel(R,k)));
    2937         259 :       gel(v, c++) = R;
    2938             :     }
    2939             :   }
    2940        1393 :   if (c == 1) return NULL;
    2941         245 :   setlg(v, c); return sturmseparate(myshallowconcat1(v), s, ell);
    2942             : }
    2943             : /* ell >= 5 prime */
    2944             : static GEN
    2945          35 : makeDLresolvent(long ell, GEN pol, long flag)
    2946             : {
    2947          35 :   GEN Dpow = checkfield(pol, ell), D, DF, F;
    2948          35 :   long d4, pow = (ell - 1) >> 1, si = signe(Dpow);
    2949          35 :   D = si > 0 ? sqrtnint(Dpow, pow) : negi(sqrtnint(negi(Dpow), pow));
    2950          35 :   d4 = Mod4(D);
    2951          35 :   if (d4 == 3 || (d4 == 0 && si > 0 && pol2s(pol))) D = negi(D);
    2952          21 :   else if (d4 == 2) D = shifti(D, 2);
    2953          35 :   DF = coredisc2(D); D = quadpoly_i(gel(DF, 1)); F = gel(DF, 2);
    2954          35 :   return flag? mkvec2(D, F): D;
    2955             : }
    2956             : 
    2957             : GEN
    2958        6425 : nflist_DL_worker(GEN P2, GEN X1pow, GEN X0pow, GEN X2, GEN Xinf2, GEN gell)
    2959             : {
    2960        6425 :   pari_sp av = avma;
    2961        6425 :   GEN X, Xinf, G, D, Da, V, bnf = bnfY(P2), nf = bnf_get_nf(bnf);
    2962        6433 :   long f, c, limf, linf, ell = gell[1];
    2963             : 
    2964        6433 :   G = mkvec2(galoisinit(nf_get_pol(nf),NULL), gen_2);
    2965        6433 :   D = bnf_get_disc(bnf);
    2966        6433 :   Da = absi_shallow(D);
    2967        6433 :   limf = floorsqrtdiv(X1pow, Da);
    2968        6433 :   linf = cmpii(X0pow, shifti(Da, 2)) >= 0? ceilsqrtdiv(X0pow, Da): 1;
    2969        6433 :   V = cgetg(limf + 1, t_VEC);
    2970             :   /* K/Q degree l with D_l Galois closure L/Q and k/Q quadratic resolvent
    2971             :    * Then d_k = D, d_K = D^(l-1)/2 f^(l-1), d_L = D^l f^(2l-2).
    2972             :    * Want d_K in [Xinf,X], i.e. d_L in D [Xinf^2,X^2] */
    2973        6433 :   Xinf = mulii(Da, Xinf2); X = mulii(Da, X2);
    2974       15456 :   for (f = linf, c = 1; f <= limf; f++)
    2975             :   {
    2976        9023 :     pari_sp av2 = avma;
    2977        9023 :     GEN P, R, F = utoipos(f);
    2978             :     long lR, k;
    2979       15071 :     if (!checkcondDL(D, F, ell, &P)) { set_avma(av2); continue; }
    2980        6433 :     P = Pell2prfa(nf, P, ell, F);
    2981        6433 :     R = mybnrclassfield_X(bnf, P, ell, X, Xinf, G);
    2982        6433 :     lR = lg(R); if (lR == 1) { set_avma(av2); continue; }
    2983         770 :     for (k = 1; k < lR; k++) gel(R,k) = polredabs(getpol(bnf, gel(R,k)));
    2984         385 :     gel(V, c++) = R;
    2985             :   }
    2986        6433 :   setlg(V,c); return gc_GEN(av, myshallowconcat1(V));
    2987             : }
    2988             : 
    2989             : static GEN
    2990        1211 : makeDLvec(long ell, GEN X, GEN Xinf, GEN field, long s)
    2991             : {
    2992             :   GEN v, X1pow, X0pow, V2;
    2993        1211 :   long pow = (ell - 1) >> 1;
    2994             : 
    2995        1211 :   checkfield_i(field, 2); if (s > 0 && s != pow) return NULL;
    2996        1162 :   if (s == pow) s = 1;
    2997        1162 :   X1pow = sqrtnint(X, pow);
    2998        1162 :   X0pow = gceilsqrtn(Xinf, pow);
    2999        1162 :   V2 = field? mkvec(field): makeC2vec(X1pow, gen_1, NULL, s == -2? -1: s);
    3000        1162 :   if (!V2) return NULL;
    3001        1162 :   v = nflist_parapply("_nflist_DL_worker", mkvec5(X1pow, X0pow, sqri(X),
    3002             :                            sqri(Xinf), mkvecsmall(ell)), V2);
    3003        1162 :   return sturmseparate(myshallowconcat1(v), s, ell);
    3004             : }
    3005             : /**********************************************************************/
    3006             : /*                                 D9                                 */
    3007             : /**********************************************************************/
    3008             : /* disc = D^4 g^2 f^6 (quad. subfield: D, cubic subfield: D g^2) */
    3009             : static GEN
    3010          63 : makeD9(GEN N, GEN field, long s)
    3011             : {
    3012             :   GEN v, LD, D, D4;
    3013             :   long i, j, si;
    3014             : 
    3015          63 :   if ((s > 0 && s != 4) || !Z_issquare(N)) return NULL;
    3016          49 :   if (field)
    3017             :   {
    3018           7 :     D = checkfield(field, 2); D4 = powiu(D, 4);
    3019           7 :     si = signe(D);
    3020           7 :     if ((s > 0 && si > 0) || (s == 0 && si < 0) || !dvdii(N, D4)) return NULL;
    3021           7 :     LD = mkvec(field);
    3022             :   }
    3023             :   else
    3024             :   {
    3025          42 :     GEN t = divisorsdisc(cored(N, 4), s);
    3026          42 :     long l = lg(t);
    3027          42 :     LD = cgetg(l, t_VEC);
    3028         105 :     for (j = 1; j < l; j++) gel(LD, j) = quadpoly_i(gel(t, j));
    3029             :   }
    3030          49 :   v = cgetg(1, t_VEC);
    3031         119 :   for (i = 1; i < lg(LD); i++)
    3032             :   {
    3033          70 :     GEN bnf = bnfY(gel(LD, i)), Q, F, G;
    3034          70 :     G = mkvec2(galoisinit(bnf, NULL), gen_2);
    3035          70 :     D4 = powiu(bnf_get_disc(bnf), 4); Q = divii(N, D4);
    3036          70 :     F = divisors(cored(Q, 6));
    3037         182 :     for (j = 1; j < lg(F); j++)
    3038             :     {
    3039         112 :       GEN R = mybnrclassfield_X(bnf, gel(F,j), 9, NULL, NULL, G);
    3040             :       long k;
    3041         140 :       for (k = 1; k < lg(R); k++)
    3042             :       {
    3043          28 :         GEN pol = getpol(bnf, gel(R, k));
    3044          28 :         if (pol && (pol = ZX_red_disc(pol, N))) v = shallowconcat(v, pol);
    3045             :       }
    3046             :     }
    3047             :   }
    3048          49 :   return sturmseparate(v, s, 9);
    3049             : }
    3050             : 
    3051             : GEN
    3052        1530 : nflist_D9_worker(GEN P2, GEN X, GEN Xinf)
    3053             : {
    3054        1530 :   pari_sp av = avma;
    3055        1530 :   GEN v, bnf = bnfY(P2), D2 = bnf_get_disc(bnf);
    3056        1533 :   GEN G = mkvec2(galoisinit(bnf, NULL), gen_2);
    3057             :   long l, f, c;
    3058             : 
    3059        1533 :   l = floorsqrtndiv(X, powiu(D2, 4), 6) + 1;
    3060        1533 :   v = cgetg(l, t_VEC); c = 1;
    3061        4697 :   for (f = 1; f < l; f++)
    3062             :   {
    3063        3164 :     GEN R = mybnrclassfield_X(bnf, utoipos(f), 9, NULL, NULL, G);
    3064        3164 :     long k, ci, lR = lg(R);
    3065        3185 :     for (k = ci = 1; k < lR; k++)
    3066             :     {
    3067          21 :       GEN pol = getpol(bnf, gel(R, k));
    3068          21 :       if ((pol = ZX_red_disc2(pol, Xinf, X))) gel(R, ci++) = pol;
    3069             :     }
    3070        3164 :     if (ci > 1) { setlg(R, ci); gel(v, c++) = R; }
    3071             :   }
    3072        1533 :   setlg(v,c); return gc_GEN(av, myshallowconcat1(v));
    3073             : }
    3074             : 
    3075             : static GEN
    3076          14 : makeD9resolvent(GEN G, long flag)
    3077             : {
    3078          14 :   GEN R = polredabs(galoisfixedfield(G, vecsplice(gal_get_gen(G), 2), 1, 0));
    3079          14 :   return condrel(R, gal_get_pol(G), flag);
    3080             : }
    3081             : 
    3082             : static GEN
    3083          49 : makeD9vec(GEN X, GEN Xinf, GEN field, long s)
    3084             : {
    3085             :   GEN X1pow, V2, v;
    3086             : 
    3087          49 :   checkfield_i(field,2); if (s > 0 && s != 4) return NULL;
    3088          28 :   if (s == 4) s = 1;
    3089          28 :   X1pow = sqrtnint(X, 4);
    3090          28 :   V2 = field? mkvec(field): makeC2vec(X1pow, gen_1, NULL, s == -2? -1: s);
    3091          28 :   if (!V2) return NULL;
    3092          28 :   v = nflist_parapply("_nflist_D9_worker", mkvec2(X, Xinf), V2);
    3093          28 :   return sturmseparate(myshallowconcat1(v), s, 9);
    3094             : }
    3095             : /**********************************************************************/
    3096             : /* Metacyclic C_a \rtimes C_ell groups with ell prime and a | ell - 1 */
    3097             : /*                includes F5 = M20, M21, and M42                     */
    3098             : /**********************************************************************/
    3099             : /* C_a resolvent field. */
    3100             : static GEN nfmakenum(long n, long t, GEN N, GEN field, long s);
    3101             : static GEN nfmakevecnum(long n, long t, GEN X, GEN Xinf, GEN field, long s);
    3102             : 
    3103             : static GEN
    3104         462 : MgenF(long ell, GEN d, GEN Fn, long *vell)
    3105             : {
    3106             :   GEN F;
    3107         462 :   if (umodiu(d, ell)) *vell = 0;
    3108             :   else
    3109             :   {
    3110         182 :     *vell = Z_lval(Fn, ell) % (ell - 1);
    3111         182 :     if (*vell) Fn = diviiexact(Fn, powuu(ell, *vell));
    3112             :   }
    3113         462 :   return Z_ispowerall(Fn, ell - 1, &F)? F: NULL;
    3114             : }
    3115             : 
    3116             : static int
    3117        2912 : okgal(GEN P, GEN g)
    3118             : {
    3119        2912 :   GEN G = polgalois0(P, 1, DEFAULTPREC);
    3120        5320 :   return equaliu(gel(G,1), g[1]) && equalis(gel(G,2), g[2])
    3121        5320 :                                  && equaliu(gel(G,3), g[3]);
    3122             : }
    3123             : static int
    3124        2380 : okgal1(GEN P, long d)
    3125        2380 : { GEN G = polgalois0(P, 1, DEFAULTPREC); return equaliu(gel(G,1), d); }
    3126             : static int
    3127          21 : okgal2(GEN P, long d, long p)
    3128             : {
    3129          21 :   GEN G = polgalois0(P, 1, DEFAULTPREC);
    3130          21 :   return equaliu(gel(G,1), d) && equalis(gel(G,2), p);
    3131             : }
    3132             : static int
    3133         721 : ok_s(GEN P, long s) { return s < 0 || pol2s(P) == s; }
    3134             : 
    3135             : /* a | ell - 1, (Z/aZ)^* cyclic, F^(ell-1)*D^((ell-1)/a) */
    3136             : static GEN
    3137         126 : makeMgen(long ell, long a, GEN N, GEN field, long s)
    3138             : {
    3139             :   GEN v, Fn, F;
    3140         126 :   long i, lv, c, vell, deg = ell * a, drel = (ell - 1) / a;
    3141             : 
    3142         126 :   if (field)
    3143             :   {
    3144           7 :     GEN d = absi_shallow(checkfield(field, a));
    3145           7 :     Fn = gdiv(N, powiu(d, drel));
    3146           7 :     if (typ(Fn) != t_INT || !(F = MgenF(ell, d, Fn, &vell))) return NULL;
    3147           7 :     v = mkvec(mkvec3(mkvec(field), F, utoi(vell)));
    3148             :   }
    3149             :   else
    3150             :   {
    3151         119 :     long s2 = maxss(s, -1);
    3152         119 :     v = divisors(cored(N, drel)); lv = lg(v);
    3153         574 :     for (i = c = 1; i < lv; i++)
    3154             :     {
    3155         455 :       GEN R, d = gel(v, i); Fn = diviiexact(N, powiu(d, drel));
    3156         455 :       if ((F = MgenF(ell, d, Fn, &vell))
    3157         189 :            && (R = nfmakenum(a, 1, d, NULL, s2))) /* C_a, disc d */
    3158          49 :         gel(v, c++) = mkvec3(R, F, utoi(vell));
    3159             :     }
    3160         119 :     setlg(v, c);
    3161             :   }
    3162         126 :   lv = lg(v);
    3163         182 :   for (i = 1; i < lv; i++)
    3164             :   {
    3165          56 :     GEN T = gel(v, i), R = gel(T, 1), F0 = gel(T, 2);
    3166          56 :     long vell = itou(gel(T, 3)), lR = lg(R), j;
    3167          91 :     for (j = c = 1; j < lR; j++)
    3168             :     {
    3169          35 :       GEN nf = nfY(gel(R,j)), F = F0, K, G;
    3170             :       long k, ck, l;
    3171          35 :       if (vell)
    3172             :       { /* ell ramified in nf */
    3173             :         long eell, q;
    3174          21 :         GEN pell = getpell(nf, ell, &eell);
    3175          21 :         q = (ell - 1) / eell; if (vell % q) continue;
    3176          21 :         F = idealmul(nf, F, idealpows(nf, pell, vell / q));
    3177             :       }
    3178          35 :       G = mkvec2(galoisinit(nf, NULL), gen_2);
    3179          35 :       K = mybnrclassfield_X(Buchall(nf, nf_FORCE, MEDDEFAULTPREC),
    3180             :                             F, ell, NULL, NULL, G);
    3181          35 :       l = lg(K);
    3182          63 :       for (k = ck = 1; k < l; k++)
    3183             :       {
    3184          28 :         GEN q = getpol(nf, gel(K, k));
    3185          56 :         if ((deg == 21 || okgal1(q, deg)) && /* automatic for M21;FIXME */
    3186          56 :             (q = ZX_red_disc(q, N))) gel(K, ck++) = q;
    3187             :       }
    3188          35 :       if (ck > 1) { setlg(K, ck); gel(R,c++) = K; }
    3189             :     }
    3190          56 :     setlg(R, c); gel(v, i) = myshallowconcat1(R);
    3191             :   }
    3192         126 :   return sturmseparate(gtoset_shallow(myshallowconcat1(v)), s, ell);
    3193             : }
    3194             : 
    3195             : /* (ell,a) = (5,4), (7,3) or (7,6) */
    3196             : static GEN
    3197          35 : makeMgenresolvent(long ell, long a, GEN pol, long flag)
    3198             : {
    3199          35 :   GEN Dpow = checkfield(pol, ell), G, R, DR, F2, nf, pell, F;
    3200             : 
    3201          35 :   G = galoissplittinginit(pol, utoipos(a*ell));
    3202          35 :   if (gal_get_order(G) != a * ell) pari_err_BUG("nfresolvent [Galois group]");
    3203          35 :   R = polredabs(galoisfixedfield(G, vecsplice(gal_get_gen(G), 2), 1, 0));
    3204          35 :   if (!flag) return R;
    3205          35 :   DR = nfdisc(R);
    3206          35 :   if (ell == 5 && a == 4)
    3207             :   {
    3208          14 :     F2 = sqrti(divii(Dpow, DR));
    3209          14 :     if (!Z_issquareall(F2, &F))
    3210             :     {
    3211             :       long e;
    3212          14 :       F2 = divis(F2, 5);
    3213          14 :       if (!Z_issquareall(F2, &F)) pari_err_BUG("nfresolvent [F5]");
    3214          14 :       nf = nfinit(R, MEDDEFAULTPREC); pell = getpell(nf, 5, &e);
    3215          14 :       if (e == 4) pell = idealsqr(nf, pell);
    3216          14 :       F = idealmul(nf, F, pell);
    3217             :     }
    3218             :   }
    3219             :   else
    3220             :   { /* ell == 7 && (a == 3 || a == 6) */
    3221             :     long v;
    3222          21 :     if (a == 3) DR = sqri(DR);
    3223          21 :     if (!Z_issquareall(divii(Dpow, DR), &F2))
    3224           0 :       pari_err_BUG("nfresolvent [M21/M42]");
    3225             :     /* F2 = F^3 or 7F^3 or 7^2F^3 */
    3226          21 :     v = Z_lval(F2, 7) % 3;
    3227          21 :     if (v) F2 = divii(F2, powuu(7, v));
    3228          21 :     if (!Z_ispowerall(F2, 3, &F)) pari_err_BUG("nfresolvent [M21/M42]");
    3229          21 :     if (v)
    3230             :     {
    3231             :       long e;
    3232           7 :       nf = nfinit(R, DEFAULTPREC); pell = getpell(nf, 7, &e);
    3233           7 :       if (e == 6) v *= 2;
    3234           7 :       F = idealmul(nf, F, idealpows(nf, pell, v));
    3235             :     }
    3236             :   }
    3237          35 :   return mkvec2(R, F);
    3238             : }
    3239             : 
    3240             : GEN
    3241        2802 : nflist_Mgen_worker(GEN field, GEN X, GEN Xinf, GEN T)
    3242             : {
    3243        2802 :   pari_sp av = avma;
    3244        2802 :   GEN v, Fn, pell, lpow, bnf = bnfY(field), D = bnf_get_disc(bnf);
    3245        2807 :   GEN G = mkvec2(galoisinit(bnf, NULL), gen_2);
    3246        2807 :   long ell = T[1], drel = T[2], deg = T[3], c, e;
    3247        2807 :   long vd = Z_lval(D, ell), limf, f;
    3248             : 
    3249        2807 :   Fn = divii(X, drel == 1 ? absi_shallow(D) : sqri(D));
    3250        2807 :   limf = floorsqrtn(Fn, ell - 1);
    3251        2807 :   pell = getpell(bnf, ell, &e); /* e | a */
    3252        2807 :   lpow = powuu(ell, (ell - 1) / e);
    3253        2807 :   v = cgetg(limf + 1, t_VEC);
    3254        6902 :   for (f = c = 1; f <= limf; f++)
    3255             :   {
    3256        4095 :     GEN F = utoipos(f), K;
    3257             :     long k, ci, lK;
    3258             : 
    3259        4095 :     if (vd)
    3260             :     {
    3261        2135 :       GEN fn = powuu(f, ell - 1);
    3262        2135 :       long imax = minss(e - 1, logint(divii(Fn, fn), lpow));
    3263        2135 :       F = mkcol2(F, gmulgu(idealpows(bnf, pell, imax), f));
    3264             :     }
    3265        4095 :     K = mybnrclassfield_X(bnf, F, ell, NULL, NULL, G); lK = lg(K);
    3266        4326 :     for (k = ci = 1; k < lK; k++)
    3267             :     {
    3268         231 :       GEN q = getpol(bnf, gel(K, k));
    3269         462 :       if (degpol(q) == ell && (deg == 21 || okgal1(q, deg)) && /* FIXME */
    3270         462 :           (q = ZX_red_disc2(q, Xinf, X))) gel(K, ci++) = q;
    3271             :     }
    3272        4095 :     if (ci > 1) { setlg(K, ci); gel(v, c++) = K; }
    3273             :   }
    3274        2807 :   setlg(v, c); v = gtoset_shallow(myshallowconcat1(v));
    3275        2807 :   return gc_GEN(av, v);
    3276             : }
    3277             : 
    3278             : /* (a,ell) = (3,7), (4,5) or (6,7) */
    3279             : static GEN
    3280         140 : makeMgenvec(long ell, long a, GEN X, GEN Xinf, GEN field, long s)
    3281             : {
    3282             :   GEN L, v, T;
    3283         140 :   long drel = (ell - 1) / a;
    3284             : 
    3285         140 :   if (field)
    3286             :   {
    3287          14 :     if (degpol(field) != a || !okgal2(field, a, a==3? 1: -1))
    3288           7 :       pari_err_TYPE("makeMgenvec [field]", field);
    3289           7 :     L = mkvec(field);
    3290             :   }
    3291         126 :   else L = nfmakevecnum(a, 1, drel == 1? X: sqrti(X), gen_1, NULL, maxss(s,-1));
    3292         133 :   if (!L) return NULL;
    3293          91 :   T = mkvecsmall3(ell, drel, ell * a);
    3294          91 :   v = nflist_parapply("_nflist_Mgen_worker", mkvec3(X, Xinf, T), L);
    3295          91 :   return sturmseparate(myshallowconcat1(v), s, ell);
    3296             : }
    3297             : 
    3298             : /**********************************************************************/
    3299             : /*                        A5 by table lookup                          */
    3300             : /**********************************************************************/
    3301             : /* V a vector of [T, n] sorted wrt t_INT n. Return elts with Xinf <= n <= X.
    3302             :  * If flag = 0 return only the T's. */
    3303             : static GEN
    3304         273 : vecslicebyX(GEN V, GEN Xinf, GEN X, long flag)
    3305             : {
    3306         273 :   long l = lg(V), i = 1, c;
    3307             :   GEN W;
    3308         273 :   if (cmpii(Xinf,gmael(V,1,2)) > 0) /* frequent special case */
    3309             :   {
    3310          63 :     i = gen_search(V, mkvec2(NULL,Xinf), NULL, &cmp2);
    3311          63 :     if (i > 0) /* found in list, rewind to first occurence */
    3312          21 :     { while (i > 1 && equalii(gmael(V, i-1, 2), Xinf)) i--; }
    3313             :     else /* not in list */
    3314          42 :       i = -i;
    3315             :   }
    3316         273 :   W = cgetg(l, t_VEC);
    3317        5033 :   for (c = 1; i < l; i++)
    3318             :   {
    3319        5033 :     GEN C = gmael(V, i, 2), x;
    3320        5033 :     if (isintzero(C)) /* marker for incomplete slice */
    3321             :     {
    3322           0 :       GEN B = gmael(V, i-1, 2);
    3323           0 :       if (equalii(B, X)) break;
    3324           0 :       pari_err_DOMAIN("nflist(A5)", "sqrt(N)", ">", B, X);
    3325             :     }
    3326        5033 :     if (cmpii(C, X) > 0) break;
    3327        4760 :     x = RgV_to_RgX(gmael(V, i, 1), 0);
    3328        4760 :     gel(W, c++) = flag ? mkvec2(x, gmael(V, i, 2)): x;
    3329             :   }
    3330         273 :   setlg(W, c); return W;
    3331             : }
    3332             : 
    3333             : /* assume 1 <= t < 1000, 1 <= 2s <= n < 100 */
    3334             : static GEN
    3335         273 : nflistfile(const char *suf, long n, long t, long s, long u)
    3336             : {
    3337             :   pariFILE *F;
    3338             :   GEN z;
    3339         273 :   char *f = stack_sprintf("%s/nflistdata/%ld/%ld/%ld%s/%ld",
    3340             :                           pari_datadir, n, t, s, suf, u);
    3341         273 :   F = pari_fopengz(f);
    3342         273 :   if (!F) pari_err_FILE("nflistdata file",f);
    3343         273 :   z = gp_readvec_stream(F->file); pari_fclose(F); return z;
    3344             : }
    3345             : 
    3346             : static GEN
    3347         273 : A5file(const char *suf, long s, long u) { return nflistfile(suf, 5, 4, s, u); }
    3348             : 
    3349             : /* If flag = 0 return only the T's. */
    3350             : static GEN
    3351         273 : vecsliceA5all(const char *suf, long s, ulong sl, GEN Xinf, GEN X, long flag)
    3352             : {
    3353             :   long i, l;
    3354             :   GEN V;
    3355         273 :   ulong  uinf = itou(divis(Xinf, sl));
    3356         273 :   ulong  usup = itou(divis(X, sl));
    3357         273 :   l = usup-uinf+2;
    3358         273 :   V = cgetg(l, t_VEC);
    3359         546 :   for (i = 1; i < l; i++)
    3360         273 :     gel(V, i) = vecslicebyX(A5file(suf, s, uinf+i-1), Xinf, X, flag);
    3361         273 :   return shallowconcat1(V);
    3362             : }
    3363             : 
    3364             : static GEN
    3365          14 : vecsliceA5(long s, GEN Xinf, GEN X, long flag)
    3366             : {
    3367          14 :   return vecsliceA5all("", s, 100000, Xinf, X, flag);
    3368             : }
    3369             : 
    3370             : static GEN
    3371           0 : vecsliceA5cond(long s, GEN Xinf, GEN X, long flag)
    3372             : {
    3373           0 :   return vecsliceA5all("cond", s, 100000, Xinf, X, flag);
    3374             : }
    3375             : 
    3376             : static GEN
    3377         154 : A5vec(GEN X, GEN Xinf, long s, long fl)
    3378             : {
    3379             :   GEN L1, L5;
    3380         154 :   const char *suf = fl? "cond": "";
    3381             : 
    3382         154 :   L1 = L5 = NULL;
    3383         154 :   if (s <= 0) L5 = vecsliceA5all(suf, 0, 100000, Xinf, X, fl);
    3384         154 :   if (s)      L1 = vecsliceA5all(suf, 2, 100000, Xinf, X, fl);
    3385         154 :   switch (s)
    3386             :   {
    3387          28 :     case 2: return L1;
    3388          21 :     case 0: return L5;
    3389          91 :     case -1:
    3390          91 :       return shallowconcat(L1, L5);
    3391          14 :     default:
    3392          14 :       return mkvec3(L5, cgetg(1, t_VEC), L1);
    3393             :   }
    3394             : }
    3395             : static GEN
    3396          21 : makeA5_i(GEN N, long s, long fl)
    3397          21 : { return s == 1 ? NULL: A5vec(N, N, s, fl); }
    3398             : static GEN
    3399          14 : makeA5(GEN N, long s)
    3400             : {
    3401             :   GEN rN;
    3402          14 :   if (!Z_issquareall(N, &rN)) return NULL;
    3403          14 :   return makeA5_i(rN, s, 0);
    3404             : }
    3405             : static GEN
    3406           7 : makeA5cond(GEN N, long s) { return makeA5_i(N, s, 1); }
    3407             : 
    3408             : /* D a sorted t_VECSMALL of conductors; return all [T, d] with d = D[i]
    3409             :  * for some i and Gal(T) = A5 with s complex places */
    3410             : GEN
    3411           0 : veccond_to_A5(GEN D, long s)
    3412             : {
    3413           0 :   pari_sp av = avma;
    3414           0 :   long l, j, lD = lg(D), c = 1;
    3415           0 :   GEN W, V = vecsliceA5cond(s, utoi(D[1]), utoi(D[lD-1]), 1);
    3416           0 :   l = lg(V);
    3417           0 :   W = cgetg(lD, t_VEC);
    3418           0 :   for (j = 1; j < lD; j++)
    3419             :   {
    3420           0 :     GEN Xinf = utoi(D[j]);
    3421           0 :     long i = gen_search(V, mkvec2(NULL, Xinf), NULL, &cmp2);
    3422           0 :     if (i > 0) /* found in list, rewind to first occurence */
    3423             :     {
    3424             :       long ii;
    3425           0 :       while (i > 1 && equalii(gmael(V, i-1, 2), Xinf)) i--;
    3426           0 :       for (ii = i; ii < l && equaliu(gmael(V,ii,2),D[j]); ii++);
    3427           0 :       gel(W, c++) = vecslice(V, i, ii-1);
    3428             :     }
    3429             :   }
    3430           0 :   setlg(W, c); return gc_GEN(av, shallowconcat1(W));
    3431             : }
    3432             : 
    3433             : /* Sextic resolvent of A5 field */
    3434             : static GEN
    3435        4221 : makeA5resolvent(GEN pol, long flag)
    3436             : {
    3437        4221 :   GEN R = cgetg(9, t_POL), D = ZX_disc(pol), c, d, e, f, v;
    3438             :   GEN c2, d2, e2, c4, df;
    3439        4221 :   pol = RgX_Rg_translate(pol, gdivgs(gel(pol, 6), -5));
    3440        4221 :   c = gdivgu(gel(pol, 5), 10);
    3441        4221 :   d = gdivgu(gel(pol, 4), 10);
    3442        4221 :   e = gdivgu(gel(pol, 3), 5);
    3443        4221 :   f = gel(pol, 2);
    3444        4221 :   c2 = gsqr(c); c4 = gsqr(c2); d2 = gsqr(d); e2 = gsqr(e);
    3445        4221 :   df = gmul(d, f);
    3446        4221 :   R[1] = evalsigne(1)|evalvarn(0);
    3447        4221 :   gel(R, 8) = gen_1;
    3448        4221 :   gel(R, 7) = gen_0;
    3449        4221 :   gel(R, 6) = gmulsg(-25, gadd(e, gmulsg(3, c2)));
    3450        4221 :   gel(R, 5) = gen_0;
    3451             : 
    3452        4221 :   v = cgetg(6, t_VEC);
    3453        4221 :   gel(v, 1) = gmulsg(15, c4);
    3454        4221 :   gel(v, 2) = gmulsg(8, gmul(c, d2));
    3455        4221 :   gel(v, 3) = gmulsg(-2, gmul(c2, e));
    3456        4221 :   gel(v, 4) = gmulsg(3, e2);
    3457        4221 :   gel(v, 5) = gmulsg(-2, df);
    3458        4221 :   gel(R, 4) = gmulsg(125, vecsum(v));
    3459        4221 :   gel(R, 3) = sqrti(D);
    3460             : 
    3461        4221 :   v = cgetg(11, t_VEC);
    3462        4221 :   gel(v, 1) = gmulsg(-25, gmul(c2, c4));
    3463        4221 :   gel(v, 2) = gmulsg(-40, gmul(gmul(c, c2), d2));
    3464        4221 :   gel(v, 3) = gmulsg(-16, gsqr(d2));
    3465        4221 :   gel(v, 4) = gmulsg(35, gmul(c4, e));
    3466        4221 :   gel(v, 5) = gmulsg(28, gmul(c, gmul(d2, e)));
    3467        4221 :   gel(v, 6) = gmulsg(-11, gsqr(gmul(c, e)));
    3468        4221 :   gel(v, 7) = gmul(e, e2);
    3469        4221 :   gel(v, 8) = gmulsg(-2, gmul(c2, df));
    3470        4221 :   gel(v, 9) = gmulsg(-2, gmul(e, df));
    3471        4221 :   gel(v, 10) = gmul(c, gsqr(f));
    3472        4221 :   gel(R, 2) = gmulsg(625, vecsum(v));
    3473        4221 :   R = polredabs(R);
    3474        4221 :   return odd(flag)? mkvec2(R, gen_1): R;
    3475             : }
    3476             : 
    3477             : /* For now field ignored. */
    3478             : static GEN
    3479         133 : makeA5vec_i(GEN X, GEN Xinf, GEN field, long s, long fl)
    3480             : {
    3481         133 :   (void)field; if (s == 1) return NULL;
    3482         133 :   return A5vec(X, Xinf, s, fl);
    3483             : }
    3484             : 
    3485             : static GEN
    3486          98 : makeA5vec(GEN X, GEN Xinf, GEN field, long s)
    3487             : {
    3488          98 :   GEN rX = sqrti(X), sXinf, rXinf = sqrtremi(Xinf, &sXinf);
    3489          98 :   if (signe(sXinf)) rXinf = addiu(rXinf, 1);
    3490          98 :   return makeA5vec_i(rX, rXinf, field, s, 0);
    3491             : }
    3492             : 
    3493             : static GEN
    3494          35 : makeA5condvec(GEN X, GEN Xinf, GEN field, long s)
    3495          35 : { return makeA5vec_i(X, Xinf, field, s, 1); }
    3496             : 
    3497             : static GEN
    3498          63 : makeA56vec_i(GEN V, GEN X, GEN Xinf)
    3499             : {
    3500          63 :   long l = lg(V), i, c;
    3501          63 :   GEN W = cgetg(l, t_VEC);
    3502        4263 :   for (i = c = 1; i < l; i++)
    3503             :   {
    3504        4200 :     GEN pol = makeA5resolvent(gel(V, i), 0), D = nfdisc(pol);
    3505        4200 :     if (cmpii(D, X) <= 0 && cmpii(D, Xinf) >= 0) gel(W, c++) = pol;
    3506             :   }
    3507          63 :   setlg(W, c); return W;
    3508             : }
    3509             : 
    3510             : static GEN
    3511          56 : makeA56vec(GEN X, GEN Xinf, long s)
    3512             : {
    3513             :   GEN v;
    3514          56 :   if (s == 1 || s == 3 || !(v = makeA5vec(X, Xinf, NULL, s))) return NULL;
    3515          56 :   if (s != -2) return makeA56vec_i(v, X, Xinf);
    3516           7 :   return mkvec3(makeA56vec_i(gel(v, 1), X, Xinf), cgetg(1, t_VEC),
    3517           7 :                 makeA56vec_i(gel(v, 3), X, Xinf));
    3518             : }
    3519             : static GEN
    3520           7 : makeA56(GEN N, long s) { return makeA56vec(N, N, s); }
    3521             : 
    3522             : /* Stupid for now */
    3523             : static GEN
    3524           7 : makeA56resolvent(GEN pol, long flag)
    3525             : {
    3526           7 :   GEN D6 = sqrti(nfdisc(pol)), LD = divisors(D6);
    3527             :   long i, s;
    3528           7 :   pol = polredabs(pol);
    3529           7 :   s = pol2s(pol)? 2: 0;
    3530          56 :   for (i = 1; i < lg(LD); i++)
    3531             :   {
    3532          56 :     GEN D5 = gel(LD,i);
    3533          56 :     if (dvdii(sqri(D5), D6))
    3534             :     {
    3535          14 :       GEN L = vecsliceA5(s, D5, D5, 0);
    3536             :       long j;
    3537          21 :       for (j = 1; j < lg(L); j++)
    3538             :       {
    3539          14 :         GEN P = gel(L, j);
    3540          14 :         if (ZX_equal(makeA5resolvent(P, 0), pol))
    3541           7 :           return odd(flag)? mkvec2(P, gen_1): P;
    3542             :       }
    3543             :     }
    3544             :   }
    3545           0 :   pari_err_BUG("nfresolvent [A56 resolvent not found]");
    3546             :   return NULL; /* LCOV_EXCL_LINE */
    3547             : }
    3548             : 
    3549             : /**********************************************************************/
    3550             : /*                                 C6                                 */
    3551             : /**********************************************************************/
    3552             : 
    3553             : static GEN
    3554        8497 : makepol6(GEN P3, GEN P2) { return polcompositum0(P3, P2, 2); }
    3555             : static GEN
    3556          28 : makepol6abs(GEN P3, GEN P2) { return polredabs(makepol6(P3, P2)); }
    3557             : 
    3558             : static GEN
    3559         105 : makeC6(GEN N, GEN field, long s)
    3560             : {
    3561         105 :   GEN R, D, d3 = NULL;
    3562             :   long i, j, lD, s2, c;
    3563             : 
    3564         105 :   if (s == 1 || s == 2) return NULL;
    3565          77 :   if (!field) D = divisorsabsdisc(cored(N, 3), s);
    3566          14 :   else if (degpol(field) == 2)
    3567             :   {
    3568           7 :     GEN D2 = nfdisc(field);
    3569           7 :     long si = signe(D2);
    3570           7 :     if ((s == 3 && si > 0) || (s == 0 && si < 0)
    3571           7 :         || !divissquare(N, powiu(D2,3))) return NULL;
    3572           7 :     D = mkvec(absi_shallow(D2));
    3573             :   }
    3574             :   else
    3575             :   {
    3576           7 :     GEN q, D3 = checkfield(field, 3);
    3577           7 :     if (!Z_issquareall(D3, &d3)) pari_err_TYPE("makeC6 [field]", field);
    3578           7 :     if (!(q = divide(N, sqri(D3)))) return NULL;
    3579           7 :     D = divisorsabsdisc(cored(gcdii(N, powiu(q,3)), 3), s);
    3580             :   }
    3581          77 :   s2 = maxss(s, -1); if (s2 == 3) s2 = 1;
    3582          77 :   lD = lg(D); R = cgetg(lD, t_VEC);
    3583         161 :   for (i = c = 1; i < lD; i++)
    3584             :   {
    3585          84 :     GEN F, L, V2, R0, D2a = gel(D, i), M = diviiexact(N, powiu(D2a, 3));
    3586             :     long l, l2;
    3587          84 :     if (!Z_issquareall(M, &F)) continue;
    3588          35 :     if (d3) { L = mkvec(mkvec(field)); l = 2; }
    3589             :     else
    3590             :     {
    3591             :       long k;
    3592          28 :       L = divisors(cored(mulii(F, D2a), 2)); l = lg(L);
    3593         112 :       for (j = k = 1; j < l; j ++)
    3594             :       {
    3595          84 :         GEN C = makeC3_f(gel(L, j));
    3596          84 :         if (lg(C) > 1) gel(L, k++) = C;
    3597             :       }
    3598          28 :       setlg(L, k); l = k; if (l == 1) continue;
    3599             :     }
    3600          35 :     V2 = makeC2(D2a, NULL, s2); l2 = lg(V2);
    3601          35 :     R0 = cgetg(l, t_VEC);
    3602          70 :     for (j = 1; j < l; j++)
    3603             :     {
    3604          35 :       GEN R3, C3 = gel(L, j);
    3605          35 :       long i2, c3, i3, l3 = lg(C3);
    3606             : 
    3607          35 :       R3 = cgetg(l2 * l3, t_VEC);
    3608          70 :       for (i3 = c3 = 1; i3 < l3; i3++)
    3609             :       {
    3610          35 :         GEN P3 = gel(C3, i3);
    3611          91 :         for (i2 = 1; i2 < l2; i2++)
    3612             :         {
    3613          56 :           GEN P6 = makepol6(P3, gel(V2, i2));
    3614          56 :           if (absequalii(nfdisc(P6), N)) gel(R3, c3++) = P6;
    3615             :         }
    3616             :       }
    3617          35 :       setlg(R3, c3); gel(R0, j) = R3;
    3618             :     }
    3619          35 :     gel(R, c++) = shallowconcat1(R0);
    3620             :   }
    3621          77 :   setlg(R,c); return sturmseparate(myshallowconcat1(R), s, 6);
    3622             : }
    3623             : 
    3624             : static GEN
    3625          28 : makeC6resolvent(GEN pol, long flag)
    3626             : {
    3627          28 :   GEN V, R3, R = mynfsubfield(pol, 2);
    3628          28 :   R3 = (flag >= 2)? mynfsubfield(pol, 3): NULL;
    3629          28 :   switch (flag)
    3630             :   {
    3631           7 :     case 0: V = R; break;
    3632           7 :     case 1: V = condrel_i(R, pol); break;
    3633           7 :     case 2: V = mkvec2(R, R3); break;
    3634           7 :     default:V = mkvec2(condrel_i(R, pol), condrel_i(R3, pol)); break;
    3635             :   }
    3636          28 :   return V;
    3637             : }
    3638             : 
    3639             : /* assume the odd part of M is squarefree, disc is OK */
    3640             : static void
    3641        8698 : C6fill(long M, GEN P3, long s, GEN vp,GEN vm)
    3642             : {
    3643             :   int p, m;
    3644        8698 :   uis_fundamental_pm_i(M, s, &p, &m, 1);
    3645        8698 :   if (p) vectrunc_append(vp, makepol6(P3, X2p(utoineg(M))));
    3646        8700 :   if (m) vectrunc_append(vm, makepol6(P3, X2p(utoipos(M))));
    3647        8699 : }
    3648             : 
    3649             : GEN
    3650         868 : nflist_C6_worker(GEN P3, GEN X, GEN Xinf, GEN M, GEN T)
    3651             : {
    3652         868 :   pari_sp av = avma;
    3653             :   GEN D3, f, D32, vp, vm, G, Ginf;
    3654         868 :   long i, limD2, l = lg(M), s = T[1];
    3655             : 
    3656         868 :   if (typ(P3)==t_VEC) { f = gel(P3,2); P3 = gel(P3,1);  } else f = C3pol_f(P3);
    3657         868 :   D3 = sqri(f); D32 = sqri(D3); G = divii(X, D32); Ginf = ceildiv(Xinf, D32);
    3658         868 :   limD2 = cmpiu(G, T[2]) < 0 ? itou(G) : T[2];
    3659             : 
    3660             :   /* D3 = f^2 is odd, gcd(M,D3) = gcd(M,f); disc = D3^2 / (D3,M)^2 * M^3 */
    3661         868 :   vp = vectrunc_init(limD2);
    3662         868 :   vm = vectrunc_init(limD2);
    3663      247618 :   for (i = 1; i < l; i++)
    3664             :   {
    3665      247415 :     long m = M[i];
    3666             :     GEN g;
    3667      247415 :     if (!odd(m)) continue;
    3668      164835 :     if (m > limD2) break;
    3669      164163 :     g = muliu(sqru(m / ugcdiu(f, m)), m);
    3670      164457 :     if (m != 1 && ok_int(g, G, Ginf)) C6fill(m, P3, s, vp, vm);
    3671      164381 :     if ((m << 2) <= limD2 && ok_int(shifti(g,6), G, Ginf))
    3672        1701 :       C6fill(m << 2, P3, s, vp, vm);
    3673      164380 :     if ((m << 3) <= limD2 && ok_int(shifti(g,9), G, Ginf))
    3674         742 :       C6fill(m << 3, P3, s, vp, vm);
    3675             :   }
    3676         875 :   return gc_GEN(av, mkvec2(vp, vm));
    3677             : }
    3678             : 
    3679             : static GEN
    3680          91 : makeC6vec(GEN X, GEN Xinf, GEN field, long s)
    3681             : {
    3682             :   GEN T, v, M;
    3683             : 
    3684          91 :   if (s == 1 || s == 2) return NULL;
    3685          63 :   if (field)
    3686             :   {
    3687             :     GEN D, f;
    3688          21 :     if (degpol(field) == 2)
    3689             :     {
    3690             :       long si, m, i, c, l;
    3691             :       GEN F;
    3692          14 :       D = nfdisc(field); si = signe(D);
    3693          14 :       if (cmpii(powiu(D, 3), X) > 0 || (s == 3 && si > 0)
    3694          14 :           || (s == 0 && si < 0)) return NULL;
    3695          14 :       m = itou(D); v = C3vec_F(floorsqrtdiv(X,D), 1, &F); l = lg(v);
    3696       78358 :       for (i = c = 1; i < l; i++)
    3697             :       {
    3698       78344 :         long f = F[i]; /* conductor */
    3699       78344 :         GEN g = muliu(sqru(m / ugcd(f, m)), m);
    3700       78344 :         if (ok_int(mulii(powuu(f, 4), g), X, Xinf))
    3701         140 :           gel(v, c++) = makepol6(gtopoly(gel(v,i), 0), field);
    3702             :       }
    3703          14 :       setlg(v, c);
    3704          14 :       if (s == -2) v = si > 0? vecs14(v, cgetg(1,t_VEC)): vecs(4, v);
    3705          14 :       return v;
    3706             :     }
    3707           7 :     D = checkfield(field, 3);
    3708           7 :     if (!Z_issquareall(D, &f)) pari_err_TYPE("makeC6 [field]", field);
    3709           7 :     if (cmpii(sqri(D), X) > 0) return NULL;
    3710           7 :     v = mkvec(mkvec2(field, f));
    3711             :   }
    3712          42 :   else if (!(v = makeC3vec(sqrti(divis(X, 3)), gen_1, NULL, 0))) return NULL;
    3713          49 :   T = mkvecsmall2(s, floorsqrtn(X, 3));
    3714          49 :   M = vecsquarefreeu(1, T[2]);
    3715          49 :   v = nflist_parapply("_nflist_C6_worker", mkvec4(X, Xinf, M, T), v);
    3716          49 :   switch (s)
    3717             :   {
    3718          14 :     case -1: return shallowconcat(Sextract(v,1), Sextract(v,2));
    3719           7 :     case -2: return vecs14(Sextract(v,1), Sextract(v,2)); /* -2 */
    3720          28 :     default: return Sextract(v, s? 2: 1);
    3721             :   }
    3722             : }
    3723             : 
    3724             : /**********************************************************************/
    3725             : /*                             S36 = D66                              */
    3726             : /**********************************************************************/
    3727             : static GEN
    3728          63 : makeS36(GEN N, GEN field, long s)
    3729             : {
    3730             :   GEN vD, P, vp, vm;
    3731             :   long i, l, cp, cm;
    3732          63 :   if (s == 1 || s == 2) return NULL;
    3733          49 :   if (s == 3) s = 1;
    3734          49 :   if (field)
    3735             :   {
    3736          21 :     long sf = s != -1? pol2s(field): 0/*dummy*/;
    3737          21 :     if (s >= 0 && s != sf) return NULL;
    3738          21 :     if (degpol(field) == 3)
    3739             :     {
    3740           7 :       GEN d, D = nfcoredisc(field, &d);
    3741           7 :       if (!absequalii(mulii(sqri(D), d), N)) return NULL;
    3742           7 :       P = mkvec(makepol6abs(field, X2m(d)));
    3743           7 :       if (s == -2) { P = vecs(4, P); if (sf) swap(gel(P,1), gel(P,4)); }
    3744           7 :       return P;
    3745             :     }
    3746             :     else
    3747             :     {
    3748          14 :       GEN D2 = checkfield(field, 2);
    3749          14 :       if (!divispowerall(N,  powiu(absi_shallow(D2),3), 4, NULL)) return NULL;
    3750          14 :       vD = mkvec(D2);
    3751             :     }
    3752             :   }
    3753          28 :   else vD = divisorsdisc(cored(N, 3), s);
    3754          42 :   l = lg(vD);
    3755          42 :   vp = cgetg(l, t_VEC);
    3756          42 :   vm = cgetg(l, t_VEC);
    3757          77 :   for (i = cp = cm = 1; i < l; i++)
    3758             :   {
    3759          35 :     GEN F, w, P2, D = gel(vD, i), Da = absi_shallow(D);
    3760          35 :     long lw, j, s2 = signe(D) > 0? 0: 1;
    3761          35 :     if (!Z_ispowerall(divii(N, powiu(Da, 3)), 4, &F)) continue;
    3762          21 :     P2 = X2m(D); if (!(w = makeDL(3, mulii(Da, sqri(F)), P2, s2))) continue;
    3763          21 :     lw = lg(w);
    3764          42 :     for (j = 1; j < lw; j++) gel(w, j) = makepol6abs(gel(w, j), P2);
    3765          21 :     if (signe(D) < 0) gel(vm, cm++) = w; else gel(vp, cp++) = w;
    3766             :   }
    3767          42 :   setlg(vp, cp); vp = myshallowconcat1(vp);
    3768          42 :   setlg(vm, cm); vm = myshallowconcat1(vm);
    3769          42 :   return s == -2? vecs14(vp, vm): shallowconcat(vp, vm);
    3770             : }
    3771             : 
    3772             : static GEN
    3773          21 : makeS36resolvent(GEN pol, long flag)
    3774             : {
    3775          21 :   GEN R2, V, S = mynfsubfields(pol, 3);
    3776          21 :   if (flag < 2) return condrel(gel(S,1), pol, flag);
    3777          14 :   R2 = mynfsubfield(pol, 2);
    3778          14 :   if (flag == 2)
    3779           7 :     V = vec_append(S, R2);
    3780             :   else
    3781          14 :     V = mkvec4(condrel_i(gel(S,1), pol), condrel_i(gel(S,2), pol),
    3782           7 :                condrel_i(gel(S,3), pol), condrel_i(R2, pol));
    3783          14 :   return V;
    3784             : }
    3785             : 
    3786             : GEN
    3787       14726 : nflist_S36_worker(GEN pol, GEN X, GEN Xinf)
    3788             : {
    3789       14726 :   GEN d, D = nfcoredisc(pol, &d);
    3790       14724 :   if (ok_int(mulii(sqri(D), d), X, Xinf)) return makepol6(pol, X2m(d));
    3791       13226 :   return gen_0;
    3792             : }
    3793             : 
    3794             : static GEN
    3795          35 : parselectS36(GEN v, GEN X, GEN Xinf)
    3796             : {
    3797          35 :   GEN w = nflist_parapply("_nflist_S36_worker", mkvec2(X, Xinf), v);
    3798          35 :   long l = lg(w), i, c;
    3799             : 
    3800       14770 :   for (i = c = 1; i < l; i++)
    3801             :   {
    3802       14735 :     GEN t = gel(w, i);
    3803       14735 :     if (typ(t) == t_POL) gel(w, c++) = t;
    3804             :   }
    3805          35 :   setlg(w, c); return w;
    3806             : }
    3807             : 
    3808             : static GEN
    3809          49 : makeS36vec(GEN X, GEN Xinf, GEN field, long s)
    3810             : {
    3811             :   GEN v;
    3812             : 
    3813          49 :   if (s == 1 || s == 2) return NULL;
    3814          35 :   if (s == 3) s = 1;
    3815          35 :   if (field)
    3816             :   {
    3817          14 :     if (degpol(field) == 3)
    3818             :     {
    3819           7 :       GEN d, D = nfcoredisc(field,&d);
    3820           7 :       long ss = signe(D) < 0? 1: 0;
    3821           7 :       if (s >= 0 && s != ss) return NULL;
    3822           7 :       if (abscmpii(mulii(sqri(D), d), X) > 0) return NULL;
    3823           7 :       v = mkvec(field);
    3824             :     }
    3825             :     else
    3826             :     {
    3827           7 :       GEN D2a = absi_shallow(checkfield(field, 2)), D2a3 = powiu(D2a, 3), RES;
    3828             :       long Fsup, Finf, F, c;
    3829           7 :       if ((s >= 0 && s != pol2s(field)) || cmpii(D2a3, X) > 0) return NULL;
    3830           7 :       Fsup = floorsqrtndiv(X, D2a3, 4);
    3831           7 :       Finf = ceilsqrtndiv(Xinf, D2a3, 4);
    3832           7 :       RES = cgetg(Fsup + 1, t_VEC);
    3833          14 :       for (F = Finf, c = 1; F <= Fsup; F++)
    3834             :       {
    3835           7 :         pari_sp av = avma;
    3836           7 :         GEN w, N = mulii(powuu(F, 4), D2a3);
    3837           7 :         if (!(w = makeS36(N, field, s))) set_avma(av);
    3838           7 :         else gel(RES, c++) = gc_GEN(av, w);
    3839             :       }
    3840           7 :       setlg(RES,c); return myshallowconcat1(RES);
    3841             :     }
    3842             :   }
    3843             :   else
    3844          21 :     if (!(v = makeS3vec(sqrti(divis(X, 3)), gen_1, NULL, s))) return NULL;
    3845          28 :   if (s != -2) return parselectS36(v, X, Xinf);
    3846           7 :   return mkvec4(parselectS36(gel(v,1), X, Xinf), cgetg(1, t_VEC),
    3847           7 :                 cgetg(1, t_VEC), parselectS36(gel(v,2), X, Xinf));
    3848             : }
    3849             : /**********************************************************************/
    3850             : /*                              D612                                  */
    3851             : /**********************************************************************/
    3852             : static void
    3853          91 : gets2s3(long s, long *s2, long *s3)
    3854             : {
    3855          91 :   switch (s)
    3856             :   {
    3857          14 :     case 0: *s2 = *s3 = 0; break;
    3858          14 :     case 2: *s2 = 0; *s3 = 1; break;
    3859           7 :     case 3: *s2 = 1; *s3 = -1; break;
    3860          56 :     default: *s2 = *s3 = -1; break;
    3861             :   }
    3862          91 : }
    3863             : 
    3864             : static GEN makeD612vec(GEN X, GEN Xinf, GEN field, long s);
    3865             : static GEN
    3866          56 : makeD612(GEN N, GEN field, long s)
    3867             : {
    3868             :   long i, j, l, c3, s2, s3;
    3869             :   GEN v;
    3870             : 
    3871          56 :   if (s == 1) return NULL;
    3872          49 :   gets2s3(s, &s2, &s3);
    3873          49 :   if (field)
    3874             :   {
    3875             :     GEN D2;
    3876             :     long si;
    3877           7 :     if (degpol(field) == 3) return makeD612vec(N,N,field,s);
    3878           7 :     D2 = checkfield(field, 2); si = signe(D2);
    3879           7 :     if ((si == 1 && s2 > 0) || (si == -1 && !s2)
    3880           7 :         || !divissquare(N, powiu(D2,3))) return NULL;
    3881           7 :     v = mkvec(D2);
    3882             :   }
    3883          42 :   else v = divisorsdisc(cored(N, 3), s2);
    3884          49 :   l = lg(v);
    3885          84 :   for (i = c3 = 1; i < l; i++)
    3886             :   {
    3887          35 :     GEN D2 = gel(v, i), D2a = absi_shallow(D2), M = divii(N, powiu(D2a, 3));
    3888          35 :     GEN P2, F = gel(core2(M), 2), L = divisors(mulii(F, D2a));
    3889          35 :     long c2, lL = lg(L);
    3890          35 :     if (lL == 1) continue;
    3891          35 :     P2 = quadpoly_i(D2);
    3892         343 :     for (j = c2 = 1; j < lL; j++)
    3893             :     {
    3894         308 :       GEN w, D3 = gel(L, j);
    3895             :       long k, c, lw;
    3896         308 :       if (Mod4(D3) == 2 || !dvdii(F, divii(D3, gcdii(D2a, D3)))
    3897         308 :           || !(w = makeDL(3, D3, NULL, s3))) continue;
    3898          21 :       lw = lg(w);
    3899          42 :       for (k = c = 1; k < lw; k++)
    3900             :       {
    3901          21 :         GEN P3 = gel(w, k), P6, d;
    3902          21 :         (void)nfcoredisc(P3, &d); if (equalii(d, D2)) continue;
    3903          21 :         if ((P6 = ZX_red_disc(makepol6(P3, P2), N))) gel(w, c++) = P6;
    3904             :       }
    3905          21 :       if (c > 1) { setlg(w, c); gel(L, c2++) = w; }
    3906             :     }
    3907          35 :     if (c2 > 1) { setlg(L, c2); gel(v, c3++) = shallowconcat1(L); }
    3908             :   }
    3909          49 :   setlg(v, c3); return sturmseparate(myshallowconcat1(v), s, 6);
    3910             : }
    3911             : 
    3912             : static GEN
    3913          14 : makeD612resolvent(GEN pol, long flag)
    3914             : {
    3915          14 :   GEN R3, R = mynfsubfield(pol, 2);
    3916          14 :   if (flag < 2) return condrel(R, pol, flag);
    3917           7 :   R3 = mynfsubfield(pol, 3);
    3918           7 :   if (flag == 3) { R = condrel_i(R, pol); R3 = condrel_i(R3, pol); }
    3919           7 :   return mkvec2(R, R3);
    3920             : }
    3921             : 
    3922             : GEN
    3923         783 : nflist_D612_worker(GEN P3, GEN X, GEN Xinf, GEN limd2s2)
    3924             : {
    3925         783 :   pari_sp av = avma;
    3926         783 :   GEN v, D2, D3 = nfcoredisc(P3, &D2), D32 = sqri(D3), Q = divii(X, D32);
    3927         784 :   long limD2 = limd2s2[1], s2 = limd2s2[2];
    3928         784 :   long c, M, limD = cmpis(Q, limD2) < 0 ? itos(Q) : limD2;
    3929         784 :   v = cgetg(2 * limD + 1, t_VEC);
    3930        6027 :   for (M = 3, c = 1; M <= limD; M++)
    3931             :   {
    3932        5241 :     GEN N, LD = cgetg(1, t_VEC);
    3933             :     long g, i;
    3934             :     int p, m;
    3935        5243 :     uis_fundamental_pm(M, s2, &p, &m);
    3936        5243 :     if (absequaliu(D2, M))
    3937          91 :     { if (signe(D2) > 0) p = 0; else m = 0; }
    3938        5243 :     if (!(LD = ufund_pm(M, p, m))) continue;
    3939        2394 :     g = ugcdiu(D3, M);
    3940        2394 :     N = mulii(D32, muliu(sqru(M/g), M));
    3941        2394 :     if (cmpii(N, X) <= 0 && cmpii(shifti(N, 2), Xinf) >= 0)
    3942             :     {
    3943         336 :       long l = lg(LD);
    3944         686 :       for (i = 1; i < l; i++)
    3945             :       {
    3946         350 :         GEN P = makepol6(P3, X2m(gel(LD,i)));
    3947         350 :         if (odd(g)) gel(v, c++) = polredabs(P);
    3948         182 :         else if ((P = ZX_red_disc2(P, Xinf, X))) gel(v, c++) = P;
    3949             :       }
    3950             :     }
    3951             :   }
    3952         786 :   setlg(v, c); return gc_GEN(av, v);
    3953             : }
    3954             : 
    3955             : static GEN
    3956          49 : makeD612vec(GEN X, GEN Xinf, GEN field, long s)
    3957             : {
    3958             :   GEN v, T;
    3959             :   long s2, s3;
    3960             : 
    3961          49 :   if (s == 1) return NULL;
    3962          42 :   v = NULL; gets2s3(s, &s2, &s3);
    3963          42 :   if (field)
    3964             :   {
    3965          14 :     if (degpol(field) == 3)
    3966             :     {
    3967           7 :       GEN D3 = nfdisc(field);
    3968           7 :       long si = signe(D3);
    3969           7 :       if ((si > 0 && s2 > 0) || (si < 0 && !s2)
    3970           7 :           || cmpii(sqri(D3), X) > 0) return NULL;
    3971           7 :       v = mkvec(field);
    3972             :     }
    3973             :     else
    3974             :     {
    3975           7 :       GEN D2a = absi_shallow(checkfield(field, 2));
    3976             :       long l, j, c;
    3977           7 :       if (!(v = makeS3vec(sqrti(divii(X, D2a)), gen_1, NULL, s3))) return NULL;
    3978           7 :       l = lg(v);
    3979         105 :       for (j = c = 1; j < l; j++)
    3980             :       {
    3981          98 :         GEN P = makepol6(gel(v, j), field);
    3982          98 :         if ((P = ZX_red_disc2(P, Xinf, X))) gel(v, c++) = P;
    3983             :       }
    3984           7 :       setlg(v, c); return sturmseparate(v, s, 6);
    3985             :     }
    3986             :   }
    3987          28 :   else if (!(v = makeS3vec(sqrti(X), gen_1, NULL, s3))) return NULL;
    3988          35 :   T = mkvecsmall2(floorsqrtn(X, 3), s2);
    3989          35 :   v = nflist_parapply("_nflist_D612_worker", mkvec3(X, Xinf, T), v);
    3990          35 :   return sturmseparate(myshallowconcat1(v), s, 6);
    3991             : }
    3992             : 
    3993             : /**********************************************************************/
    3994             : /*                          A46 and S46P                              */
    3995             : /**********************************************************************/
    3996             : 
    3997             : /* A46, S46P, in place */
    3998             : static GEN
    3999         343 : makeS46Ppols(long card, GEN v)
    4000             : {
    4001         343 :   long l = lg(v), i;
    4002         343 :   GEN d = utoipos(card);
    4003         686 :   for (i = 1; i < l; i++)
    4004             :   {
    4005         343 :     GEN G = galoissplittinginit(gel(v,i), d), g = gal_get_gen(G);
    4006         343 :     GEN p = (card == 12)? gel(g, 1): mkvec2(gel(g, 1), gel(g, 4));
    4007         343 :     gel(v,i) = polredabs(galoisfixedfield(G, p, 1, 0));
    4008             :   }
    4009         343 :   return v;
    4010             : }
    4011             : /* S46M, in place */
    4012             : static GEN
    4013         637 : makeS46Mpols(GEN v, GEN X, GEN Xinf)
    4014             : {
    4015         637 :   long l = lg(v), i, c;
    4016         637 :   GEN d = utoipos(24);
    4017         868 :   for (i = c = 1; i < l; i++)
    4018             :   {
    4019         231 :     GEN G = galoissplittinginit(gel(v,i), d), g = gal_get_gen(G);
    4020         231 :     GEN p = perm_mul(gel(g, 4), gel(g, 2));
    4021         231 :     p = galoisfixedfield(G, p, 1, 0);
    4022         231 :     p = Xinf? ZX_red_disc2(p, Xinf, X): ZX_red_disc(p, X);
    4023         231 :     if (p) gel(v, c++) = p;
    4024             :   }
    4025         637 :   setlg(v, c); return v;
    4026             : }
    4027             : 
    4028             : static GEN
    4029          49 : makeA46(GEN N, GEN field, long s)
    4030             : {
    4031             :   GEN n, v, D;
    4032             :   long i, l, c;
    4033             : 
    4034          49 :   if (s== 1 || s==3 || !Z_issquareall(N, &n)) return NULL;
    4035          42 :   if (field)
    4036             :   {
    4037           7 :     GEN t, q, D = checkfield(field, 3);
    4038           7 :     if (!Z_issquare(D)
    4039           7 :         || !(q = divide(n, D)) || !(t = makeA4S4(field, q, s))) return NULL;
    4040           7 :     return makeS46Ppols(12, t);
    4041             :   }
    4042          35 :   D = divisors(gel(core2(n), 2));
    4043          35 :   l = lg(D); v = cgetg(l, t_VEC);
    4044          56 :   for (i = 2, c = 1; i < l; i++)
    4045             :   {
    4046          21 :     GEN t, q, g3 = gel(D,i), C = makeC3_f(g3);
    4047          21 :     long j, l = lg(C);
    4048          21 :     if (l == 1) continue;
    4049           7 :     q = diviiexact(n, sqri(g3));
    4050          14 :     for (j = 1; j < l; j++)
    4051           7 :       if ((t = makeA4S4(gel(C,j), q, s))) gel(v, c++) = makeS46Ppols(12,t);
    4052             :   }
    4053          35 :   setlg(v,c); return sturmseparate(myshallowconcat1(v), s, 6);
    4054             : }
    4055             : 
    4056             : static GEN
    4057          49 : makeS46P(GEN N, GEN field, long s)
    4058             : {
    4059             :   GEN n, v, D;
    4060             :   long i, snew, l, c;
    4061             : 
    4062          49 :   if (s==1 || s==3 || !Z_issquareall(N, &n)) return NULL;
    4063             :   /* s = -2, -1, 0, 2 */
    4064          42 :   if (field)
    4065             :   {
    4066           7 :     GEN D3 = checkfield(field, 3), f, t;
    4067           7 :     if (Z_issquare(D3) || !dvdii(n, D3)) return NULL;
    4068           7 :     snew = s == 2 && signe(D3) < 0 ? 1 : s;
    4069           7 :     f = divii(n, absi_shallow(D3));
    4070           7 :     if (!(t = makeA4S4(field, f, snew))) return NULL;
    4071           7 :     return makeS46Ppols(24, t);
    4072             :   }
    4073          35 :   D = divisors(n); l = lg(D); v = cgetg(l, t_VEC);
    4074          42 :   for (i = 2, c = 1; i < l; i++)
    4075             :   {
    4076           7 :     GEN f, P, D3a = gel(D,i);
    4077             :     long c3, j, lv3;
    4078           7 :     if (!(P =  makeDL(3, D3a, NULL, s? -1: 0))) continue;
    4079           7 :     f = gel(D, l-i); lv3 = lg(P);
    4080          14 :     for (j = c3 = 1; j < lv3; j++)
    4081             :     {
    4082           7 :       GEN T, P3 = gel(P,j);
    4083           7 :       long snew = (s == 2 && signe(ZX_disc(P3)) == -1) ? 1 : s;
    4084           7 :       if ((T = makeA4S4(P3, f, snew))) gel(P,c3++) = T;
    4085             :     }
    4086           7 :     if (c3 == 1) continue;
    4087           7 :     setlg(P, c3); gel(v, c++) = makeS46Ppols(24, shallowconcat1(P));
    4088             :   }
    4089          35 :   setlg(v,c); return sturmseparate(myshallowconcat1(v), s, 6);
    4090             : }
    4091             : 
    4092             : GEN
    4093         881 : nflist_A46S46P_worker(GEN P3, GEN Xinf, GEN sqX, GEN cards)
    4094             : {
    4095         881 :   pari_sp av = avma;
    4096         881 :   long card = cards[1], s = cards[2];
    4097         881 :   GEN w, F, V, DATA = S4data(P3, s), D3 = S4_get_disc(DATA);
    4098         882 :   GEN D3a = absi_shallow(D3);
    4099         882 :   long limf = itos(divii(sqX, D3a)), linf = 1, snew, f, i, c;
    4100             : 
    4101         882 :   if (cmpii(Xinf, sqri(shifti(D3a, 2))) >= 0)
    4102          21 :     linf = ceilsqrtdiv(Xinf, sqri(D3));
    4103         882 :   snew = s == 2 && signe(D3) < 0 ? 1 : s;
    4104         882 :   V = cgetg(limf, t_VEC);
    4105         882 :   F = vecfactoru_i(linf, limf);
    4106        5614 :   for (f = linf, i = c = 1; f <= limf; f++, i++)
    4107        4732 :     if ((w = A4S4_fa(DATA, gel(F,i), f, snew)))
    4108         315 :       gel(V, c++) = makeS46Ppols(card, w);
    4109         882 :   setlg(V,c); V = myshallowconcat1(V);
    4110         882 :   return gc_GEN(av, V);
    4111             : }
    4112             : 
    4113             : static GEN
    4114          91 : makeA46S46Pvec(long card, GEN X, GEN Xinf, GEN field, long s)
    4115             : {
    4116             :   GEN v, sqX, T;
    4117             : 
    4118          91 :   if (s == 1 || s == 3) return NULL;
    4119          63 :   sqX = sqrti(X);
    4120          63 :   if (field)
    4121             :   {
    4122          14 :     GEN D = checkfield(field, 3);
    4123          14 :     long fl = Z_issquare(D);
    4124          14 :     if ((card == 12 && !fl) || (card == 24 && fl)) return  NULL;
    4125          14 :     v = mkvec(field);
    4126             :   }
    4127             :   else
    4128          49 :     v = card == 12? makeC3vec(sqX, gen_1, NULL, 0)
    4129          49 :                   : makeS3vec(sqX, gen_1, NULL, s? -1: 0);
    4130          63 :   if (!v) return NULL;
    4131          63 :   T = mkvec3(Xinf, sqX, mkvecsmall2(card, s == -2? -1: s));
    4132          63 :   v = nflist_parapply("_nflist_A46S46P_worker", T, v);
    4133          63 :   return sturmseparate(myshallowconcat1(v), s, 6);
    4134             : }
    4135             : 
    4136             : /**********************************************************************/
    4137             : /*                              S46M                                  */
    4138             : /**********************************************************************/
    4139             : static GEN
    4140         637 : glco46M(GEN F, GEN D2a)
    4141             : {
    4142         637 :   GEN C, F0, D = divisors(D2a);
    4143         637 :   long k, i, c, l = lg(D), klim = vali(D2a)? minss(2, vali(F)): 0;
    4144             :   /* could restrict divisors to multiples of (D2,F)/2^klim */
    4145             : 
    4146         637 :   F0 = klim? shifti(F, -klim): F;
    4147         637 :   C = cgetg((klim+1) * (l-1) + 1, t_VEC);
    4148        2051 :   for (i = c = 1; i < l; i++)
    4149             :   {
    4150        1414 :     GEN g = gcdii(F, gel(D,l-i));
    4151        1414 :     long v = vali(g);
    4152        1414 :     if (v) g = shifti(g, -v);
    4153        1414 :     if (!is_pm1(g) || v > klim) continue;
    4154             :     /* (F,D[l-i]) = 2^v; if v <= k <= klim, add F*D[i]>>k */
    4155        1400 :     gel(C, c++) = g = mulii(F0, gel(D,i));
    4156        1400 :     for (k = v; k < klim; k++) gel(C, c++) = g = shifti(g, 1);
    4157             :   }
    4158         637 :   setlg(C, c); return C;
    4159             : }
    4160             : 
    4161             : static GEN
    4162         637 : doA4S4(GEN field, GEN C, long s)
    4163             : {
    4164         637 :   long l = lg(C), i, c;
    4165         637 :   GEN w, v = cgetg(l, t_VEC);
    4166        2037 :   for (i = c = 1; i < l; i++)
    4167        1400 :     if ((w = makeA4S4(field, gel(C,i), s))) gel(v, c++) = w;
    4168         637 :   setlg(v,c); return myshallowconcat1(v);
    4169             : }
    4170             : 
    4171             : static GEN
    4172          56 : makeS46M(GEN N, GEN field, long s)
    4173             : {
    4174             :   GEN v, D, LC, F;
    4175             :   long i, c, l, snew;
    4176             : 
    4177          56 :   if (s == 1) return NULL;
    4178          49 :   snew = s == 3 ? 1 : maxss(s, -1);
    4179          49 :   if (field)
    4180             :   {
    4181             :     GEN D3, D2, D2a, t, Dpow;
    4182           7 :     checkfield_i(field, 3); D3 = nfcoredisc(field, &D2); D2a = absi_shallow(D2);
    4183           7 :     Dpow = mulii(D2a, sqri(D3));
    4184           7 :     if ((signe(D3) < 0 && (s == 0 || s == 2))
    4185           7 :         || (signe(D3) > 0 && (s == 3 || Z_issquare(D3)))
    4186           7 :         || !divissquareall(N, Dpow, &F)) return NULL;
    4187           7 :     LC = glco46M(F, D2a);
    4188           7 :     t = doA4S4(field, LC, snew); return makeS46Mpols(t, N, NULL);
    4189             :   }
    4190          42 :   D = divisorsabsdisc(cored(N, 3), snew);
    4191          42 :   l = lg(D); v = cgetg(l*l, t_VEC);
    4192          56 :   for (i = c = 1; i < l; i++)
    4193             :   {
    4194          14 :     GEN D2a = gel(D, i), NSD2 = divii(N, powiu(D2a, 3)), NSD4, F;
    4195             :     long j;
    4196          14 :     if (!Z_issquareall(NSD2, &NSD4)) continue;
    4197          14 :     F = divisors(cored(NSD2, 4));
    4198          35 :     for (j = 1; j < lg(F); j++)
    4199             :     {
    4200          21 :       GEN f2 = sqri(gel(F, j)), P;
    4201             :       long k, lP;
    4202          21 :       if (!(P = makeDL(3, mulii(D2a, f2), NULL, minss(snew, 1)))) continue;
    4203          14 :       lP = lg(P); LC = glco46M(divii(NSD4, f2), D2a);
    4204          28 :       for (k = 1; k < lP; k++) gel(P,k) = doA4S4(gel(P,k), LC, snew);
    4205          14 :       gel(v, c++) = makeS46Mpols(shallowconcat1(P), N, NULL);
    4206             :     }
    4207             :   }
    4208          42 :   if (c == 1) return NULL;
    4209          14 :   setlg(v,c); return sturmseparate(gtoset_shallow(shallowconcat1(v)), s, 6);
    4210             : }
    4211             : 
    4212             : GEN
    4213         252 : nflist_S46M_worker(GEN P3, GEN X, GEN Xinf, GEN gs)
    4214             : {
    4215         252 :   pari_sp av = avma;
    4216         252 :   long s = gs[1], snew = s == 3 ? 1 : s;
    4217         252 :   GEN V, DATA = S4data(P3, s), D3 = S4_get_disc(DATA);
    4218         252 :   GEN D2a = absi_shallow(coredisc(D3));
    4219         252 :   long lim = floorsqrtdiv(X, mulii(sqri(D3), D2a)), f, c;
    4220             : 
    4221         252 :   V = cgetg(lim + 1, t_VEC);;
    4222         868 :   for (f = 1, c = 1; f <= lim; f++)
    4223             :   {
    4224         616 :     GEN C = glco46M(utoipos(f), D2a), t = doA4S4(DATA, C, snew);
    4225         616 :     gel(V, c++) = makeS46Mpols(t, X, Xinf);
    4226             :   }
    4227         252 :   setlg(V,c); V = myshallowconcat1(V);
    4228         252 :   return gc_upto(av, gtoset(V));
    4229             : }
    4230             : 
    4231             : static GEN
    4232          42 : makeS46Mvec(GEN X, GEN Xinf, GEN field, long s)
    4233             : {
    4234             :   GEN v;
    4235             : 
    4236          42 :   if (s == 1) return NULL;
    4237          35 :   if (field)
    4238             :   {
    4239           7 :     GEN D = checkfield(field, 3);
    4240           7 :     if (Z_issquare(D)) return NULL;
    4241           7 :     v = mkvec(field);
    4242             :   }
    4243             :   else
    4244             :   {
    4245          28 :     long s3 = s == 3? 1: (s < 0? -1: 0), l2, i, c;
    4246          28 :     GEN v2 = makeC2vec(sqrtnint(X,3), gen_1, NULL, s3);
    4247          28 :     if (!v2) return NULL;
    4248          28 :     l2 = lg(v2); v = cgetg(l2, t_VEC);
    4249        1092 :     for (i = c = 1; i < l2; i++)
    4250             :     {
    4251        1064 :       GEN w, T = gel(v2, i), D2a = absi_shallow(nfdisc(T));
    4252        1064 :       if ((w = makeS3vec(sqrti(divii(X, D2a)), gen_1, T, s3))) gel(v, c++) = w;
    4253             :     }
    4254          28 :     setlg(v,c); v = myshallowconcat1(v);
    4255             :   }
    4256          35 :   v = nflist_parapply("_nflist_S46M_worker",
    4257             :                            mkvec3(X, Xinf, mkvecsmall(s == -2? -1: s)), v);
    4258          35 :   return sturmseparate(myshallowconcat1(v), s, 6);
    4259             : }
    4260             : 
    4261             : /************************************************************************/
    4262             : /*                                  A462                                */
    4263             : /************************************************************************/
    4264             : static GEN
    4265         126 : arch0() { return mkvec(mkvec3(gen_0, gen_0, gen_0)); }
    4266             : static GEN
    4267          63 : arch1g() { return mkvec(mkvec3(gen_1, gen_0, gen_0)); }
    4268             : static GEN
    4269          63 : arch1() { return mkvec3(mkvec3(gen_1, gen_0, gen_0),
    4270             :                         mkvec3(gen_0, gen_1, gen_0),
    4271             :                         mkvec3(gen_0, gen_0, gen_1)); }
    4272             : static GEN
    4273          63 : arch2g() { return mkvec(mkvec3(gen_0, gen_1, gen_1)); }
    4274             : static GEN
    4275          63 : arch2() { return mkvec3(mkvec3(gen_0, gen_1, gen_1),
    4276             :                         mkvec3(gen_1, gen_0, gen_1),
    4277             :                         mkvec3(gen_1, gen_1, gen_0)); }
    4278             : static GEN
    4279          56 : arch3() { return mkvec(mkvec3(gen_1, gen_1, gen_1)); }
    4280             : 
    4281             : static GEN
    4282          91 : archA462(long s)
    4283             : {
    4284          91 :   switch (s)
    4285             :   {
    4286          14 :     case 0: return arch0();
    4287          14 :     case 1: return arch1g();
    4288          14 :     case 2: return arch2g();
    4289          49 :     default: return shallowconcat1(mkvec3(arch0(),arch1g(),arch2g()));
    4290             :   }
    4291             : }
    4292             : 
    4293             : static int
    4294        4515 : stable_arch(GEN v)
    4295             : {
    4296        4515 :   long i, l = lg(v);
    4297        4515 :   GEN x = gel(v,1);
    4298        7525 :   for (i = 2; i < l; i++) if (!equalii(x, gel(v,i))) return 0;
    4299        1505 :   return 1;
    4300             : }
    4301             : /* nf cyclic of prime degree, return a generator of */
    4302             : static GEN
    4303        5894 : cycfindaut(GEN nf)
    4304             : {
    4305        5894 :   GEN A = galoisconj(nf, NULL);
    4306        5894 :   return nfgaloismatrix(nf, gel(A, gequalX(gel(A,1))? 2 : 1));
    4307             : }
    4308             : 
    4309             : static int
    4310        2653 : isprM(GEN x)
    4311        2653 : { return typ(x) == t_MAT && lg(x) == 3; }
    4312             : static GEN
    4313       20251 : doA462(GEN bnf, GEN L, GEN Arch, GEN aut, GEN G, GEN GAL)
    4314             : {
    4315       20251 :   pari_sp av = avma;
    4316       20251 :   long c, k, i, m, lA = lg(Arch), l = lg(L);
    4317             :   int stable0;
    4318             :   GEN v;
    4319       20251 :   if (l == 1) return NULL;
    4320        2653 :   v = cgetg((lA-1) * (l-1) + 1, t_VEC);
    4321        2653 :   stable0 = !isprM(gel(L,l-1)); /* not implemented for prM */
    4322        7210 :   for (i = c = 1; i < lA; i++)
    4323             :   {
    4324        4557 :     GEN arch = gel(Arch, i);
    4325        4557 :     int stable = stable0 && stable_arch(arch);
    4326       15938 :     for (k = 1; k < l; k++)
    4327             :     {
    4328       11382 :       GEN R, id = gel(L,k), F = mkvec2(id, arch);
    4329             :       long cR, lR;
    4330       11382 :       if (stable && ZM_equal(nfgaloismatrixapply(bnf, aut, id), id))
    4331         497 :         R = mybnrclassfield_X(bnf, F, 2, NULL, NULL, G);
    4332             :       else
    4333       10885 :         R = mybnrclassfield(bnf, F, 2);
    4334       11381 :       lR = lg(R);
    4335       12459 :       for (m = cR = 1; m < lR; m++)
    4336             :       {
    4337        1078 :         GEN P = rnfequation(bnf, gel(R, m));
    4338        1078 :         if (okgal(P, GAL)) gel(R, cR++) = polredabs(P);
    4339             :       }
    4340       11381 :       if (cR > 1) { setlg(R, cR); gel(v, c++) = R; }
    4341             :     }
    4342             :   }
    4343        2653 :   if (c == 1) { set_avma(av); return NULL; }
    4344         819 :   setlg(v, c); return gtoset_shallow(shallowconcat1(v));
    4345             : }
    4346             : static GEN
    4347          49 : makeA462(GEN N, GEN field, long s)
    4348             : {
    4349             :   GEN v, L, Arch, GAL;
    4350             :   long i, c, l;
    4351             : 
    4352          49 :   if (s == 3) return NULL;
    4353          49 :   Arch = archA462(s);
    4354          49 :   GAL = mkvecsmall3(24, -1, 6);
    4355          49 :   if (field)
    4356             :   {
    4357           7 :     GEN D3 = checkfield(field, 3);
    4358           7 :     if (!Z_issquare(D3) || !dvdii(N, sqri(D3))) return NULL;
    4359           7 :     L = mkvec(field);
    4360             :   }
    4361             :   else
    4362             :   {
    4363          42 :     GEN LD = divisors(cored(N, 4));
    4364          42 :     L = cgetg(1, t_VEC);
    4365          91 :     for (i = 1; i < lg(LD); i++)
    4366             :     {
    4367          49 :       GEN t = makeC3_f(gel(LD,i));
    4368          49 :       if (lg(t) > 1) L = shallowconcat(L, t);
    4369             :     }
    4370             :   }
    4371          49 :   l = lg(L); v = cgetg(l, t_VEC);
    4372          63 :   for (i = c = 1; i < l; i++)
    4373             :   {
    4374          14 :     GEN bnf = bnfY(gel(L,i)), nf = bnf_get_nf(bnf), aut = cycfindaut(bnf);
    4375          14 :     GEN T, I = ideals_by_norm(nf, divii(N, sqri(nf_get_disc(nf))));
    4376          14 :     GEN G = mkvec2(galoisinit(nf, NULL), gen_0);
    4377          14 :     if ((T = doA462(bnf, I, Arch, aut, G, GAL))) gel(v, c++) = T;
    4378             :   }
    4379          49 :   if (c == 1) return NULL;
    4380          14 :   setlg(v, c); return sturmseparate(shallowconcat1(v), s, 6);
    4381             : }
    4382             : 
    4383             : GEN
    4384         175 : nflist_A462_worker(GEN P3, GEN X, GEN Xinf, GEN Arch, GEN GAL)
    4385             : {
    4386         175 :   pari_sp av = avma;
    4387         175 :   GEN bnf = bnfY(P3), aut = cycfindaut(bnf), v, t;
    4388         175 :   GEN G = mkvec2(galoisinit(bnf, NULL), gen_0), D2 = sqri(bnf_get_disc(bnf));
    4389         175 :   long c, l, j, lim = itos(divii(X, D2)), liminf = itos(ceildiv(Xinf, D2));
    4390             : 
    4391         175 :   v = ideallist(bnf, lim); l = lg(v);
    4392       20412 :   for (c = 1, j = liminf; j < l; j++)
    4393       20237 :     if ((t = doA462(bnf, gel(v,j), Arch, aut, G, GAL))) gel(v,c++) = t;
    4394         175 :   setlg(v, c); return gc_GEN(av, myshallowconcat1(v));
    4395             : }
    4396             : static GEN
    4397          49 : makeA462vec(GEN X, GEN Xinf, GEN field, long s)
    4398             : {
    4399             :   GEN v, GAL;
    4400             : 
    4401          49 :   if (s == 3) return NULL;
    4402          42 :   if (field)
    4403             :   {
    4404           7 :     GEN D3 = checkfield(field, 3);
    4405           7 :     if (!Z_issquare(D3) || cmpii(sqri(D3), X) > 0) return NULL;
    4406           7 :     v = mkvec(field);
    4407             :   }
    4408          35 :   else if (!(v = makeC3vec(sqrti(X), gen_1, NULL, 0))) return NULL;
    4409          42 :   GAL = mkvecsmall3(24, -1, 6);
    4410          42 :   v = nflist_parapply("_nflist_A462_worker", mkvec4(X, Xinf, archA462(s), GAL), v);
    4411          42 :   return sturmseparate(myshallowconcat1(v), s, 6);
    4412             : }
    4413             : 
    4414             : /************************************************************************/
    4415             : /*                                  S3C3                                */
    4416             : /************************************************************************/
    4417             : 
    4418             : static int
    4419        3626 : isok3(ulong N)
    4420             : {
    4421             :   GEN fa, P, E;
    4422        3626 :   long v = u_lvalrem(N, 3, &N), i, l;
    4423        3626 :   if (v == 1 || v >= 4) return 0;
    4424        2828 :   fa = factoru(N); P = gel(fa, 1); E = gel(fa, 2); l = lg(P);
    4425        3633 :   for (i = 1; i < l; i++)
    4426        2415 :     if (P[i] % 3 == 1) { if (E[i] != 1) return 0; }
    4427        1974 :     else               { if (E[i] != 2) return 0; }
    4428        1218 :   return 1;
    4429             : }
    4430             : 
    4431             : static GEN
    4432          49 : makeS3C3(GEN N, GEN field, long s)
    4433             : {
    4434             :   GEN v, LD, cond;
    4435             :   long s2, i;
    4436             : 
    4437          49 :   if (s == 1 || s == 2) return NULL;
    4438          35 :   s2 = s == 3 ? 1 : s;
    4439          35 :   if (field)
    4440             :   {
    4441           7 :     GEN D = checkfield(field, 2);
    4442           7 :     if (!divissquareall(N, powiu(absi_shallow(D), 3), &cond)) return NULL;
    4443           7 :     LD = mkvec(D);
    4444             :   }
    4445          28 :   else LD = divisorsdisc(cored(N, 3), s2);
    4446          35 :   v = cgetg(1, t_VEC);
    4447          49 :   for (i = 1; i < lg(LD); i++)
    4448             :   {
    4449          14 :     GEN L, bnf, nf, D = gel(LD, i);
    4450             :     long j, k;
    4451          14 :     if (!divissquareall(N, powiu(absi_shallow(D), 3), &cond)) continue;
    4452          14 :     bnf = bnfY(Y2m(D)); nf = bnf_get_nf(bnf);
    4453          14 :     L = ideals_by_norm(nf, cond);
    4454          42 :     for (j = 1; j < lg(L); j++)
    4455             :     {
    4456          28 :       GEN R = mybnrclassfield_N(bnf, gel(L,j), N, 3);
    4457          56 :       for (k = 1; k < lg(R); k++)
    4458             :       {
    4459          28 :         GEN P = rnfequation(nf, gel(R, k));
    4460          28 :         if (okgal1(P, 18)) v = vec_append(v, polredabs(P));
    4461             :       }
    4462             :     }
    4463             :   }
    4464          35 :   return sturmseparate(gtoset_shallow(v), s, 6);
    4465             : }
    4466             : 
    4467             : GEN
    4468         413 : nflist_S3C3_worker(GEN D2, GEN X, GEN Xinf)
    4469             : {
    4470         413 :   pari_sp av = avma;
    4471         413 :   GEN bnf = bnfY(Y2m(D2)), nf = bnf_get_nf(bnf), aut = cycfindaut(nf);
    4472         413 :   GEN G = mkvec2(galoisinit(bnf, NULL), gen_0);
    4473         413 :   long f, c, limf = floorsqrtdiv(X, powuu(itou(D2), 3));
    4474         413 :   GEN v = ideallist0(nf, limf, 4 | 8);
    4475             : 
    4476        4039 :   for (f = c = 1; f <= limf; f++)
    4477             :   {
    4478             :     pari_sp av2;
    4479             :     long j, k, cL;
    4480             :     GEN L;
    4481             : 
    4482        3626 :     if (!isok3(f)) continue;
    4483        1218 :     av2 = avma; L = gel(v, f);
    4484        2548 :     for (j = cL = 1; j < lg(L); j++)
    4485             :     {
    4486        1330 :       pari_sp av3 = avma;
    4487        1330 :       long stable = gequal(gel(L,j), nfgaloismatrixapply(nf, aut, gel(L,j)));
    4488        1330 :       GEN R = mybnrclassfield_X(bnf, gel(L,j), 3, X, Xinf, stable? G: NULL);
    4489        1330 :       long lR = lg(R), cR;
    4490        1582 :       for (k = cR = 1; k < lR; k++)
    4491             :       {
    4492         252 :         GEN P = rnfequation(nf, gel(R, k));
    4493         252 :         if (okgal1(P, 18)) gel(R, cR++) = polredabs(P);
    4494             :       }
    4495        1330 :       if (cR == 1) { set_avma(av3); continue; }
    4496         252 :       setlg(R, cR); gel(L, cL++) = R;
    4497             :     }
    4498        1218 :     if (cL == 1) { set_avma(av2); continue; }
    4499         126 :     setlg(L, cL); gel(v, c++) = shallowconcat1(L);
    4500             :   }
    4501         413 :   setlg(v, c); return gc_GEN(av, gtoset_shallow(myshallowconcat1(v)));
    4502             : }
    4503             : 
    4504             : static GEN
    4505          42 : makeS3C3vec(GEN X, GEN Xinf, GEN field, long s)
    4506             : {
    4507             :   GEN v;
    4508             : 
    4509          42 :   if (s == 1 || s == 2) return NULL;
    4510          28 :   if (field)
    4511             :   {
    4512           7 :     GEN D = checkfield(field, 2);
    4513           7 :     v = mkvec(D);
    4514             :   }
    4515             :   else
    4516             :   {
    4517          21 :     long lim = floorsqrtn(X, 3), Da, c;
    4518          21 :     v = cgetg(2 * lim + 1, t_VEC);
    4519         945 :     for (Da = 3, c = 1; Da <= lim; Da++)
    4520             :     {
    4521             :       int p, m;
    4522         924 :       uis_fundamental_pm(Da, s, &p, &m);
    4523         924 :       if (p) gel(v, c++) = utoipos(Da);
    4524         924 :       if (m) gel(v, c++) = utoineg(Da);
    4525             :     }
    4526          21 :     if (c == 1) return NULL;
    4527          21 :     setlg(v, c);
    4528             :   }
    4529          28 :   v = nflist_parapply("_nflist_S3C3_worker", mkvec2(X, Xinf), v);
    4530          28 :   return sturmseparate(myshallowconcat1(v), s, 6);
    4531             : }
    4532             : 
    4533             : /************************************************************************/
    4534             : /*                               S462                                   */
    4535             : /************************************************************************/
    4536             : 
    4537             : static GEN
    4538          98 : archS4621(long s)
    4539             : {
    4540          98 :   switch(s)
    4541             :   {
    4542          28 :     case 0: case 1: return cgetg(1, t_VEC);
    4543          14 :     case 2: retmkvec(mkvec(gen_0));
    4544           7 :     case 3: retmkvec(mkvec(gen_1));
    4545          49 :     default:retmkvec2(mkvec(gen_0), mkvec(gen_1));
    4546             :   }
    4547             : }
    4548             : 
    4549             : static GEN
    4550          98 : archS4623(long s)
    4551             : {
    4552          98 :   switch (s)
    4553             :   {
    4554          14 :     case 0: return arch0();
    4555          14 :     case 1: return arch1();
    4556          14 :     case 2: return arch2();
    4557           7 :     case 3: return arch3();
    4558          49 :     default:return shallowconcat1(mkvec4(arch0(),arch1(),arch2(),arch3()));
    4559             :   }
    4560             : }
    4561             : 
    4562             : static GEN
    4563          49 : makeS462(GEN N, GEN field, long s)
    4564             : {
    4565          49 :   GEN RES = cgetg(1, t_VEC), L, listarch1, listarch3, GAL;
    4566             :   long i, j, l, m;
    4567          49 :   listarch1 = archS4621(s); listarch3 = archS4623(s);
    4568          49 :   GAL = mkvecsmall3(48, -1, 11);
    4569          49 :   if (field)
    4570             :   {
    4571           7 :     GEN d = checkfield(field, 3);
    4572           7 :     if (Z_issquare(d) || !dvdii(N, sqri(d))) return NULL;
    4573           7 :     L = mkvec(field);
    4574             :   }
    4575             :   else
    4576             :   {
    4577             :     GEN T;
    4578             :     long c;
    4579          42 :     L =  divisors(cored(N, 2));
    4580          91 :     for (i = c = 1; i < lg(L); i++)
    4581          49 :       if ((T = makeDL(3, gel(L,i), NULL, (s == 0 || s == 1) ? 0 : -1)))
    4582           7 :         gel(L, c++) = T;
    4583          42 :     if (c == 1) return NULL;
    4584           7 :     setlg(L, c); L = shallowconcat1(L);
    4585             :   }
    4586          28 :   for (i = 1; i < lg(L); i++)
    4587             :   {
    4588          14 :     GEN bnf = bnfY(gel(L,i)), nf = bnf_get_nf(bnf);
    4589          14 :     GEN I = ideals_by_norm(nf, divii(N, sqri(nf_get_disc(nf))));
    4590          14 :     GEN Arch = nf_get_r1(nf) == 1 ? listarch1 : listarch3;
    4591          28 :     for (j = 1; j < lg(I); j++)
    4592             :     {
    4593          14 :       GEN id = gel(I, j);
    4594          42 :       for (l = 1; l < lg(Arch); l++)
    4595             :       {
    4596          28 :         GEN R = mybnrclassfield(bnf, mkvec2(id, gel(Arch, l)), 2);
    4597          42 :         for (m = 1; m < lg(R); m++)
    4598             :         {
    4599          14 :           GEN P = rnfequation(bnf, gel(R, m));
    4600          14 :           if (okgal(P, GAL) && (P = ZX_red_disc(P, N))) RES = vec_append(RES, P);
    4601             :         }
    4602             :       }
    4603             :     }
    4604             :   }
    4605          14 :   return sturmseparate(gtoset_shallow(RES), s, 6);
    4606             : }
    4607             : 
    4608             : GEN
    4609         959 : nflist_S462_worker(GEN P3, GEN X, GEN Xinf, GEN vArch, GEN GAL)
    4610             : {
    4611         959 :   pari_sp av = avma;
    4612         959 :   GEN bnf = bnfY(P3), nf = bnf_get_nf(bnf), D2 = sqri(nf_get_disc(nf));
    4613         959 :   long limf = itos(divii(X, D2)), liminf = itos(ceildiv(Xinf, D2));
    4614         959 :   long r1 = nf_get_r1(nf), c, j, k, l, m;
    4615         959 :   GEN v, vI = ideallist(bnf, limf), Arch = gel(vArch, r1 == 1? 1 : 2);
    4616             : 
    4617         959 :   v = cgetg(limf + 1, t_VEC);
    4618       12677 :   for (c = 1, j = liminf; j <= limf; j++)
    4619             :   {
    4620       11718 :     GEN I = gel(vI, j), REU = cgetg(1, t_VEC);
    4621       18263 :     for (k = 1; k < lg(I); k++)
    4622             :     {
    4623        6545 :       GEN id = gel(I, k);
    4624       16079 :       for (l = 1; l < lg(Arch); l++)
    4625             :       {
    4626        9534 :         GEN R = mybnrclassfield(bnf, mkvec2(id, gel(Arch, l)), 2);
    4627       10836 :         for (m = 1; m < lg(R); m++)
    4628             :         {
    4629        1302 :           GEN P = rnfequation(bnf, gel(R, m));
    4630        1302 :           if (okgal(P, GAL)) REU = vec_append(REU, polredabs(P));
    4631             :         }
    4632             :       }
    4633             :     }
    4634       11718 :     if (lg(REU) > 1) gel(v, c++) = REU;
    4635             :   }
    4636         959 :   setlg(v,c); v = myshallowconcat1(v);
    4637         959 :   return gc_GEN(av, gtoset_shallow(v));
    4638             : }
    4639             : static GEN
    4640          56 : makeS462vec(GEN X, GEN Xinf, GEN field, long s)
    4641             : {
    4642             :   GEN v, T, GAL;
    4643             : 
    4644          56 :   if (field)
    4645             :   {
    4646           7 :     GEN D3 = checkfield(field, 3);
    4647           7 :     long si = signe(D3);
    4648           7 :     if (Z_issquare(D3) || (si < 0 && (s == 0 || s == 1))) return NULL;
    4649           7 :     v = mkvec(field);
    4650             :   }
    4651          49 :   else if (!(v = makeS3vec(sqrti(X), gen_1, NULL, (s==0 || s==1)? 0: -1)))
    4652           7 :     return NULL;
    4653          49 :   GAL = mkvecsmall3(48, -1, 11);
    4654          49 :   T = mkvec4(X, Xinf, mkvec2(archS4621(s), archS4623(s)), GAL);
    4655          49 :   v = nflist_parapply("_nflist_S462_worker", T, v);
    4656          49 :   return sturmseparate(myshallowconcat1(v), s, 6);
    4657             : }
    4658             : /************************************************************************/
    4659             : /*                              C32C4                                   */
    4660             : /************************************************************************/
    4661             : static GEN
    4662        2961 : doC32C4_i(GEN bnf, GEN L, GEN GAL)
    4663             : {
    4664        2961 :   long i, l = lg(L);
    4665             :   GEN v;
    4666        2961 :   if (l == 1) return L;
    4667        1659 :   v = cgetg(l, t_VEC);
    4668        4515 :   for (i = 1; i < l; i++)
    4669             :   {
    4670        2856 :     GEN w = cgetg(1, t_VEC), R = mybnrclassfield(bnf, gel(L,i), 3);
    4671        2856 :     long j, lR = lg(R);
    4672        3262 :     for (j = 1; j < lR; j++)
    4673             :     {
    4674         406 :       GEN P12 = rnfequation(bnf, gel(R, j)), S = _nfsubfields(P12, 6);
    4675         406 :       long k, lS = lg(S);
    4676         924 :       for (k = 1; k < lS; k++)
    4677             :       {
    4678         518 :         GEN P = gel(S,k);
    4679         518 :         if (okgal(P, GAL)) w = vec_append(w, polredabs(P));
    4680             :       }
    4681             :     }
    4682        2856 :     gel(v,i) = w;
    4683             :   }
    4684        1659 :   return gtoset_shallow(myshallowconcat1(v));
    4685             : }
    4686             : static GEN
    4687          49 : doC32C4(GEN N, GEN P4, GEN GAL)
    4688             : {
    4689          49 :   GEN nf, bnf, F, F2, D4 = nfdisc(P4), D2 = nfdisc(_nfsubfields1(P4, 2));
    4690          49 :   if (!(F2 = divide(N, mulii(D2,D4))) || !Z_issquareall(F2, &F)) return NULL;
    4691          49 :   bnf = bnfY(P4); nf = bnf_get_nf(bnf);
    4692          49 :   return doC32C4_i(bnf, ideals_by_norm(nf, F2), GAL);
    4693             : }
    4694             : static GEN
    4695          56 : makeC32C4_i(GEN N, GEN field, long s)
    4696             : {
    4697          56 :   GEN GAL = mkvecsmall3(36, 1, 10), v, w, C;
    4698             :   long c, i, j, l;
    4699          56 :   if (!Z_issquare(N) || s == 1 || s == 3) return NULL;
    4700          49 :   if (field)
    4701             :   {
    4702           7 :     checkfield_i(field, 4);
    4703           7 :     return (okgal2(field,4,-1) && ok_s(field, s))? doC32C4(N, field, GAL): NULL;
    4704             :   }
    4705          42 :   v = divisors(N); l = lg(v);
    4706         490 :   for (i = c = 1; i < l; i++)
    4707             :   {
    4708             :     long cw, lC;
    4709         448 :     if (!(C = makeC4(gel(v, i), NULL, maxss(s, -1)))) continue;
    4710          28 :     lC = lg(C);
    4711          70 :     for (j = cw = 1; j < lC; j++)
    4712          42 :       if ((w = doC32C4(N, gel(C,j), GAL))) gel(C,cw++) = w;
    4713          28 :     if (cw > 1) { setlg(C, cw); gel(v, c++) = shallowconcat1(C); }
    4714             :   }
    4715          42 :   setlg(v, c); return myshallowconcat1(v);
    4716             : }
    4717             : static GEN
    4718          56 : makeC32C4(GEN N, GEN field, long s)
    4719             : {
    4720          56 :   GEN v = makeC32C4_i(N, field, s);
    4721          56 :   return v? sturmseparate(v, s, 6): NULL;
    4722             : }
    4723             : 
    4724             : static GEN
    4725          28 : makeC32C4resolvent(GEN pol, long flag)
    4726             : {
    4727          28 :   GEN P12 = polredabs(gel(compositum(pol, pol), 2));
    4728          28 :   return condrel(mynfsubfield(P12,4), P12, flag);
    4729             : }
    4730             : 
    4731             : /* ideals of square norm < lim^2 */
    4732             : static GEN
    4733        6426 : ideallistsquare(GEN bnf, long lim)
    4734             : {
    4735        6426 :   pari_sp av = avma;
    4736        6426 :   GEN nf = bnf_get_nf(bnf), V, Z, F;
    4737        6426 :   long d = nf_get_degree(nf), lim2 = lim * lim, p;
    4738             :   forprime_t T;
    4739             : 
    4740        6426 :   if (lim <= 0) return cgetg(1, t_VEC);
    4741        6181 :   V = const_vec(lim, cgetg(1, t_VEC)); gel(V, 1) = mkvec(trivial_fact());
    4742        6181 :   u_forprime_init(&T, 2, lim);
    4743        6181 :   F = cgetg(d+1, t_VECSMALL);
    4744        6181 :   Z = cgetg(d+1, t_VECSMALL);
    4745       14770 :   while ((p = u_forprime_next(&T)))
    4746             :   {
    4747        8589 :     long lv, i, llp = ulogint(lim2, p), tot, m;
    4748        8589 :     GEN P = idealprimedec_limit_f(nf, utoipos(p), llp);
    4749        8589 :     GEN W = shallowcopy(V);
    4750        8589 :     lv = lg(P);
    4751       19845 :     for (i = tot = 1; i < lv; i++)
    4752             :     {
    4753       11256 :       F[i] = pr_get_f(gel(P,i));
    4754       11256 :       Z[i] = llp / F[i] + 1; tot *= Z[i];
    4755             :     }
    4756       75348 :     for (m = 1; m < tot; m++)
    4757             :     {
    4758       66759 :       GEN v = cgetg(lv, t_VECSMALL);
    4759       66759 :       long n = m, S = 0;
    4760      258377 :       for (i = 1; i < lv; i++) { v[i] = n % Z[i]; n /= Z[i]; S += v[i] * F[i]; }
    4761       66759 :       if (!odd(S) && S <= llp)
    4762             :       {
    4763       18459 :         GEN id = famat_remove_trivial(mkvec2(P, zc_to_ZC(v)));
    4764       18459 :         long j, pS = upowuu(p, S >> 1);
    4765       54509 :         for (j = 1; j <= lim / pS; j++)
    4766             :         {
    4767       36050 :           GEN vs = shallowcopy(gel(V, j));
    4768       36050 :           long k, l = lg(vs);
    4769       58583 :           for (k = 1; k < l; k++) gel(vs, k) = famat_mul(gel(vs, k), id);
    4770       36050 :           gel(W, pS * j) = shallowconcat(gel(W, pS * j), vs);
    4771             :         }
    4772             :       }
    4773             :     }
    4774        8589 :     V = W;
    4775             :   }
    4776        6181 :   return gc_GEN(av, V);
    4777             : }
    4778             : 
    4779             : GEN
    4780        1131 : nflist_C32C4_worker(GEN P4, GEN X, GEN Xinf, GEN GAL)
    4781             : {
    4782        1131 :   pari_sp av = avma;
    4783        1131 :   GEN bnf = bnfY(P4), D4 = bnf_get_disc(bnf), D2 = nfdisc(_nfsubfields1(P4, 2));
    4784        1134 :   GEN vI, v, w, D4D2 = mulii(D4, D2);
    4785        1134 :   long f, c, limf = floorsqrtdiv(X, D4D2), liminf = ceilsqrtdiv(Xinf, D4D2);
    4786             : 
    4787        1134 :   vI = ideallistsquare(bnf, limf); v = cgetg(limf + 1, t_VEC);
    4788        4046 :   for (c = 1, f = liminf; f <= limf; f++)
    4789        2912 :     if ((w = doC32C4_i(bnf,  gel(vI, f), GAL))) gel(v, c++) = w;
    4790        1134 :   setlg(v,c); return gc_GEN(av, gtoset_shallow(myshallowconcat1(v)));
    4791             : }
    4792             : static GEN
    4793          49 : makeC32C4vec(GEN X, GEN Xinf, GEN field, long s)
    4794             : {
    4795             :   GEN v, L, GAL;
    4796             : 
    4797          49 :   if (s == 1 || s == 3) return NULL;
    4798          35 :   GAL = mkvecsmall3(36, 1, 10);
    4799          35 :   if (field)
    4800             :   {
    4801           7 :     checkfield_i(field, 4);
    4802           7 :     if (!okgal2(field, 4, -1) || !ok_s(field, s)) return NULL;
    4803           7 :     L = mkvec(field);
    4804             :   }
    4805          28 :   else L = makeC4vec(divis(X, 5), gen_1, NULL, s == -2? -1: s);
    4806          35 :   v = nflist_parapply("_nflist_C32C4_worker", mkvec3(X, Xinf, GAL), L);
    4807          35 :   return sturmseparate(myshallowconcat1(v), s, 6);
    4808             : }
    4809             : /************************************************************************/
    4810             : /*                                 C9                                   */
    4811             : /************************************************************************/
    4812             : 
    4813             : static GEN
    4814         210 : bnrcfC9(GEN bnf, GEN P, GEN F)
    4815             : {
    4816         210 :   GEN v, cond = F, vec9 = mkvec(utoipos(9)), nf = bnf_get_nf(bnf);
    4817         210 :   long i, l, c, lP = lg(P);
    4818         420 :   for (i = 1; i < lP; i++)
    4819             :   {
    4820         210 :     GEN p = gel(P, i), pr = idealprimedec_galois(nf, p);
    4821         210 :     if (equaliu(p, 3)) pr = idealsqr(nf, pr);
    4822         210 :     cond = idealmul(nf, cond, pr);
    4823             :   }
    4824         210 :   v = mybnrclassfield(bnf, cond, 3);
    4825         210 :   l = lg(v); if (l == 1) return v;
    4826         112 :   for (i = c = 1; i < l; i++)
    4827             :   {
    4828          56 :     GEN P = rnfequation(nf, gel(v,i)), G = galoisinit(P, NULL);
    4829          56 :     if (typ(G) != t_INT && gequal(galoisisabelian(G, 2), vec9))
    4830          56 :       gel(v, c++) = polredabs(P);
    4831             :   }
    4832          56 :   setlg(v, c); return gtoset_shallow(v);
    4833             : }
    4834             : 
    4835             : static GEN
    4836          56 : makeC9(GEN N, GEN field, long s)
    4837             : {
    4838             :   GEN v, D, F;
    4839             :   long i, lD;
    4840             : 
    4841          56 :   if (s > 0) return NULL;
    4842          42 :   if (field)
    4843             :   {
    4844           7 :     GEN D = checkfield(field, 3), d, P;
    4845           7 :     if (!Z_issquareall(D, &d)
    4846           7 :         || !divispowerall(N, powiu(D,4), 6, &F)) return NULL;
    4847           7 :     P = gel(Z_factor(d), 1);
    4848           7 :     return bnrcfC9(bnfY(field), P, F);
    4849             :   }
    4850          35 :   v = cgetg(1, t_VEC);
    4851          35 :   D = divisors(cored(N, 8)); lD = lg(D);
    4852          63 :   for (i = 2; i < lD; i++)
    4853             :   {
    4854          28 :     GEN v3, P, d = gel(D,i);
    4855             :     long j, l3;
    4856          28 :     if (!Z_ispowerall(divii(N, powiu(d, 8)), 6, &F)
    4857          28 :         || !checkcondC3(d, &P)) continue;
    4858          14 :     v3 = makeC3_i(d, P); l3 = lg(v3);
    4859          28 :     for (j = 1; j < l3; j++)
    4860          14 :       v = shallowconcat(v, bnrcfC9(bnfY(gel(v3,j)), P, F));
    4861             :   }
    4862          35 :   return s == -2? vecs(5, v): v;
    4863             : }
    4864             : 
    4865             : GEN
    4866          77 : nflist_C9_worker(GEN T, GEN X, GEN Xinf)
    4867             : {
    4868          77 :   pari_sp av = avma;
    4869          77 :   GEN bnf = bnfY(T), D3 = bnf_get_disc(bnf), D34 = powiu(D3, 4);
    4870          77 :   GEN sqD = sqrti(D3), P = gel(Z_factor(sqD), 1), v;
    4871          77 :   long fl = umodiu(D3, 3) == 0;
    4872          77 :   long limf = floorsqrtndiv(X, D34, 6), f, c;
    4873          77 :   long limi = ceilsqrtndiv(Xinf, D34, 6);
    4874             : 
    4875          77 :   v = cgetg(limf + 1, t_VEC); c = 1;
    4876         350 :   for (f = limi; f <= limf; f++)
    4877             :   {
    4878             :     GEN t;
    4879         273 :     if (fl) { long r = f % 9; if (r != 3 && r != 6) continue; }
    4880         189 :     t = bnrcfC9(bnf, P, utoipos(f));
    4881         189 :     if (lg(t) > 1) gel(v, c++) = t;
    4882             :   }
    4883          77 :   if (c == 1) retgc_const(av, cgetg(1, t_VEC));
    4884          35 :   setlg(v,c); return gc_GEN(av, myshallowconcat1(v));
    4885             : }
    4886             : 
    4887             : static GEN
    4888          49 : makeC9vec(GEN X, GEN Xinf, GEN field, long s)
    4889             : {
    4890             :   GEN v;
    4891          49 :   if (s > 0) return NULL;
    4892          21 :   if (field)
    4893             :   {
    4894           7 :     GEN D = checkfield(field, 3);
    4895           7 :     if (!Z_issquare(D) || cmpii(powiu(D,4), X) > 0) return NULL;
    4896           7 :     v = mkvec(field);
    4897             :   }
    4898          14 :   else if (!(v = makeC3vec(sqrtnint(X, 4), gen_1, NULL, 0))) return NULL;
    4899          21 :   v = nflist_parapply("_nflist_C9_worker", mkvec2(X, Xinf), v);
    4900          21 :   v = myshallowconcat1(v);
    4901          21 :   return (s == -2)? vecs(5, v): v;
    4902             : }
    4903             : /************************************************************************/
    4904             : /*                                C3xC3                                 */
    4905             : /************************************************************************/
    4906             : 
    4907             : static GEN
    4908          49 : makeC3C3(GEN N, GEN field, long s)
    4909             : {
    4910             :   GEN D, v, f, L;
    4911             :   long i, j, l, c;
    4912             : 
    4913          49 :   if (s > 0 || !Z_ispowerall(N, 6, &f)) return NULL;
    4914          35 :   D = divisors(f); l = lg(D);
    4915          35 :   if (field)
    4916             :   {
    4917           7 :     GEN d = checkfield(field, 3), g;
    4918           7 :     if (!Z_issquareall(d, &g) || !dvdii(f, g)) return NULL;
    4919           7 :     v = cgetg(l, t_VEC);
    4920          42 :     for (i = 2, c = 1; i < l; i++)
    4921             :     {
    4922          35 :       GEN t, g3 = gel(D, i);
    4923             :       long lt;
    4924          35 :       if (equalii(g3, g) || !equalii(lcmii(g,g3), f)) continue;
    4925          21 :       t = makeC3_f(g3); lt = lg(t); if (lt == 1) continue;
    4926          35 :       for (j = 1; j < lt; j++)
    4927          21 :         gel(t,j) = polredabs(polcompositum0(field, gel(t,j), 2));
    4928          14 :       gel(v, c++) = t;
    4929             :     }
    4930           7 :     setlg(v, c); return gtoset_shallow(myshallowconcat1(v));
    4931             :   }
    4932          28 :   L = const_vec(l-1, NULL);
    4933          28 :   v = cgetg(l * (l-1) / 2 + 1, t_VEC);
    4934          91 :   for (i = c = 1; i < l; i++)
    4935             :   {
    4936          63 :     GEN g = gel(D,i);
    4937         231 :     for (j = i; j < l; j++)
    4938         168 :       if (equalii(lcmii(g, gel(D,j)), f))
    4939             :       {
    4940             :         GEN Li, Lj, w;
    4941             :         long li, lj, a, b, cw;
    4942          77 :         if (!gel(L,i)) gel(L,i) = makeC3_f(g);
    4943          77 :         if (!gel(L,j)) gel(L,j) = makeC3_f(gel(D,j));
    4944          77 :         Li = gel(L,i); li = lg(Li);
    4945          77 :         Lj = gel(L,j); lj = lg(Lj); w = cgetg(li * lj, t_VEC);
    4946         119 :         for (a = cw = 1; a < li; a++)
    4947          84 :           for (b = i == j? a+1: 1; b < lj; b++)
    4948          42 :             gel(w, cw++) = polredabs(polcompositum0(gel(Li,a), gel(Lj,b), 2));
    4949          77 :         setlg(w, cw); gel(v, c++) = w;
    4950             :       }
    4951             :   }
    4952          28 :   setlg(v, c); v = gtoset_shallow(myshallowconcat1(v));
    4953          28 :   return s == -2? vecs(5, v): v;
    4954             : }
    4955             : 
    4956             : static GEN
    4957          21 : makeC3C3resolvent(GEN pol, long flag)
    4958             : {
    4959          21 :   GEN V = mynfsubfields(pol, 3);
    4960          21 :   if (lg(V) != 5) pari_err_BUG("makeC3C3resolvent");
    4961          21 :   if (flag < 2) return condrel(gel(V,1), pol, flag);
    4962          14 :   if (flag == 2) return V;
    4963           7 :   return mkvec4(condrel_i(gel(V,1), pol),
    4964           7 :                 condrel_i(gel(V,2), pol),
    4965           7 :                 condrel_i(gel(V,3), pol),
    4966           7 :                 condrel_i(gel(V,4), pol));
    4967             : }
    4968             : 
    4969             : /* x, y > 0 */
    4970             : static GEN
    4971         112 : lcmiu(GEN x, ulong y) { return muliu(x, y / ugcdiu(x,y)); }
    4972             : static GEN
    4973        1676 : lcmuu(ulong x, ulong y) { return muluu(x, y / ugcd(x, y)); }
    4974             : 
    4975             : GEN
    4976         224 : nflist_C3C3_worker(GEN gi, GEN w, GEN F, GEN X)
    4977             : {
    4978         224 :   pari_sp av = avma;
    4979         224 :   long c, j, i = itos(gi), l = lg(w), f = F[i], x = X[1], xinf = X[2];
    4980         224 :   GEN P3 = gel(w, i), v = cgetg(l, t_VEC);
    4981        1900 :   for (j = i + 1, c = 1; j < l; j++)
    4982        1676 :     if (ok_intu(lcmuu(f, F[j]), x, xinf))
    4983         168 :       gel(v, c++) = polredabs(polcompositum0(P3, gel(w, j), 2));
    4984         224 :   setlg(v, c); return gc_GEN(av, v);
    4985             : }
    4986             : 
    4987             : static GEN
    4988          49 : makeC3C3vec(GEN X, GEN Xinf, GEN field, long s)
    4989             : {
    4990             :   GEN F, v, v3;
    4991             :   long j, l, x, xinf;
    4992             : 
    4993          49 :   if (s > 0) return NULL;
    4994          21 :   x = floorsqrtn(X, 6);
    4995          21 :   v3 = C3vec_F(x, 1, &F); if (!v3) return NULL;
    4996          21 :   v3 = zvV_to_ZXV(v3); l = lg(v3);
    4997          21 :   v = cgetg((l - 1) * l / 2 + 1, t_VEC);
    4998          21 :   xinf = ceilsqrtn(Xinf, 6);
    4999          21 :   if (field)
    5000             :   {
    5001           7 :     GEN F3, D3 = checkfield(field, 3);
    5002             :     long c;
    5003           7 :     if (!Z_issquareall(D3, &F3)) return NULL;
    5004         119 :     for (j = c = 1; j < l; j++)
    5005         112 :       if (ok_intu(lcmiu(F3, F[j]), x, xinf) && !ZX_equal(gel(v3,j), field))
    5006          28 :         gel(v, c++) = polredabs(polcompositum0(field, gel(v3,j), 2));
    5007           7 :     setlg(v, c);
    5008             :   }
    5009             :   else
    5010             :   {
    5011          14 :     GEN T = mkvec3(v3, F, mkvecsmall2(x,xinf));
    5012          14 :     v = nflist_parapply("_nflist_C3C3_worker", T, identity_ZV(l-1));
    5013          14 :     v = myshallowconcat1(v);
    5014             :   }
    5015          21 :   v = gtoset_shallow(v); return s == -2? vecs(5, v): v;
    5016             : }
    5017             : 
    5018             : /************************************************************************/
    5019             : /*                                S32                                   */
    5020             : /************************************************************************/
    5021             : 
    5022             : static GEN
    5023         560 : makepolS32(GEN P1, GEN P2)
    5024             : {
    5025         560 :   GEN G = galoissplittinginit(polcompositum0(P1, P2, 2), utoipos(36));
    5026         560 :   GEN vH = galoissubgroups(G), g = mkvec2(gal_get_gen(G), gal_get_orders(G));
    5027         560 :   long i, l = lg(vH);
    5028       21616 :   for (i = 1; i < l; i++)
    5029             :   {
    5030       21616 :     GEN H = gel(vH, i);
    5031       21616 :     if (group_order(H) == 6 && !group_isabelian(H) /*S3*/
    5032        4816 :         && group_subgroup_is_faithful(g, H))
    5033         560 :       return polredabs(galoisfixedfield(G, H, 1, 0));
    5034             :   }
    5035             :   return NULL; /*LCOV_EXCL_LINE*/
    5036             : }
    5037             : 
    5038             : static GEN
    5039          77 : extractS3cond(GEN V3, GEN sqX, GEN field, long s)
    5040             : {
    5041          77 :   GEN v, v2 = NULL;
    5042          77 :   long l = lg(V3), c, c2, i;
    5043             : 
    5044          77 :   v = cgetg(l, t_VEC);
    5045          77 :   if (s == 3) v2 = cgetg(l, t_VEC);
    5046      629251 :   for (i = c = c2 = 1; i < l; i++)
    5047             :   {
    5048      629174 :     GEN pol = gel(V3, i), D, F, DF;
    5049      629174 :     (void)nfcoredisc2(pol, &D, &F); DF = mulii(D, F);
    5050      629174 :     if (abscmpii(DF, sqX) <= 0)
    5051             :     {
    5052        9450 :       GEN ind = field || s == 3 ? gen_0 : utoipos(c);
    5053        9450 :       GEN V = mkvecn(5, pol, F, mulii(sqri(DF), D), D, ind);
    5054        9450 :       if (s != 3 || signe(D) > 0) gel(v, c++) = V; else gel(v2, c2++) = V;
    5055             :     }
    5056             :   }
    5057          77 :   setlg(v, c); if (s != 3) return v;
    5058           7 :   setlg(v2, c2); return mkvec2(v, v2);
    5059             : }
    5060             : 
    5061             : static GEN makeS32common(GEN V3, GEN X, GEN Xinf, GEN field, long s);
    5062             : static GEN
    5063          49 : makeS32(GEN N, GEN field, long s)
    5064             : {
    5065             :   long s3, i, c, l;
    5066             :   GEN v, t;
    5067             : 
    5068          49 :   if (s == 1) return NULL;
    5069          42 :   s3 = -1; if (s == 0) s3 = 0; if (s == 2) s3 = 1;
    5070          42 :   v = divisors(N); l = lg(v);
    5071         868 :   for (i = 2, c = 1; i < l; i++)
    5072         826 :     if ((t = makeDL(3, gel(v, i), NULL, s3))) gel(v,c++) = t;
    5073          42 :   setlg(v,c); return makeS32common(myshallowconcat1(v), N, N, field, s);
    5074             : }
    5075             : 
    5076             : static GEN
    5077          28 : group_add_elt(GEN H, GEN g, long r)
    5078          28 : { return mkvec2(vec_append(gel(H,1),g), vecsmall_append(gel(H,2), r)); }
    5079             : 
    5080             : static GEN
    5081          14 : makeS32resolvent(GEN pol, long flag)
    5082             : {
    5083          14 :   GEN w, g1, g2, H1, H2, G = galoissplittinginit(pol, utoipos(36));
    5084          14 :   GEN v = galoissubgroups(G), g = galois_group(G);
    5085          14 :   long i, c, l = lg(v);
    5086         854 :   for (i = c = 1; i < l; i++)
    5087             :   {
    5088         840 :     GEN H = gel(v,i);
    5089         840 :     if (group_order(H) == 6 && group_subgroup_isnormal(g,H)) gel(v, c++) = H;
    5090             :   }
    5091          14 :   H1 = gel(v,1); g1 = gel(H1,1);
    5092          14 :   H2 = gel(v,2); g2 = gel(H2,1); /* G = H1 x H2, Hi ~ S3 */
    5093          14 :   H1 = group_add_elt(H1, gel(g2,2), 2);
    5094          14 :   H2 = group_add_elt(H2, gel(g1,2), 2);
    5095          14 :   w = condrel_dummy(galoisfixedfield(G,H1,1,0), flag);
    5096          14 :   if (flag >= 2) w = mkvec2(w, condrel_dummy(galoisfixedfield(G,H2,1,0),flag));
    5097          14 :   return w;
    5098             : }
    5099             : 
    5100             : /* s = 0: real, real; s = 1 imp; s = 2: imag, imag; s = 3: real, imag. */
    5101             : GEN
    5102        7469 : nflist_S32_worker(GEN S1, GEN X, GEN Xinf, GEN w, GEN gs)
    5103             : {
    5104        7469 :   pari_sp av = avma;
    5105        7469 :   GEN pol1 = gel(S1, 1), F1 = gel(S1, 2), A1 = gel(S1, 3), D1 = gel(S1, 4), v;
    5106        7469 :   long c, j, l = lg(w), i = itos(gel(S1, 5)), s = gs[1];
    5107        7469 :   v = cgetg(l, t_VEC);
    5108      777588 :   for (j = s == 3 ? 1 : i + 1, c = 1; j < l; j++)
    5109             :   {
    5110      770193 :     GEN S2 = gel(w,j), F2 = gel(S2,2), A2 = gel(S2,3), D2 = gel(S2,4), Q,P;
    5111      770193 :     if (equalii(D2, D1)) continue;
    5112      702976 :     P = mulii(sqri(gcdii(D1,D2)), gcdii(F1,F2)); /* usually 1 */
    5113      703639 :     Q = diviiexact(mulii(A1, A2), sqri(P)); if (abscmpii(Q, X) > 0) continue;
    5114         560 :     P = makepolS32(pol1, gel(S2,1));
    5115         560 :     if (ok_int(nfdisc(P), X, Xinf)) gel(v, c++) = P;
    5116             :   }
    5117        7395 :   setlg(v, c); return gc_GEN(av, v);
    5118             : }
    5119             : 
    5120             : static GEN
    5121          77 : makeS32common(GEN v, GEN X, GEN Xinf, GEN field, long s)
    5122             : {
    5123             :   GEN v1, v2;
    5124          77 :   v = extractS3cond(v, sqrti(X), field, s);
    5125          77 :   if (field)
    5126             :   {
    5127             :     GEN D, F;
    5128             :     long si;
    5129          14 :     checkfield_i(field, 3); nfcoredisc2(field, &D, &F); si = signe(D);
    5130          14 :     if ((si > 0 && s == 2) || (si < 0 && s == 0) || equali1(D)) return NULL;
    5131          14 :     v2 = mkvec(mkvecn(5, field, F, mulii(sqri(F), powiu(D, 3)), D, gen_0));
    5132          14 :     if (s != 3) v1 = v; else v1 = gel(v, si > 0 ? 2 : 1);
    5133             :   }
    5134             :   else
    5135          63 :     if (s != 3) v1 = v2 = v; else { v1 = gel(v, 1); v2 = gel(v, 2); }
    5136          77 :   v = nflist_parapply("_nflist_S32_worker", mkvec4(X, Xinf, v2, mkvecsmall(s)), v1);
    5137          77 :   return sturmseparate(gtoset_shallow(myshallowconcat1(v)), s, 6);
    5138             : }
    5139             : 
    5140             : static GEN
    5141          42 : makeS32vec(GEN X, GEN Xinf, GEN field, long s)
    5142             : {
    5143          42 :   long s3 = -1;
    5144             :   GEN v;
    5145             : 
    5146          42 :   if (s == 1) return NULL;
    5147          35 :   if (s == 0) s3 = 0; else if (s == 2) s3 = 1;
    5148          35 :   if (!(v = makeS3vec(divis(X, s? 3: 5), gen_1, NULL, s3))) return NULL;
    5149          35 :   return makeS32common(v, X, Xinf, field, s);
    5150             : }
    5151             : 
    5152             : /************************************************************************/
    5153             : /*                            C32:D4                                    */
    5154             : /************************************************************************/
    5155             : 
    5156             : static GEN
    5157          14 : makeC32D4resolvent(GEN pol, long flag) { return makeC32C4resolvent(pol, flag); }
    5158             : static int
    5159       25291 : cyc_is_trivial(GEN c) { return lg(c) == 1 || equali1(gel(c,1)); }
    5160             : 
    5161             : static GEN
    5162       25291 : C32D4pol(GEN bnf, GEN id)
    5163             : {
    5164       25291 :   GEN v, g3 = utoipos(3), bnr = bnrinitmod(bnf, id, 0, g3);
    5165             :   long l, i, c;
    5166             : 
    5167       25291 :   if (cyc_is_trivial(bnr_get_cyc(bnr))) return NULL;
    5168        2436 :   v = bnrclassfield(bnr, g3, 0, MEDDEFAULTPREC);
    5169        2436 :   if (typ(v) == t_POL) v = mkvec(v);
    5170        2436 :   l = lg(v);
    5171        5040 :   for (i = c = 1; i < l; i++)
    5172             :   {
    5173        2604 :     GEN Q = rnfequation0(bnf, gel(v, i), 0);
    5174        2604 :     Q = _nfsubfields(Q, 6);
    5175        2604 :     if (lg(Q) > 1)
    5176             :     {
    5177        1827 :       Q = polredabs(gel(Q, 1));
    5178        1827 :       if (okgal1(Q, 72)) gel(v, c++) = Q;
    5179             :     }
    5180             :   }
    5181        2436 :   if (c == 1) return NULL;
    5182         693 :   setlg(v, c); return v;
    5183             : }
    5184             : 
    5185             : static GEN
    5186       27276 : bigdisc(GEN P) { return mulii(nfdisc(P), nfdisc(_nfsubfields1(P, 2))); }
    5187             : 
    5188             : /* v,w = factorization matrices (for ideals of the same norm), do we have
    5189             :  * aut(v) = w ? */
    5190             : static int
    5191         462 : prMconj(GEN nf, GEN v, GEN w, GEN aut)
    5192             : {
    5193         462 :   GEN P = gel(v,1), E = gel(v,2), Q = gel(w,1), F = gel(w,2);
    5194         462 :   long i, j, l = lg(P);
    5195         462 :   if (lg(Q) != l) return 0;
    5196         147 :   if (!ZV_equal(ZV_sort_shallow(E), ZV_sort_shallow(F))) return 0;
    5197         126 :   Q = shallowcopy(Q);
    5198         378 :   for (i = 1; i < l; i++)
    5199             :   {
    5200         252 :     GEN pr = gel(P,i), p = pr_get_p(pr), e = gel(E,i), pi = pr_get_gen(pr);
    5201         252 :     long ep = pr_get_e(pr), fp = pr_get_f(pr);
    5202         252 :     pi = nfgaloismatrixapply(nf, aut, pi);
    5203         525 :     for (j = 1; j < l; j++)
    5204             :     {
    5205         441 :       GEN qr = gel(Q,j);
    5206         441 :       if (!qr) continue;
    5207         357 :       if (pr_get_f(qr) == fp && pr_get_e(qr) == ep
    5208         357 :           && equalii(gel(F,j), e) && equalii(pr_get_p(qr), p)
    5209         357 :           && nfval(nf, pi, qr)) { gel(Q,j) = NULL; break; }
    5210             :     }
    5211             :   }
    5212         126 :   return 1;
    5213             : }
    5214             : 
    5215             : GEN
    5216       27263 : nflist_C32D4_worker(GEN P, GEN X, GEN Xinf, GEN gs)
    5217             : {
    5218       27263 :   pari_sp av = avma;
    5219       27263 :   GEN bd = bigdisc(P), RES = cgetg(1, t_VEC), L, bnf, nf, aut;
    5220       27270 :   long s = itos(gs), lim, j;
    5221             : 
    5222       27270 :   if (abscmpii(bd, X) > 0) retgc_const(av, cgetg(1, t_VEC));
    5223        5291 :   bnf = bnfY(P); nf = bnf_get_nf(bnf); aut = cycfindaut(nf);
    5224        5292 :   lim = itos(divii(X, absi_shallow(bd)));
    5225        5292 :   L = ideallistsquare(bnf, lim);
    5226       24423 :   for (j = 1; j <= lim; j++)
    5227             :   {
    5228       19131 :     GEN v = gel(L, j);
    5229       19131 :     long k, lv = lg(v);
    5230       44548 :     for (k = 1; k < lv; k++)
    5231             :     {
    5232       25417 :       GEN R, vk = gel(v, k);
    5233             :       long m, n, c, lR;
    5234       25417 :       if (!vk || !(R = C32D4pol(bnf, vk))) continue;
    5235         693 :       lR = lg(R);
    5236        1386 :       for (m = c = 1; m < lR; m++)
    5237             :       {
    5238         693 :         GEN Z = gel(R, m);
    5239         693 :         if (ok_s(Z, s) && ok_int(nfdisc(Z), X, Xinf)) gel(R, c++) = Z;
    5240             :       }
    5241         693 :       if (c > 1) { setlg(R, c); RES = shallowconcat(RES, R); }
    5242        1050 :       for (n = k + 1; n < lv; n++)
    5243         483 :         if (gel(v,n) && prMconj(nf, vk, gel(v,n), aut)) {gel(v,n)=NULL; break;}
    5244             :     }
    5245             :   }
    5246        5292 :   return gc_GEN(av, RES);
    5247             : }
    5248             : 
    5249             : static GEN
    5250          42 : makeC32D4vec(GEN X, GEN Xinf, GEN field, long s)
    5251             : {
    5252             :   long s4;
    5253             :   GEN v;
    5254             : 
    5255          42 :   if (s == -2) s4 = -1; else if (s == 3) s4 = 2; else s4 = s;
    5256          42 :   if (field)
    5257             :   {
    5258           7 :     checkfield_i(field, 4);
    5259           7 :     if (!okgal1(field, 8) || !ok_s(field,s4)) return NULL;
    5260           7 :     v = mkvec(field);
    5261             :   }
    5262          35 :   else v = makeD4vec(X, gen_1, NULL, s4);
    5263          42 :   v = nflist_parapply("_nflist_C32D4_worker", mkvec3(X, Xinf, stoi(s)), v);
    5264          42 :   return sturmseparate(gtoset_shallow(myshallowconcat1(v)), s, 6);
    5265             : }
    5266             : 
    5267             : static GEN
    5268          49 : makeC32D4(GEN N, GEN field, long s)
    5269             : {
    5270             :   long s4, i, lv;
    5271             :   GEN v;
    5272          49 :   if (s == -2) s4 = -1; else if (s == 3) s4 = 2; else s4 = s;
    5273          49 :   if (field)
    5274             :   {
    5275           7 :     GEN D = checkfield(field, 4);
    5276           7 :     if (!okgal1(field, 8) || !ok_s(field,s4) || !dvdii(N, D)) return NULL;
    5277           7 :     v = mkvec(field);
    5278             :   }
    5279             :   else
    5280             :   {
    5281             :     long c;
    5282             :     GEN C;
    5283          42 :     v = divisors(absi(N)); lv = lg(v);
    5284         133 :     for (i = c = 1; i < lv; i++)
    5285          91 :       if ((C = makeD4(gel(v, i), NULL, s4)))
    5286             :       {
    5287          91 :         long j, cC, lC = lg(C);
    5288         105 :         for (j = cC = 1; j < lC; j++)
    5289          14 :           if (dvdii(N, bigdisc(gel(C,j)))) gel(C, cC++) = gel(C,j);
    5290          91 :         if (cC > 1) { setlg(C, cC); gel(v, c++) = C; }
    5291             :       }
    5292          42 :     if (c == 1) return NULL;
    5293           7 :     setlg(v, c); v = shallowconcat1(v);
    5294             :   }
    5295          14 :   lv = lg(v);
    5296          28 :   for (i = 1; i < lv; i++)
    5297          14 :     gel(v,i) = nflist_C32D4_worker(gel(v,i), N, N, stoi(s));
    5298          14 :   return sturmseparate(gtoset_shallow(myshallowconcat1(v)), s, 6);
    5299             : }
    5300             : 
    5301             : /************************************************************************/
    5302             : /*                         Global Programs                              */
    5303             : /************************************************************************/
    5304             : static long
    5305        2415 : grouptranslate(const char *g, long *t, int QT)
    5306             : {
    5307             :   long ell;
    5308             :   char r;
    5309             : 
    5310        2415 :   if (QT)
    5311             :   {
    5312          63 :     r = *g; ell = itos( strtoi(g + 1) );
    5313          63 :     if (ell < 0) return 0;
    5314          63 :     if (r == 'A') { *t = -2; return ell; }
    5315          35 :     if (r == 'S') { *t = -1; return ell; }
    5316          28 :     if (!strcmp(g, "C3")) { *t = -2; return ell; }
    5317             :   }
    5318        2366 :   if (!strcmp(g, "C1")) { *t = 1; return 1; }
    5319        2282 :   if (!strcmp(g, "C2") || !strcmp(g, "D2")) { *t = 1; return 2; }
    5320        2135 :   if (!strcmp(g, "C3")) { *t = 1; return 3; }
    5321        2044 :   if (!strcmp(g, "S3") || !strcmp(g,"D3")) { *t = 2; return 3; }
    5322        1918 :   if (!strcmp(g, "C4")) { *t = 1; return 4; }
    5323        1778 :   if (!strcmp(g, "V4")) { *t = 2; return 4; }
    5324        1687 :   if (!strcmp(g, "D4")) { *t = 3; return 4; }
    5325        1575 :   if (!strcmp(g, "A4")) { *t = 4; return 4; }
    5326        1477 :   if (!strcmp(g, "S4")) { *t = 5; return 4; }
    5327        1358 :   if (!strcmp(g, "C5")) { *t = 1; return 5; }
    5328        1267 :   if (!strcmp(g, "D5"))  { *t = 2; return 5; }
    5329        1155 :   if (!strcmp(g, "F5") || !strcmp(g, "M20"))  { *t = 3; return 5; }
    5330        1057 :   if (!strcmp(g, "A5")) { *t = 4; return 5; }
    5331        1001 :   if (!strcmp(g, "A5cond")) { *t = 9; return 5; }
    5332         959 :   if (!strcmp(g, "C6")) { *t = 1; return 6; }
    5333         840 :   if (!strcmp(g, "D6")) { *t = 2; return 6; }
    5334         840 :   if (!strcmp(g, "C7")) { *t = 1; return 7; }
    5335         756 :   if (!strcmp(g, "D7")) { *t = 2; return 7; }
    5336         665 :   if (!strcmp(g, "M21")) { *t = 3; return 7; }
    5337         588 :   if (!strcmp(g, "M42")) { *t = 4; return 7; }
    5338         518 :   if (!strcmp(g, "C9")) { *t = 1; return 9; }
    5339         413 :   if (!strcmp(g, "D9")) { *t = 3; return 9; }
    5340         301 :   if (QT)
    5341             :   {
    5342           0 :     if (!strcmp(g, "C8")) { *t = 1; return 8; }
    5343           0 :     if (!strcmp(g, "D8")) { *t = 2; return 8; }
    5344           0 :     if (!strcmp(g, "C10")) { *t = 1; return 10; }
    5345           0 :     if (!strcmp(g, "D10")) { *t = 3; return 10; }
    5346           0 :     if (!strcmp(g, "C11")) { *t = 1; return 11; }
    5347           0 :     if (!strcmp(g, "D11")) { *t = 2; return 11; }
    5348             :   }
    5349         301 :   r = *g; ell = itos( strtoi(g + 1) );
    5350         301 :   if (ell >= 8 && (r == 'C' || r == 'D'))
    5351             :   {
    5352         294 :     GEN fa = factoru(ell), P = gel(fa, 1), E = gel(fa, 2);
    5353         294 :     switch(lg(P))
    5354             :     {
    5355         189 :       case 2:
    5356         189 :         if (E[1] == 1) { *t = (r == 'C') ? 1: 2; return ell; }
    5357           0 :         break;
    5358         105 :       case 3:
    5359         105 :         if (E[1] == 1 && E[2] == 1 && r == 'C') { *t = P[2]; return P[1]; }
    5360           0 :         break;
    5361             :     }
    5362             :   }
    5363           7 :   *t = 0; return 0;
    5364             : }
    5365             : static GEN
    5366         133 : uispq(ulong d)
    5367             : {
    5368         133 :   GEN fa = factoru(d), E = gel(fa, 2);
    5369         133 :   return lg(E) == 3 && E[1] == 1 && E[2] == 1 ? gel(fa, 1) : NULL;
    5370             : }
    5371             : 
    5372             : static long
    5373        6209 : group_nTk(GEN g, long *t, int QT)
    5374             : {
    5375        6209 :   long L[] = { 0, /* https://oeis.org/A002106 */
    5376             :   1,1,2,5,5,16,7,50,34,45,8,301,9,63,104,1954,10,
    5377             :   983,8,1117,164,59,7,25000,211,96,2392,1854,8,5712,
    5378             :   12,2801324,162,115,407,121279,11,76,306,315842,10,
    5379             :   9491,10,2113,10923,56,6 };
    5380        6209 :   long N = numberof(L), n, k;
    5381             : 
    5382        6209 :   if (lg(g) != 3 || !RgV_is_ZV(g)) { *t = 0; return 0; }
    5383        6209 :   n = itos(gel(g,1)); if (n <= 0) return 0;
    5384        6209 :   if (n >= N) pari_err_IMPL(stack_sprintf("group nTk with n > %ld", N-1));
    5385        6209 :   *t = k = itos(gel(g,2));
    5386        6209 :   if (k <= 0 || k > L[n])
    5387             :   {
    5388             :     char *s;
    5389          14 :     s = stack_sprintf("incorrect group %ldTk with k = %ld not in [1,%ld]",
    5390             :                       n, k, L[n]);
    5391          14 :     pari_err(e_MISC, s);
    5392             :   }
    5393        6195 :   if (!QT)
    5394             :   {
    5395             :     GEN P;
    5396        1365 :     if (n <= 9)
    5397             :     {
    5398        1330 :       long v[] = { 0, 1, 1, 2, 5, 4, 13, 4, 0, 3 };
    5399        1330 :       return k <= v[n]? n: 0;
    5400             :     }
    5401          35 :     if (uisprime(n) && k <= 2) return n;
    5402          28 :     if (k != 1) return 0;
    5403          21 :     if (!(P = uispq(n))) return 0;
    5404           7 :     *t = P[2]; return P[1];
    5405             :   }
    5406        4830 :   if (n <= 2) *t = -2; /* An */
    5407        4802 :   else if (k == L[n]) *t = -1; /* Sn */
    5408        4669 :   else if (k == L[n]-1) *t = -2; /* An */
    5409        4830 :   return n;
    5410             : }
    5411             : 
    5412             : static int
    5413        1078 : okfield(GEN F) { return typ(F) == t_POL && RgX_is_ZX(F) && ZX_is_irred(F); }
    5414             : static GEN
    5415        2065 : nfmakenum(long n, long t, GEN N, GEN field, long s)
    5416             : {
    5417        2065 :   GEN v = NULL;
    5418        2065 :   switch(100 * n + t)
    5419             :   {
    5420          35 :     case 101: return makeC1(N, field, s);
    5421         105 :     case 201: return makeC2(N, field, s);
    5422          77 :     case 301: return makeC3(N, field, s);
    5423          56 :     case 302: return makeDL(3, N, field, s);
    5424         196 :     case 401: return makeC4(N, field, s);
    5425          49 :     case 402: return makeV4(N, field, s);
    5426          63 :     case 403: return makeD4(N, field, s);
    5427          49 :     case 404: return makeA4(N, field, s);
    5428          77 :     case 405: return makeS4(N, field, s);
    5429          63 :     case 501: return makeC5(N, field, s);
    5430          63 :     case 502: return makeDL(5, N, field, s);
    5431          56 :     case 503: return makeMgen(5, 4, N, field, s); /*F5*/
    5432          14 :     case 504: return makeA5(N, s);
    5433           7 :     case 509: return makeA5cond(N, s);
    5434         105 :     case 601: return makeC6(N, field, s);
    5435          56 :     case 602: return makeS36(N, field, s);
    5436          56 :     case 603: return makeD612(N, field, s);
    5437          49 :     case 604: return makeA46(N, field, s);
    5438          49 :     case 605: return makeS3C3(N, field, s);
    5439          49 :     case 606: return makeA462(N, field, s);
    5440          49 :     case 607: return makeS46P(N, field, s);
    5441          56 :     case 608: return makeS46M(N, field, s);
    5442          49 :     case 609: return makeS32(N, field, s);
    5443          56 :     case 610: return makeC32C4(N, field, s);
    5444          49 :     case 611: return makeS462(N, field, s);
    5445           7 :     case 612: return makeA56(N, s);
    5446          49 :     case 613: return makeC32D4(N, field, s);
    5447          49 :     case 701: return makeCL(7, N, field, s);
    5448          49 :     case 702: return makeDL(7, N, field, s);
    5449          35 :     case 703: return makeMgen(7, 3, N, field, s); /*M21*/
    5450          35 :     case 704: return makeMgen(7, 6, N, field, s);
    5451          56 :     case 901: return makeC9(N, field, s);
    5452          49 :     case 902: return makeC3C3(N, field, s);
    5453          63 :     case 903: return makeD9(N, field, s);
    5454             :   }
    5455         140 :   if (!v && uisprime(n)) switch(t)
    5456             :   {
    5457          56 :     case 1: return makeCL(n, N, field, s);
    5458          35 :     case 2: return makeDL(n, N, field, s);
    5459          49 :     default: return makeCpq(n, t, N, field, s);
    5460             :   }
    5461             :   return NULL;/*LCOV_EXCL_LINE*/
    5462             : }
    5463             : /* deg(pol) < 8 */
    5464             : static GEN
    5465         441 : nfresolvent_small(GEN pol, long flag)
    5466             : {
    5467         441 :   long deg = degpol(pol), dP, s;
    5468             :   GEN G;
    5469         441 :   if (deg == 1) return makeC1resolvent(flag);
    5470         420 :   if (deg == 2) return makeC2resolvent(pol, flag);
    5471         406 :   G = polgalois0(pol, 1, DEFAULTPREC);
    5472         406 :   dP = itos(gel(G,1));
    5473         420 :   if (deg == 3) return dP == 3? makeC3resolvent(pol, flag)
    5474          42 :                               : makeS3resolvent(pol, flag);
    5475         378 :   s = itos(gel(G,2));
    5476         378 :   if (deg == 4)
    5477             :   {
    5478          91 :     if (dP == 4) return s == -1? makeC4resolvent(pol, flag)
    5479          49 :                                : makeV4resolvent(pol, flag);
    5480          42 :     if (dP == 8) return condrelresolvent(pol, 2, flag); /*D4*/
    5481          28 :     return makeA4S4resolvent(pol, flag);
    5482             :   }
    5483         301 :   if (deg == 5)
    5484             :   {
    5485          56 :     if (dP == 5)  return makeCLresolvent(5, pol, flag);
    5486          42 :     if (dP == 10) return makeDLresolvent(5, pol, flag);
    5487          28 :     if (dP == 20) return makeMgenresolvent(5, 4, pol, flag); /*F5*/
    5488          14 :     if (dP == 60) return makeA5resolvent(pol, flag);
    5489             :   }
    5490         252 :   if (deg == 6)
    5491             :   {
    5492         196 :     if (dP == 6 && s == -1)
    5493             :     { /* works both with new_galois_format set or unset */
    5494          49 :       long k = itos(gel(G,3));
    5495          28 :       return k == 1? makeC6resolvent(pol, flag)
    5496          77 :                    : makeS36resolvent(pol, flag);
    5497             :     }
    5498         161 :     if (dP == 12) return s == -1? makeD612resolvent(pol, flag)
    5499          42 :                                 : condrelresolvent(pol,3,flag); /*A46*/
    5500         119 :     if (dP == 18) return condrelresolvent(pol,2,flag); /*S3C3*/
    5501         105 :     if (dP == 24) return condrelresolvent(pol,3,flag); /*S46P,S46M,A462*/
    5502          77 :     if (dP == 36) return (s == 1)? makeC32C4resolvent(pol, flag)
    5503          42 :                                  : makeS32resolvent(pol, flag);
    5504          35 :     if (dP == 48) return condrelresolvent(pol,3,flag); /*S462*/
    5505          21 :     if (dP == 60) return makeA56resolvent(pol,flag);
    5506          14 :     if (dP == 72) return makeC32D4resolvent(pol, flag);
    5507             :   }
    5508          56 :   if (deg == 7)
    5509             :   {
    5510          49 :     if (dP == 7)  return makeCLresolvent(7, pol, flag);
    5511          35 :     if (dP == 14) return makeDLresolvent(7, pol, flag);
    5512          21 :     if (dP == 21) return makeMgenresolvent(7, 3, pol, flag); /*M21*/
    5513          14 :     if (dP == 42) return makeMgenresolvent(7, 6, pol, flag); /*M42*/
    5514             :   }
    5515           7 :   return gen_0;
    5516             : }
    5517             : 
    5518             : static GEN
    5519         553 : nfresolvent_i(GEN pol, long flag)
    5520             : {
    5521             :   long d;
    5522             :   GEN G;
    5523             : 
    5524         553 :   if (!okfield(pol)) pari_err_TYPE("nfresolvent", pol);
    5525         553 :   if (flag < 0 || flag > 3) pari_err_FLAG("nfresolvent");
    5526         553 :   d = degpol(pol);
    5527         553 :   if (d < 8) return nfresolvent_small(pol, flag);
    5528         112 :   if ((G = uispq(d))) return makeCpqresolvent(G[2], G[1], pol, flag);
    5529          84 :   if (d != 9 && !uisprime(d)) return gen_0;
    5530          84 :   G = galoisinit(pol, NULL);
    5531          84 :   if (typ(G) != t_INT)
    5532             :   {
    5533          56 :     if (d == 9)
    5534             :     {
    5535          35 :       long n = lg(gal_get_gen(G))-1;
    5536          14 :       return n == 1? condrelresolvent(pol,3,flag) /*C9*/
    5537          49 :                    : makeC3C3resolvent(pol, flag); /*C3xC3*/
    5538             :     }
    5539          21 :     return makeCLresolvent(d, pol, flag);
    5540             :   }
    5541          28 :   G = galoissplittinginit(pol, utoipos(2*d));
    5542          28 :   if (gal_get_order(G) != 2*d) return gen_0;
    5543          21 :   return d == 9? makeD9resolvent(G, flag): makeDLresolvent(d, pol, flag);
    5544             : }
    5545             : GEN
    5546         553 : nfresolvent(GEN pol, long flag)
    5547         553 : { pari_sp av = avma; return gc_GEN(av, nfresolvent_i(pol, flag)); }
    5548             : 
    5549             : /* 1 <= Xinf <= X */
    5550             : static GEN
    5551        2030 : nfmakevecnum(long n, long t, GEN X, GEN Xinf, GEN field, long s)
    5552             : {
    5553        2030 :   switch(n * 100 + t)
    5554             :   {
    5555          28 :     case 101: return makeC1vec(Xinf, field, s);
    5556          56 :     case 201: return makeC2vec(X, Xinf, field, s);
    5557          77 :     case 301: return makeC3vec(X, Xinf, field, s);
    5558          49 :     case 302: return makeS3vec(X, Xinf, field, s);
    5559         105 :     case 401: return makeC4vec(X, Xinf, field, s);
    5560          42 :     case 402: return makeV4vec(X, Xinf, field, s);
    5561          49 :     case 403: return makeD4vec(X, Xinf, field, s);
    5562          49 :     case 404: return makeA4S4vec(1, X, Xinf, field, s);
    5563          42 :     case 405: return makeA4S4vec(0, X, Xinf, field, s);
    5564          77 :     case 501: return makeC5vec(X, Xinf, field, s);
    5565          49 :     case 502: return makeDLvec(5, X, Xinf, field, s);
    5566          63 :     case 503: return makeMgenvec(5, 4, X, Xinf, field, s); /*F5*/
    5567          42 :     case 504: return makeA5vec(X, Xinf, field, s);
    5568          35 :     case 509: return makeA5condvec(X, Xinf, field, s);
    5569          91 :     case 601: return makeC6vec(X, Xinf, field, s);
    5570          49 :     case 602: return makeS36vec(X, Xinf, field, s);
    5571          49 :     case 603: return makeD612vec(X, Xinf, field, s);
    5572          42 :     case 604: return makeA46S46Pvec(12, X, Xinf, field, s);/*A46S*/
    5573          42 :     case 605: return makeS3C3vec(X, Xinf, field, s);
    5574          49 :     case 606: return makeA462vec(X, Xinf, field, s);
    5575          49 :     case 607: return makeA46S46Pvec(24, X, Xinf, field, s); /*S46P*/
    5576          42 :     case 608: return makeS46Mvec(X, Xinf, field, s);
    5577          42 :     case 609: return makeS32vec(X, Xinf, field, s);
    5578          49 :     case 610: return makeC32C4vec(X, Xinf, field, s);
    5579          56 :     case 611: return makeS462vec(X, Xinf, field, s);
    5580          49 :     case 612: return makeA56vec(X, Xinf, s);
    5581          42 :     case 613: return makeC32D4vec(X, Xinf, field, s);
    5582          35 :     case 701: return makeCLvec(7, X, Xinf, field, s);
    5583          42 :     case 702: return makeDLvec(7, X, Xinf, field, s);
    5584          42 :     case 703: return makeMgenvec(7, 3, X, Xinf, field, s); /*M21*/
    5585          35 :     case 704: return makeMgenvec(7, 6, X, Xinf, field, s); /*M41*/
    5586          49 :     case 901: return makeC9vec(X, Xinf, field, s);
    5587          49 :     case 902: return makeC3C3vec(X, Xinf, field, s);
    5588          49 :     case 903: return makeD9vec(X, Xinf, field, s);
    5589             :   }
    5590         315 :   if (uisprime(n)) switch(t)
    5591             :   {
    5592         203 :     case 1: return makeCLvec(n, X, Xinf, field, s);
    5593          49 :     case 2: return makeDLvec(n, X, Xinf, field, s);
    5594          63 :     default: return makeCpqvec(n, t, X, Xinf, field, s);
    5595             :   }
    5596             :   return NULL;/*LCOV_EXCL_LINE*/
    5597             : }
    5598             : 
    5599             : /* s > -2 */
    5600             : static GEN
    5601          14 : nfmakesomehard(long n, long t, long s)
    5602             : {
    5603          14 :   pari_sp av = avma;
    5604             :   long i;
    5605         168 :   for (i = 1;; i++, set_avma(av))
    5606         154 :   {
    5607         168 :     GEN v = nfmakevecnum(n, t, int2n(18 + 2*i), gen_1, NULL, s);
    5608         168 :     if (v && lg(v) > 2) return v;
    5609             :   }
    5610             : }
    5611             : static long
    5612         105 : minlim(GEN v)
    5613             : {
    5614         105 :   long i, m = LONG_MAX;
    5615         105 :   if (!v) return m;
    5616         392 :   for (i = lg(v)-1; i; i--) if (v[i] && m > v[i]) m = v[i];
    5617         105 :   return m;
    5618             : }
    5619             : static GEN
    5620         168 : nfmakesome(long n, long t, long s)
    5621             : {
    5622         168 :   GEN v = NULL;
    5623         168 :   long lim, flag = 0;
    5624         168 :   switch(n * 100 + t)
    5625             :   {
    5626           7 :     case 101: v = mkvecsmall(1); break;
    5627           7 :     case 201: v = mkvecsmall2(33, 24); break;
    5628           7 :     case 301: v = mkvecsmall2(3969, 0); break;
    5629          14 :     case 302: v = mkvecsmall2(568, 108); break;
    5630           7 :     case 401: v = mkvecsmall3(35152, 0, 44217); break;
    5631           7 :     case 402: v = mkvecsmall3(14400, 0, 1225); break;
    5632           7 :     case 403: v = mkvecsmall3(5125, 1375, 549); break;
    5633           7 :     case 404: v = mkvecsmall3(270400, 0, 29241); break;
    5634           7 :     case 405: v = mkvecsmall3(8468, 976, 1076); break;
    5635           7 :     case 501: v = mkvecsmall3(1073283121, 0, 0); break;
    5636           7 :     case 502: v = mkvecsmall3(4330561, 0, 51529); break;
    5637          14 :     case 503: v = mkvecsmall3(LONG_MAX, 0, 253125); break;
    5638          21 :     case 504: v = mkvecsmall3(11812969, 0, 149769); break;
    5639          21 :     case 509: v = mkvecsmall3(5105, 0, 992); break;
    5640           0 :     case 601: v = mkvecsmall4(4148928, 0, 0, 2250423); break;
    5641           0 :     case 602: v = mkvecsmall4(32166277, 0, 0, 273375); break;
    5642           0 :     case 603: v = mkvecsmall4(9045125, 0, 242000, 86528); break;
    5643           0 :     case 604: v = mkvecsmall4(125238481, 0, 4439449, 0); break;
    5644           0 :     case 605: v = mkvecsmall4(7442000, 0, 0, 143883); break;
    5645           0 :     case 606: v = mkvecsmall4(2115281, 419904, 373977, 0); break;
    5646           0 :     case 607: v = mkvecsmall4(12730624, 0, 118336, 0); break;
    5647           0 :     case 608: v = mkvecsmall4(183250432, 0, 440711081, 13144256); break;
    5648           0 :     case 609: v = mkvecsmall4(LONG_MAX, 0, 1382400, 1494108); break;
    5649           0 :     case 610: v = mkvecsmall4(765905625, 0, 4950625, 0); break;
    5650           0 :     case 611: v = mkvecsmall4(5695040, 941872, 57661, 37479); break;
    5651          21 :     case 612: v = mkvecsmall4(185313769, 0, 1907161, 0); break;
    5652           0 :     case 613: v = mkvecsmall4(LONG_MAX, 221875, 87625, 44496); break;
    5653           0 :     case 701: v = mkvecsmall4(LONG_MAX, 0, 0, 0); break;
    5654           0 :     case 702: v = mkvecsmall4(LONG_MAX, 0, 0, 80062991); break;
    5655           0 :     case 703: v = mkvecsmall4(LONG_MAX, 0, 0, 0); break;
    5656           0 :     case 704: v = mkvecsmall4(LONG_MAX, 0, 0, LONG_MAX); break;
    5657           0 :     case 901: v = mkvecsmall5(LONG_MAX, 0, 0, 0, 0); break;
    5658           0 :     case 902: v = mkvecsmall5(LONG_MAX, 0, 0, 0, 0); break;
    5659           0 :     case 903: v = mkvecsmall5(LONG_MAX, 0, 0, 0, LONG_MAX); break;
    5660             :   }
    5661         168 :   if (!v) flag = uisprime(n) && t <= 2? t: 0;
    5662         168 :   if (!v && t >= 5) return makeCpqsome(t, n, s);
    5663         168 :   if (s == -2)
    5664             :   {
    5665          42 :     long i, l = (n >> 1) + 2;
    5666          42 :     GEN W = cgetg(l, t_VEC);
    5667         189 :     for (i = 1; i < l; i++)
    5668             :     {
    5669         147 :       GEN w = NULL;
    5670         147 :       if (!v)
    5671          42 :       { if (i == 1 || (i == l-1 && flag == 2)) w = nfmakesomehard(n, t, i-1); }
    5672         105 :       else if (v[i] == LONG_MAX)
    5673           7 :         w = nfmakesomehard(n, t, i-1);
    5674          98 :       else if (v[i])
    5675          63 :         w = nfmakevecnum(n, t, utoipos(v[i]), gen_1, NULL, i-1);
    5676         147 :       gel(W, i) = w? w: cgetg(1, t_VEC);
    5677             :     }
    5678          42 :     return W;
    5679             :   }
    5680         126 :   else if (s == -1)
    5681         105 :     lim = minlim(v);
    5682             :   else
    5683             :   {
    5684          21 :     lim = v[s + 1];
    5685          21 :     if (!lim) return cgetg(1, t_VEC);
    5686             :   }
    5687         112 :   if (lim == LONG_MAX) return nfmakesomehard(n, t, s);
    5688         112 :   return nfmakevecnum(n, t, utoipos(lim), gen_1, NULL, s);
    5689             : }
    5690             : 
    5691             : GEN
    5692        8624 : nflist(GEN GP, GEN N, long s, GEN field)
    5693             : {
    5694        8624 :   pari_sp av = avma;
    5695             :   GEN v, X, Xinf;
    5696        8624 :   long n = 0, t = 0, tp = typ(GP);
    5697        8624 :   long QT = N && typ(N) == t_POL;
    5698             : 
    5699        8624 :   if (s < -2) pari_err_DOMAIN("nflist", "s", "<", gen_m2, stoi(s));
    5700        8624 :   if (field && !okfield(field)) pari_err_TYPE("nflist", field);
    5701        8624 :   switch(tp)
    5702             :   {
    5703        2415 :     case t_STR: n = grouptranslate(GSTR(GP), &t, QT); break;
    5704        6209 :     case t_VEC: n = group_nTk(GP, &t, QT); break;
    5705             :   }
    5706        8610 :   if (!n)
    5707             :   {
    5708          35 :     const char *s =
    5709             :     "unsupported group (%Ps). Use one of\n\
    5710             :   \"C1\"=[1,1];\n\
    5711             :   \"C2\"=[2,1];\n\
    5712             :   \"C3\"=[3,1], \"S3\"=[3,2];\n\
    5713             :   \"C4\"=[4,1], \"V4\"=[4,2], \"D4\"=[4,3], \"A4\"=[4,4], \"S4\"=[4,5];\n\
    5714             :   \"C5\"=[5,1], \"D5\"=[5,2], \"F5\"=\"M20\"=[5,3], \"A5\"=[5,4];\n\
    5715             :   \"C6\"=[6,1], \"D6\"=[6,2], [6,3], [6,4],..., [6,13];\n\
    5716             :   \"C7\"=[7,1], \"D7\"=[7,2], \"M21\"=[7,3], \"M42\"=[7,4];\n\
    5717             :   \"C9\"=[9,1], [9,2], \"D9\"=[9,3].\"\n\
    5718             :   Also supported are \"Cp\"=[p,1] and \"Dp\"=[p,2] for any odd prime p,\n\
    5719             :   and \"Cn\"=[n,1] when n is a product of two distinct primes";
    5720          35 :     pari_err(e_MISC, s, GP);
    5721             :   }
    5722        8575 :   if (QT) return gc_GEN(av, nflistQT(n, t, varn(N)));
    5723        3682 :   if (s > ((t >= 5 ? n*t : n) >> 1)) return cgetg(1, t_VEC);
    5724        3647 :   if (!N) return gc_GEN(av, nfmakesome(n, t, s));
    5725        3479 :   switch(typ(N))
    5726             :   {
    5727        1883 :     case t_INT: X = Xinf = N; break;
    5728        1596 :     case t_VEC: case t_COL:
    5729        1596 :       if (lg(N) == 3) { Xinf = gel(N,1); X = gel(N,2); break; }
    5730           7 :     default: pari_err_TYPE("nflist", N);
    5731             :       Xinf = X = NULL;/*LCOV_EXCL_LINE*/
    5732             :   }
    5733        3472 :   if (typ(X) != t_INT)
    5734             :   {
    5735         126 :     X = gfloor(X);
    5736         126 :     if (typ(X) != t_INT) pari_err_TYPE("nflist", N);
    5737             :   }
    5738        3472 :   if (typ(Xinf) != t_INT)
    5739             :   {
    5740           7 :     Xinf = gceil(Xinf);
    5741           7 :     if (typ(Xinf) != t_INT) pari_err_TYPE("nflist", N);
    5742             :   }
    5743        3472 :   if (signe(Xinf) <= 0)
    5744             :   {
    5745          28 :     if (signe(Xinf) < 0) pari_err_DOMAIN("nflist", "Xinf", "<=", gen_0, Xinf);
    5746          14 :     Xinf = gen_1;
    5747             :   }
    5748        3458 :   if (signe(X) < 0) pari_err_DOMAIN("nflist", "X", "<=", gen_0, X);
    5749        3451 :   switch(cmpii(Xinf, X))
    5750             :   {
    5751          14 :     case 1: v = NULL; break;
    5752        1876 :     case 0: v = nfmakenum(n, t, X, field, s); break;
    5753        1561 :     default: v = nfmakevecnum(n, t, X, Xinf, field, s);
    5754             :   }
    5755        3444 :   if (!v)
    5756             :   {
    5757        1064 :     set_avma(av); if (s != -2) return cgetg(1,t_VEC);
    5758         448 :     retconst_vec((n>>1) + 1, cgetg(1,t_VEC));
    5759             :   }
    5760        2380 :   return gc_GEN(av, v);
    5761             : }
    5762             : 
    5763             : /*****************************************************************/
    5764             : /*                          Polsubcyclo                          */
    5765             : /*****************************************************************/
    5766             : /* auxiliary functions assume that trivial impossibilities for s or n
    5767             :  * are already handled in caller */
    5768             : static GEN
    5769           0 : polsubcycloC2(GEN n, long s)
    5770             : {
    5771           0 :   GEN V = divisorsdisc(n, s), W;
    5772           0 :   long l = lg(V), i;
    5773           0 :   W = cgetg(l, t_VEC);
    5774           0 :   for (i = 1; i < l; i++) gel(W, i) = quadpoly_i(gel(V, i));
    5775           0 :   return W;
    5776             : }
    5777             : static GEN
    5778           0 : polsubcycloC2_i(GEN n, long s)
    5779             : {
    5780             :   long l, i;
    5781             :   GEN V;
    5782             :   int p, m;
    5783           0 :   if (typ(n) == t_VEC)
    5784             :   {
    5785           0 :     fa_is_fundamental_pm(gel(n,1), gel(n,2), s, &p, &m);
    5786           0 :     n = gel(n,1);
    5787             :   }
    5788             :   else
    5789           0 :     is_fundamental_pm(n, s, &p, &m);
    5790           0 :   if (!(V = fund_pm(n, p, m))) return NULL;
    5791           0 :   l = lg(V);
    5792           0 :   for (i = 1; i < l; i++) gel(V, i) = quadpoly_i(gel(V, i));
    5793           0 :   return V;
    5794             : }
    5795             : 
    5796             : static GEN
    5797           7 : polsubcycloC3_i(GEN n)
    5798           7 : { GEN P; return checkcondC3(n, &P)? makeC3_i(typ(n) == t_VEC? gel(n,1): n, P)
    5799           7 :                                   : NULL; }
    5800             : /* Cyclic cubic subfields of Q(zeta_n). */
    5801             : static GEN
    5802           7 : polsubcycloC3(GEN n)
    5803             : {
    5804             :   long i, l, c;
    5805           7 :   GEN D = divisors_factored(n);
    5806           7 :   l = lg(D);
    5807          14 :   for (i = 2, c = 1; i < l; i++)
    5808             :   {
    5809           7 :     GEN v = polsubcycloC3_i(gel(D,i));
    5810           7 :     if (v) gel(D,c++) = v;
    5811             :   }
    5812           7 :   setlg(D, c); return myshallowconcat1(D);
    5813             : }
    5814             : 
    5815             : static GEN
    5816           7 : makeV4pairssimple(GEN D, GEN P, GEN f)
    5817             : {
    5818           7 :   long l = lg(D), n = l-1, i, j, c;
    5819           7 :   GEN R = cgetg((n-1) * n / 2 + 1, t_VEC);
    5820           7 :   for (i = c = 1; i < n; i++)
    5821             :   {
    5822           0 :     GEN Di = gel(D,i);
    5823           0 :     for (j = i + 1; j < l; j++)
    5824             :     {
    5825           0 :       if (f && !equalii(lcmii(Di, gel(D,j)), f)) continue;
    5826           0 :       gel(R, c++) = polcompositum0(gel(P,i), gel(P,j), 2);
    5827             :     }
    5828             :   }
    5829           7 :   setlg(R,c); return R;
    5830             : }
    5831             : static GEN
    5832          21 : makeV4pairs(GEN D, GEN P, GEN f)
    5833             : {
    5834          21 :   long l = lg(D), n = l-1, i, j, c;
    5835          21 :   GEN V = cgetg(l, t_VEC), R = cgetg((n-1) * n / 2 + 1, t_VEC);
    5836             : 
    5837         168 :   for (i = 1; i < l; i++) gel(V, i) = const_vecsmall(n, 1);
    5838         147 :   for (i = c = 1; i < n; i++)
    5839             :   {
    5840         126 :     GEN C = gel(V,i);
    5841         567 :     for (j = i + 1; j < l; j++)
    5842         441 :       if (C[j])
    5843             :       { /* Di, Dj fundamental discs */
    5844         189 :         GEN d, Di = gel(D,i), Dj = gel(D,j), g = gcdii(Di, Dj);
    5845             :         long k;
    5846         189 :         if (!is_pm1(g)) { Di = diviiexact(Di, g); Dj = diviiexact(Dj, g); }
    5847         189 :         d = mulii(Di, Dj); if (f && !equalii(f, mulii(d, g))) continue;
    5848         126 :         if (Mod4(d) > 1) d = shifti(d, 2);
    5849         126 :         k = vecsearch(D, d, NULL); /* d = coredisc(Di*Dj), j < k */
    5850         126 :         C[k] = gel(V, j)[k] = 0;
    5851         126 :         gel(R, c++) = polcompositum0(gel(P,i), gel(P,j), 2);
    5852             :       }
    5853             :   }
    5854          21 :   setlg(R, c); return R;
    5855             : }
    5856             : static GEN
    5857          28 : polsubcycloV4_i(GEN V, long s, GEN n)
    5858             : {
    5859          28 :   long i, l = lg(V);
    5860          28 :   GEN P = cgetg(l, t_VEC);
    5861          28 :   if (s <= 0) ZV_sort_inplace(V); /* for vecsearch */
    5862         175 :   for (i = 1; i < l; i++) gel(P,i) = quadpoly_i(gel(V,i));
    5863          28 :   return (s <= 0)? makeV4pairs(V, P, n): makeV4pairssimple(V, P, n);
    5864             : }
    5865             : 
    5866             : static GEN
    5867           7 : polsubcycloC5(GEN n)
    5868             : {
    5869           7 :   GEN v, D = divisors_factored(n), T = C5bnf();
    5870           7 :   long i, c, l = lg(D);
    5871          14 :   for (i = 2, c = 1; i < l; i++)
    5872           7 :     if ((v = polsubcycloC5_i(gel(D,i), T))) gel(D,c++) = v;
    5873           7 :   setlg(D, c); return myshallowconcat1(D);
    5874             : }
    5875             : 
    5876             : /* ell odd prime */
    5877             : static GEN
    5878           0 : makeCLall(long ell, GEN F)
    5879             : {
    5880           0 :   GEN D = divisors(F);
    5881           0 :   long i, l = lg(D);
    5882           0 :   for (i = 1; i < l; i++) gel(D,i) = makeCL_f(ell, gel(D,i));
    5883           0 :   return shallowconcat1(D);
    5884             : }
    5885             : 
    5886             : static GEN
    5887           0 : polsubcycloC6(GEN n, long s)
    5888             : {
    5889           0 :   GEN v3 = polsubcycloC3(n), v2, R;
    5890           0 :   long n3 = lg(v3) - 1, n2, i, j, c;
    5891           0 :   if (!n3) return v3;
    5892           0 :   v2 = polsubcycloC2(n, s); n2 = lg(v2) - 1;
    5893           0 :   if (!n2) return NULL;
    5894           0 :   R = cgetg(n2 * n3 + 1, t_VEC);
    5895           0 :   for (i = c = 1; i <= n3; i++)
    5896             :   {
    5897           0 :     GEN p3 = gel(v3, i);
    5898           0 :     for (j = 1; j <= n2; j++)
    5899           0 :       gel(R, c++) = polcompositum0(p3, gel(v2,j), 2);
    5900             :   }
    5901           0 :   return R;
    5902             : }
    5903             : 
    5904             : static GEN
    5905           0 : polsubcycloC6_i(GEN n, long s)
    5906             : {
    5907           0 :   GEN D = divisors_factored(n), R;
    5908           0 :   long l = lg(D), i, j, c, L = 2 * (l-1) * omega(n);
    5909             : 
    5910           0 :   if (typ(n) == t_VEC) n = gel(n,1);
    5911           0 :   R = cgetg(L + 1, t_VEC); c = 1;
    5912           0 :   for (i = 2; i < l; i++)
    5913             :   {
    5914           0 :     GEN d = gel(D, i), V2 = polsubcycloC2_i(d, s);
    5915             :     long l2;
    5916           0 :     if (!V2) continue;
    5917           0 :     l2 = lg(V2);
    5918           0 :     if (typ(d) == t_VEC) d = gel(d,1);
    5919           0 :     for (j = 1; j < l; j++)
    5920             :     {
    5921           0 :       GEN V3, e = gel(D, j);
    5922             :       long l3, i3;
    5923           0 :       if (!equalii(lcmii(d, typ(e) == t_VEC? gel(e,1): e), n)) continue;
    5924           0 :       V3 = polsubcycloC3_i(e); if (!V3) continue;
    5925           0 :       l3 = lg(V3);
    5926           0 :       for (i3 = 1; i3 < l3; i3++)
    5927             :       {
    5928           0 :         GEN p3 = gel(V3, i3);
    5929             :         long i2;
    5930           0 :         for (i2 = 1; i2 < l2; i2++)
    5931           0 :           gel(R, c++) = polcompositum0(p3, gel(V2,i2), 2);
    5932             :       }
    5933             :     }
    5934             :   }
    5935           0 :   setlg(R, c); return R;
    5936             : }
    5937             : 
    5938             : /* fli = 1 for conductor n, else all subfields of Q(zeta_n) */
    5939             : static GEN
    5940         154 : polsubcyclofast_i(GEN n, long ell, long s, long fli)
    5941             : {
    5942         154 :   GEN N, fa = check_arith_pos(n, "polsubcyclofast");
    5943             : 
    5944         154 :   if (fa && typ(n) != t_VEC) n = mkvec2(factorback(fa), fa);
    5945             :   /* n either t_INT or [N, factor(N)] */
    5946         154 :   if (ell <= 0 && ell != -4)
    5947           0 :     pari_err_DOMAIN("polsubcyclofast", "d", "<=", gen_0, stoi(ell));
    5948             :   /* translate wrt r2 for compatibility with nflist functions */
    5949         154 :   if (!s) s = odd(ell)? 0: -1;
    5950          70 :   else if (s == 1) s = 0;
    5951          35 :   else if (s ==-1)
    5952             :   {
    5953          35 :     if (odd(ell)) return NULL;
    5954          35 :     s = labs(ell) >> 1;
    5955             :   }
    5956           0 :   else pari_err_FLAG("polsubcyclo");
    5957         154 :   N = fa? gel(n, 1): n;
    5958         154 :   if (Mod4(N) == 2)
    5959             :   {
    5960           0 :     if (fli) return NULL;
    5961           0 :     N = shifti(N, -1);
    5962           0 :     if (fa)
    5963             :     { /* remove 2^1 */
    5964           0 :       GEN P = vecsplice(gel(fa,1), 1), E = vecsplice(gel(fa,2), 1);
    5965           0 :       n = mkvec2(N, mkmat2(P, E));
    5966             :     }
    5967             :   }
    5968         154 :   if (ell == 1)
    5969             :   {
    5970           0 :     if (fli && !equali1(N)) return NULL;
    5971           0 :     retmkvec(pol_x(0));
    5972             :   }
    5973         154 :   if (equali1(N)) return NULL;
    5974         154 :   if (ell == -4) return polsubcycloV4_i(divisorsdisc(n,s), s, fli? N: NULL);
    5975         126 :   if (ell >= 7) return fli? makeCLall(ell,n): makeCL_f(ell,n);
    5976         105 :   switch(ell)
    5977             :   {
    5978           0 :     case 2: return fli? polsubcycloC2_i(n, s): polsubcycloC2(n, s);
    5979           7 :     case 3: return fli? polsubcycloC3_i(n): polsubcycloC3(n);
    5980          84 :     case 4: return fli? polsubcycloC4_i(n, s, fli, NULL): polsubcycloC4(n, s);
    5981          14 :     case 5: return fli? polsubcycloC5_i(n, NULL): polsubcycloC5(n);
    5982           0 :     case 6: return fli? polsubcycloC6_i(n, s): polsubcycloC6(n, s);
    5983             :   }
    5984             :   return NULL; /* LCOV_EXCL_LINE */
    5985             : }
    5986             : GEN
    5987         154 : polsubcyclofast(GEN n, long ell, long s, long fli)
    5988             : {
    5989         154 :   pari_sp av = avma;
    5990         154 :   GEN v = polsubcyclofast_i(n, ell, s, fli);
    5991         154 :   if (!v) retgc_const(av, cgetg(1, t_VEC));
    5992         147 :   return gc_GEN(av, v);
    5993             : }

Generated by: LCOV version 1.16