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

Generated by: LCOV version 1.16