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 - base2.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.18.0 lcov report (development 29818-b3e15d99d2) Lines: 2231 2372 94.1 %
Date: 2024-12-27 09:09:37 Functions: 174 178 97.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 2000  The PARI group.
       2             : 
       3             : This file is part of the PARI/GP package.
       4             : 
       5             : PARI/GP is free software; you can redistribute it and/or modify it under the
       6             : terms of the GNU General Public License as published by the Free Software
       7             : Foundation; either version 2 of the License, or (at your option) any later
       8             : version. It is distributed in the hope that it will be useful, but WITHOUT
       9             : ANY WARRANTY WHATSOEVER.
      10             : 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             : /*******************************************************************/
      15             : /*                                                                 */
      16             : /*                       MAXIMAL ORDERS                            */
      17             : /*                                                                 */
      18             : /*******************************************************************/
      19             : #include "pari.h"
      20             : #include "paripriv.h"
      21             : 
      22             : #define DEBUGLEVEL DEBUGLEVEL_nf
      23             : 
      24             : /* allow p = -1 from factorizations, avoid oo loop on p = 1 */
      25             : static long
      26       12355 : safe_Z_pvalrem(GEN x, GEN p, GEN *z)
      27             : {
      28       12355 :   if (is_pm1(p))
      29             :   {
      30          28 :     if (signe(p) > 0) return gvaluation(x,p); /*error*/
      31          21 :     *z = absi(x); return 1;
      32             :   }
      33       12327 :   return Z_pvalrem(x, p, z);
      34             : }
      35             : /* D an integer, P a ZV, return a factorization matrix for D over P, removing
      36             :  * entries with 0 exponent. */
      37             : static GEN
      38        3619 : fact_from_factors(GEN D, GEN P, long flag)
      39             : {
      40        3619 :   long i, l = lg(P), iq = 1;
      41        3619 :   GEN Q = cgetg(l+1,t_COL);
      42        3619 :   GEN E = cgetg(l+1,t_COL);
      43       15967 :   for (i=1; i<l; i++)
      44             :   {
      45       12355 :     GEN p = gel(P,i);
      46             :     long k;
      47       12355 :     if (flag && !equalim1(p))
      48             :     {
      49          14 :       p = gcdii(p, D);
      50          14 :       if (is_pm1(p)) continue;
      51             :     }
      52       12355 :     k = safe_Z_pvalrem(D, p, &D);
      53       12348 :     if (k) { gel(Q,iq) = p; gel(E,iq) = utoipos(k); iq++; }
      54             :   }
      55        3612 :   D = absi_shallow(D);
      56        3612 :   if (!equali1(D))
      57             :   {
      58         616 :     long k = Z_isanypower(D, &D);
      59         616 :     if (!k) k = 1;
      60         616 :     gel(Q,iq) = D; gel(E,iq) = utoipos(k); iq++;
      61             :   }
      62        3612 :   setlg(Q,iq);
      63        3612 :   setlg(E,iq); return mkmat2(Q,E);
      64             : }
      65             : 
      66             : /* d a t_INT; f a t_MAT factorisation of some t_INT sharing some divisors
      67             :  * with d, or a prime (t_INT). Return a factorization F of d: "primes"
      68             :  * entries in f _may_ be composite, and are included as is in d. */
      69             : static GEN
      70        2148 : update_fact(GEN d, GEN f)
      71             : {
      72             :   GEN P;
      73        2148 :   switch (typ(f))
      74             :   {
      75        2134 :     case t_INT: case t_VEC: case t_COL: return f;
      76          14 :     case t_MAT:
      77          14 :       if (lg(f) == 3) { P = gel(f,1); break; }
      78             :     /*fall through*/
      79             :     default:
      80           7 :       pari_err_TYPE("nfbasis [factorization expected]",f);
      81             :       return NULL;/*LCOV_EXCL_LINE*/
      82             :   }
      83           7 :   return fact_from_factors(d, P, 1);
      84             : }
      85             : 
      86             : /* T = C T0(X/L); C = L^d / lt(T0), d = deg(T)
      87             :  * disc T = C^2(d - 1) L^-(d(d-1)) disc T0 = (L^d / lt(T0)^2)^(d-1) disc T0 */
      88             : static GEN
      89      812504 : set_disc(nfmaxord_t *S)
      90             : {
      91             :   GEN L, dT;
      92             :   long d;
      93      812504 :   if (S->T0 == S->T) return ZX_disc(S->T);
      94      248865 :   d = degpol(S->T0);
      95      248875 :   L = S->unscale;
      96      248875 :   if (typ(L) == t_FRAC && abscmpii(gel(L,1), gel(L,2)) < 0)
      97       11581 :     dT = ZX_disc(S->T); /* more efficient */
      98             :   else
      99             :   {
     100      237294 :     GEN l0 = leading_coeff(S->T0);
     101      237295 :     GEN a = gpowgs(gdiv(gpowgs(L, d), sqri(l0)), d-1);
     102      237296 :     dT = gmul(a, ZX_disc(S->T0)); /* more efficient */
     103             :   }
     104      248861 :   return S->dT = dT;
     105             : }
     106             : 
     107             : /* dT != 0 */
     108             : static GEN
     109      788572 : poldiscfactors_i(GEN T, GEN dT, long flag)
     110             : {
     111             :   GEN U, fa, Z, E, P, Tp;
     112             :   long i, l;
     113             : 
     114      788572 :   fa = absZ_factor_limit_strict(dT, minuu(tridiv_bound(dT), maxprime()), &U);
     115      788585 :   if (!U) return fa;
     116         776 :   Z = mkcol(gel(U,1)); P = gel(fa,1); Tp = NULL;
     117        1664 :   while (lg(Z) != 1)
     118             :   { /* pop and handle last element of Z */
     119         888 :     GEN p = veclast(Z), r;
     120         888 :     setlg(Z, lg(Z)-1);
     121         888 :     if (!Tp) /* first time: p is composite and not a power */
     122         776 :       Tp = ZX_deriv(T);
     123             :     else
     124             :     {
     125         112 :       (void)Z_isanypower(p, &p);
     126         112 :       if ((flag || lgefint(p)==3) && BPSW_psp(p))
     127          89 :       { P = vec_append(P, p); continue; }
     128             :     }
     129         799 :     r = FpX_gcd_check(T, Tp, p);
     130         799 :     if (r)
     131          56 :       Z = shallowconcat(Z, Z_cba(r, diviiexact(p,r)));
     132         743 :     else if (flag)
     133           7 :       P = shallowconcat(P, gel(Z_factor(p),1));
     134             :     else
     135         736 :       P = vec_append(P, p);
     136             :   }
     137         776 :   ZV_sort_inplace(P); l = lg(P); E = cgetg(l, t_COL);
     138        6982 :   for (i = 1; i < l; i++) gel(E,i) = utoipos(Z_pvalrem(dT, gel(P,i), &dT));
     139         776 :   return mkmat2(P,E);
     140             : }
     141             : 
     142             : GEN
     143          42 : poldiscfactors(GEN T, long flag)
     144             : {
     145          42 :   pari_sp av = avma;
     146             :   GEN dT;
     147          42 :   if (typ(T) != t_POL || !RgX_is_ZX(T)) pari_err_TYPE("poldiscfactors",T);
     148          42 :   if (flag < 0 || flag > 1) pari_err_FLAG("poldiscfactors");
     149          42 :   dT = ZX_disc(T);
     150          42 :   if (!signe(dT)) retmkvec2(gen_0, Z_factor(gen_0));
     151          35 :   return gerepilecopy(av, mkvec2(dT, poldiscfactors_i(T, dT, flag)));
     152             : }
     153             : 
     154             : static void
     155      812530 : nfmaxord_check_args(nfmaxord_t *S, GEN T, long flag)
     156             : {
     157      812530 :   GEN dT, L, E, P, fa = NULL;
     158             :   pari_timer t;
     159      812530 :   long l, ty = typ(T);
     160             : 
     161      812530 :   if (DEBUGLEVEL) timer_start(&t);
     162      812530 :   if (ty == t_VEC) {
     163       23933 :     if (lg(T) != 3) pari_err_TYPE("nfmaxord",T);
     164       23933 :     fa = gel(T,2); T = gel(T,1); ty = typ(T);
     165             :   }
     166      812530 :   if (ty != t_POL) pari_err_TYPE("nfmaxord",T);
     167      812530 :   T = Q_primpart(T);
     168      812499 :   if (degpol(T) <= 0) pari_err_CONSTPOL("nfmaxord");
     169      812501 :   RgX_check_ZX(T, "nfmaxord");
     170      812500 :   S->T0 = T;
     171      812500 :   S->T = T = ZX_Q_normalize(T, &L);
     172      812510 :   S->unscale = L;
     173      812510 :   S->dT = dT = set_disc(S);
     174      812472 :   S->certify = 1;
     175      812472 :   if (!signe(dT)) pari_err_IRREDPOL("nfmaxord",T);
     176      812471 :   if (fa)
     177             :   {
     178       23933 :     const long MIN = 100; /* include at least all p < 101 */
     179       23933 :     GEN P0 = NULL, U;
     180       23933 :     S->certify = 0;
     181       23933 :     if (!isint1(L)) fa = update_fact(dT, fa);
     182       23926 :     switch(typ(fa))
     183             :     {
     184         224 :       case t_MAT:
     185         224 :         if (!is_Z_factornon0(fa)) pari_err_TYPE("nfmaxord",fa);
     186         217 :         P0 = gel(fa,1); /* fall through */
     187        3612 :       case t_VEC: case t_COL:
     188        3612 :         if (!P0)
     189             :         {
     190        3395 :           if (!RgV_is_ZV(fa)) pari_err_TYPE("nfmaxord",fa);
     191        3395 :           P0 = fa;
     192             :         }
     193        3612 :         P = gel(absZ_factor_limit_strict(dT, MIN, &U), 1);
     194        3612 :         if (lg(P) != 0) { settyp(P, typ(P0)); P0 = shallowconcat(P0,P); }
     195        3612 :         P0 = ZV_sort_uniq_shallow(P0);
     196        3612 :         fa = fact_from_factors(dT, P0, 0);
     197        3605 :         break;
     198       20300 :       case t_INT:
     199       20300 :         fa = absZ_factor_limit(dT, (signe(fa) <= 0)? 1: maxuu(itou(fa), MIN));
     200       20300 :         break;
     201           7 :       default:
     202           7 :         pari_err_TYPE("nfmaxord",fa);
     203             :     }
     204             :   }
     205             :   else
     206             :   {
     207      788538 :     S->certify = !(flag & nf_PARTIALFACT);
     208      788538 :     fa = poldiscfactors_i(T, dT, 0);
     209             :   }
     210      812455 :   P = gel(fa,1); l = lg(P);
     211      812455 :   E = gel(fa,2);
     212      812455 :   if (l > 1 && is_pm1(gel(P,1)))
     213             :   {
     214          21 :     l--;
     215          21 :     P = vecslice(P, 2, l);
     216          21 :     E = vecslice(E, 2, l);
     217             :   }
     218      812452 :   S->dTP = P;
     219      812452 :   S->dTE = vec_to_vecsmall(E);
     220      812441 :   if (DEBUGLEVEL>2) timer_printf(&t, "disc. factorisation");
     221      812441 : }
     222             : 
     223             : static int
     224      217137 : fnz(GEN x,long j)
     225             : {
     226             :   long i;
     227      696904 :   for (i=1; i<j; i++)
     228      529361 :     if (signe(gel(x,i))) return 0;
     229      167543 :   return 1;
     230             : }
     231             : /* return list u[i], 2 by 2 coprime with the same prime divisors as ab */
     232             : static GEN
     233         273 : get_coprimes(GEN a, GEN b)
     234             : {
     235         273 :   long i, k = 1;
     236         273 :   GEN u = cgetg(3, t_COL);
     237         273 :   gel(u,1) = a;
     238         273 :   gel(u,2) = b;
     239             :   /* u1,..., uk 2 by 2 coprime */
     240         994 :   while (k+1 < lg(u))
     241             :   {
     242         721 :     GEN d, c = gel(u,k+1);
     243         721 :     if (is_pm1(c)) { k++; continue; }
     244        1218 :     for (i=1; i<=k; i++)
     245             :     {
     246         784 :       GEN ui = gel(u,i);
     247         784 :       if (is_pm1(ui)) continue;
     248         448 :       d = gcdii(c, ui);
     249         448 :       if (d == gen_1) continue;
     250         448 :       c = diviiexact(c, d);
     251         448 :       gel(u,i) = diviiexact(ui, d);
     252         448 :       u = vec_append(u, d);
     253             :     }
     254         434 :     gel(u,++k) = c;
     255             :   }
     256        1267 :   for (i = k = 1; i < lg(u); i++)
     257         994 :     if (!is_pm1(gel(u,i))) gel(u,k++) = gel(u,i);
     258         273 :   setlg(u, k); return u;
     259             : }
     260             : 
     261             : /*******************************************************************/
     262             : /*                                                                 */
     263             : /*                            ROUND 4                              */
     264             : /*                                                                 */
     265             : /*******************************************************************/
     266             : typedef struct {
     267             :   /* constants */
     268             :   long pisprime; /* -1: unknown, 1: prime,  0: composite */
     269             :   GEN p, f; /* goal: factor f p-adically */
     270             :   long df;
     271             :   GEN pdf; /* p^df = reduced discriminant of f */
     272             :   long mf; /* */
     273             :   GEN psf, pmf; /* stability precision for f, wanted precision for f */
     274             :   long vpsf; /* v_p(p_f) */
     275             :   /* these are updated along the way */
     276             :   GEN phi; /* a p-integer, in Q[X] */
     277             :   GEN phi0; /* a p-integer, in Q[X] from testb2 / testc2, to be composed with
     278             :              * phi when correct precision is known */
     279             :   GEN chi; /* characteristic polynomial of phi (mod psc) in Z[X] */
     280             :   GEN nu; /* irreducible divisor of chi mod p, in Z[X] */
     281             :   GEN invnu; /* numerator ( 1/ Mod(nu, chi) mod pmr ) */
     282             :   GEN Dinvnu;/* denominator ( ... ) */
     283             :   long vDinvnu; /* v_p(Dinvnu) */
     284             :   GEN prc, psc; /* reduced discriminant of chi, stability precision for chi */
     285             :   long vpsc; /* v_p(p_c) */
     286             :   GEN ns, nsf, precns; /* cached Newton sums for nsf and their precision */
     287             : } decomp_t;
     288             : static GEN maxord_i(decomp_t *S, GEN p, GEN f, long mf, GEN w, long flag);
     289             : static GEN dbasis(GEN p, GEN f, long mf, GEN alpha, GEN U);
     290             : static GEN maxord(GEN p,GEN f,long mf);
     291             : static GEN ZX_Dedekind(GEN F, GEN *pg, GEN p);
     292             : 
     293             : static void
     294         477 : fix_PE(GEN *pP, GEN *pE, long i, GEN u, GEN N)
     295             : {
     296             :   GEN P, E;
     297         477 :   long k, l = lg(u), lP = lg(*pP);
     298             :   pari_sp av;
     299             : 
     300         477 :   *pP = P = shallowconcat(*pP, vecslice(u, 2, l-1));
     301         477 :   *pE = E = vecsmall_lengthen(*pE, lP + l-2);
     302         477 :   gel(P,i) = gel(u,1); av = avma;
     303         477 :   E[i] = Z_pvalrem(N, gel(P,i), &N);
     304         961 :   for (k=lP, lP=lg(P); k < lP; k++) E[k] = Z_pvalrem(N, gel(P,k), &N);
     305         477 :   set_avma(av);
     306         477 : }
     307             : static long
     308      685741 : diag_denomval(GEN M, GEN p)
     309             : {
     310             :   long j, v, l;
     311      685741 :   if (typ(M) != t_MAT) return 0;
     312      463193 :   v = 0; l = lg(M);
     313     2070895 :   for (j=1; j<l; j++)
     314             :   {
     315     1607706 :     GEN t = gcoeff(M,j,j);
     316     1607706 :     if (typ(t) == t_FRAC) v += Z_pval(gel(t,2), p);
     317             :   }
     318      463189 :   return v;
     319             : }
     320             : 
     321             : /* n > 1 is composite, not a pure power, and has no prime divisor < 2^14;
     322             :  * return a BPSW divisor of n and smallest k-th root of largest coprime cofactor */
     323             : static GEN
     324         183 : Z_fac(GEN n)
     325             : {
     326         183 :   GEN p = icopy(n), part = ifac_start(p, 0);
     327             :   long e;
     328         183 :   ifac_next(&part, &p, &e); n = diviiexact(n, powiu(p, e));
     329         183 :   (void)Z_isanypower(n, &n); return mkvec2(p, n);
     330             : }
     331             : 
     332             : /* Warning: data computed for T = ZX_Q_normalize(T0). If S.unscale !=
     333             :  * gen_1, caller must take steps to correct the components if it wishes
     334             :  * to stick to the original T0. Return a vector of p-maximal orders, for
     335             :  * those p s.t p^2 | disc(T) [ = S->dTP ]*/
     336             : static GEN
     337      812525 : get_maxord(nfmaxord_t *S, GEN T0, long flag)
     338             : {
     339             :   GEN P, E;
     340             :   VOLATILE GEN O;
     341             :   VOLATILE long lP, i, k;
     342             : 
     343      812525 :   nfmaxord_check_args(S, T0, flag);
     344      812443 :   P = S->dTP; lP = lg(P);
     345      812443 :   E = S->dTE;
     346      812443 :   O = cgetg(1, t_VEC);
     347     3142003 :   for (i=1; i<lP; i++)
     348             :   {
     349             :     VOLATILE pari_sp av;
     350             :     /* includes the silly case where P[i] = -1 */
     351     2329534 :     if (E[i] <= 1)
     352             :     {
     353     1303305 :       if (S->certify)
     354             :       {
     355     1295338 :         GEN p = gel(P,i);
     356     1295338 :         if (signe(p) > 0 && !BPSW_psp(p))
     357             :         {
     358         183 :           fix_PE(&P, &E, i, Z_fac(p), S->dT);
     359         183 :           lP = lg(P); i--; continue;
     360             :         }
     361             :       }
     362     1303133 :       O = vec_append(O, gen_1); continue;
     363             :     }
     364     1026229 :     av = avma;
     365     1026229 :     pari_CATCH(CATCH_ALL) {
     366         273 :       GEN u, err = pari_err_last();
     367             :       long l;
     368         273 :       switch(err_get_num(err))
     369             :       {
     370         273 :         case e_INV:
     371             :         {
     372         273 :           GEN p, x = err_get_compo(err, 2);
     373         273 :           if (typ(x) == t_INTMOD)
     374             :           { /* caught false prime, update factorization */
     375         273 :             p = gcdii(gel(x,1), gel(x,2));
     376         273 :             u = diviiexact(gel(x,1),p);
     377         273 :             if (DEBUGLEVEL) pari_warn(warner,"impossible inverse: %Ps", x);
     378         273 :             gerepileall(av, 2, &p, &u);
     379             : 
     380         273 :             u = get_coprimes(p, u); l = lg(u);
     381             :             /* no small factors, but often a prime power */
     382         819 :             for (k = 1; k < l; k++) (void)Z_isanypower(gel(u,k), &gel(u,k));
     383         273 :             break;
     384             :           }
     385             :           /* fall through */
     386             :         }
     387             :         case e_PRIME: case e_IRREDPOL:
     388             :         { /* we're here because we failed BPSW_isprime(), no point in
     389             :            * reporting a possible counter-example to the BPSW test */
     390           0 :           GEN p = gel(P,i);
     391           0 :           set_avma(av);
     392           0 :           if (DEBUGLEVEL)
     393           0 :             pari_warn(warner,"large composite in nfmaxord:loop(), %Ps", p);
     394           0 :           if (expi(p) < 100)
     395           0 :             u = gel(Z_factor(p), 1); /* p < 2^100 should take ~20ms */
     396           0 :           else if (S->certify)
     397           0 :             u = Z_fac(p);
     398             :           else
     399           0 :           { /* give up, probably not maximal */
     400           0 :             GEN B, g, k = ZX_Dedekind(S->T, &g, p);
     401           0 :             k = FpX_normalize(k, p);
     402           0 :             B = dbasis(p, S->T, E[i], NULL, FpX_div(S->T,k,p));
     403           0 :             O = vec_append(O, B);
     404           0 :             pari_CATCH_reset(); continue;
     405             :           }
     406           0 :           break;
     407             :         }
     408           0 :         default: pari_err(0, err);
     409             :           return NULL;/*LCOV_EXCL_LINE*/
     410             :       }
     411         273 :       fix_PE(&P, &E, i, u, S->dT);
     412         273 :       lP = lg(P); av = avma;
     413     1026503 :     } pari_RETRY {
     414     1026503 :       GEN p = gel(P,i), O2;
     415     1026503 :       if (DEBUGLEVEL>2) err_printf("Treating p^k = %Ps^%ld\n",p,E[i]);
     416     1026503 :       O2 = maxord(p,S->T,E[i]);
     417     1026261 :       if (S->certify && (odd(E[i]) || E[i] != 2*diag_denomval(O2, p))
     418      609888 :                      && !BPSW_psp(p))
     419             :       {
     420          21 :         fix_PE(&P, &E, i, gel(Z_factor(p), 1), S->dT);
     421          21 :         lP = lg(P); i--;
     422             :       }
     423             :       else
     424     1026233 :         O = vec_append(O, O2);
     425     1026249 :     } pari_ENDCATCH;
     426             :   }
     427      812469 :   S->dTP = P; S->dTE = E; return O;
     428             : }
     429             : 
     430             : /* M a QM, return denominator of diagonal. All denominators are powers of
     431             :  * a given integer */
     432             : static GEN
     433       98155 : diag_denom(GEN M)
     434             : {
     435       98155 :   GEN d = gen_1;
     436       98155 :   long j, l = lg(M);
     437      681011 :   for (j=1; j<l; j++)
     438             :   {
     439      582856 :     GEN t = gcoeff(M,j,j);
     440      582856 :     if (typ(t) == t_INT) continue;
     441      208021 :     t = gel(t,2);
     442      208021 :     if (abscmpii(t,d) > 0) d = t;
     443             :   }
     444       98155 :   return d;
     445             : }
     446             : static void
     447      746022 : setPE(GEN D, GEN P, GEN *pP, GEN *pE)
     448             : {
     449      746022 :   long k, j, l = lg(P);
     450             :   GEN P2, E2;
     451      746022 :   *pP = P2 = cgetg(l, t_VEC);
     452      746024 :   *pE = E2 = cgetg(l, t_VECSMALL);
     453     2867968 :   for (k = j = 1; j < l; j++)
     454             :   {
     455     2121907 :     long v = Z_pvalrem(D, gel(P,j), &D);
     456     2121943 :     if (v) { gel(P2,k) = gel(P,j); E2[k] = v; k++; }
     457             :   }
     458      746061 :   setlg(P2, k);
     459      746058 :   setlg(E2, k);
     460      746047 : }
     461             : void
     462      101291 : nfmaxord(nfmaxord_t *S, GEN T0, long flag)
     463             : {
     464      101291 :   GEN O = get_maxord(S, T0, flag);
     465      101288 :   GEN f = S->T, P = S->dTP, a = NULL, da = NULL;
     466      101288 :   long n = degpol(f), lP = lg(P), i, j, k;
     467      101291 :   int centered = 0;
     468      101291 :   pari_sp av = avma;
     469             :   /* r1 & basden not initialized here */
     470      101291 :   S->r1 = -1;
     471      101291 :   S->basden = NULL;
     472      354168 :   for (i=1; i<lP; i++)
     473             :   {
     474      252877 :     GEN M, db, b = gel(O,i);
     475      252877 :     if (b == gen_1) continue;
     476       98155 :     db = diag_denom(b);
     477       98155 :     if (db == gen_1) continue;
     478             : 
     479             :     /* db = denom(b), (da,db) = 1. Compute da Im(b) + db Im(a) */
     480       98155 :     b = Q_muli_to_int(b,db);
     481       98156 :     if (!da) { da = db; a = b; }
     482             :     else
     483             :     { /* optimization: easy as long as both matrix are diagonal */
     484      131896 :       j=2; while (j<=n && fnz(gel(a,j),j) && fnz(gel(b,j),j)) j++;
     485       49608 :       k = j-1; M = cgetg(2*n-k+1,t_MAT);
     486      181502 :       for (j=1; j<=k; j++)
     487             :       {
     488      131895 :         gel(M,j) = gel(a,j);
     489      131895 :         gcoeff(M,j,j) = mulii(gcoeff(a,j,j),gcoeff(b,j,j));
     490             :       }
     491             :       /* could reduce mod M(j,j) but not worth it: usually close to da*db */
     492      271763 :       for (  ; j<=n;     j++) gel(M,j) = ZC_Z_mul(gel(a,j), db);
     493      271762 :       for (  ; j<=2*n-k; j++) gel(M,j) = ZC_Z_mul(gel(b,j+k-n), da);
     494       49606 :       da = mulii(da,db);
     495       49607 :       a = ZM_hnfmodall_i(M, da, hnf_MODID|hnf_CENTER);
     496       49608 :       gerepileall(av, 2, &a, &da);
     497       49607 :       centered = 1;
     498             :     }
     499             :   }
     500      101291 :   if (da)
     501             :   {
     502       48548 :     GEN index = diviiexact(da, gcoeff(a,1,1));
     503      228786 :     for (j=2; j<=n; j++) index = mulii(index, diviiexact(da, gcoeff(a,j,j)));
     504       48546 :     if (!centered) a = ZM_hnfcenter(a);
     505       48546 :     a = RgM_Rg_div(a, da);
     506       48548 :     S->index = index;
     507       48548 :     S->dK = diviiexact(S->dT, sqri(index));
     508             :   }
     509             :   else
     510             :   {
     511       52743 :     S->index = gen_1;
     512       52743 :     S->dK = S->dT;
     513       52743 :     a = matid(n);
     514             :   }
     515      101288 :   setPE(S->dK, P, &S->dKP, &S->dKE);
     516      101289 :   S->basis = RgM_to_RgXV(a, varn(f));
     517      101287 : }
     518             : GEN
     519         938 : nfbasis(GEN x, GEN *pdK)
     520             : {
     521         938 :   pari_sp av = avma;
     522             :   nfmaxord_t S;
     523             :   GEN B;
     524         938 :   nfmaxord(&S, x, 0);
     525         938 :   B = RgXV_unscale(S.basis, S.unscale);
     526         938 :   if (pdK) *pdK = S.dK;
     527         938 :   return gc_all(av, pdK? 2: 1, &B, pdK);
     528             : }
     529             : /* field discriminant: faster than nfmaxord, use local data only */
     530             : static GEN
     531      711233 : maxord_disc(nfmaxord_t *S, GEN x)
     532             : {
     533      711233 :   GEN O = get_maxord(S, x, 0), I = gen_1;
     534      711199 :   long n = degpol(S->T), lP = lg(O), i, j;
     535     2787662 :   for (i = 1; i < lP; i++)
     536             :   {
     537     2076482 :     GEN b = gel(O,i);
     538     2076482 :     if (b == gen_1) continue;
     539     2705893 :     for (j = 1; j <= n; j++)
     540             :     {
     541     2114551 :       GEN c = gcoeff(b,j,j);
     542     2114551 :       if (typ(c) == t_FRAC) I = mulii(I, gel(c,2)) ;
     543             :     }
     544             :   }
     545      711180 :   return diviiexact(S->dT, sqri(I));
     546             : }
     547             : GEN
     548       66465 : nfdisc(GEN x)
     549             : {
     550       66465 :   pari_sp av = avma;
     551             :   nfmaxord_t S;
     552       66465 :   return gerepileuptoint(av, maxord_disc(&S, x));
     553             : }
     554             : GEN
     555      644780 : nfdiscfactors(GEN x)
     556             : {
     557      644780 :   pari_sp av = avma;
     558      644780 :   GEN E, P, D, nf = checknf_i(x);
     559      644778 :   if (nf)
     560             :   {
     561           7 :     D = nf_get_disc(nf);
     562           7 :     P = nf_get_ramified_primes(nf);
     563             :   }
     564             :   else
     565             :   {
     566             :     nfmaxord_t S;
     567      644771 :     D = maxord_disc(&S, x);
     568      644726 :     P = S.dTP;
     569             :   }
     570      644733 :   setPE(D, P, &P, &E); settyp(P, t_COL);
     571      644758 :   return gerepilecopy(av, mkvec2(D, mkmat2(P, zc_to_ZC(E))));
     572             : }
     573             : 
     574             : static ulong
     575     1595176 : Flx_checkdeflate(GEN x)
     576             : {
     577     1595176 :   ulong d = 0, i, lx = (ulong)lg(x);
     578     2546163 :   for (i=3; i<lx; i++)
     579     1700795 :     if (x[i]) { d = ugcd(d,i-2); if (d == 1) break; }
     580     1595176 :   return d;
     581             : }
     582             : 
     583             : /* product of (monic) irreducible factors of f over Fp[X]
     584             :  * Assume f reduced mod p, otherwise valuation at x may be wrong */
     585             : static GEN
     586     1595178 : Flx_radical(GEN f, ulong p)
     587             : {
     588     1595178 :   long v0 = Flx_valrem(f, &f);
     589             :   ulong du, d, e;
     590             :   GEN u;
     591             : 
     592     1595177 :   d = Flx_checkdeflate(f);
     593     1595207 :   if (!d) return v0? polx_Flx(f[1]): pol1_Flx(f[1]);
     594      999120 :   if (u_lvalrem(d,p, &e)) f = Flx_deflate(f, d/e); /* f(x^p^i) -> f(x) */
     595      999123 :   u = Flx_gcd(f, Flx_deriv(f, p), p); /* (f,f') */
     596      999113 :   du = degpol(u);
     597      999113 :   if (du)
     598             :   {
     599      313963 :     if (du == (ulong)degpol(f))
     600           0 :       f = Flx_radical(Flx_deflate(f,p), p);
     601             :     else
     602             :     {
     603      313962 :       u = Flx_normalize(u, p);
     604      313963 :       f = Flx_div(f, u, p);
     605      313962 :       if (p <= du)
     606             :       {
     607       66354 :         GEN w = (degpol(f) >= degpol(u))? Flx_rem(f, u, p): f;
     608       66354 :         w = Flxq_powu(w, du, u, p);
     609       66354 :         w = Flx_div(u, Flx_gcd(w,u,p), p); /* u / gcd(u, v^(deg u-1)) */
     610       66354 :         f = Flx_mul(f, Flx_radical(Flx_deflate(w,p), p), p);
     611             :       }
     612             :     }
     613             :   }
     614      999119 :   if (v0) f = Flx_shift(f, 1);
     615      999113 :   return f;
     616             : }
     617             : /* Assume f reduced mod p, otherwise valuation at x may be wrong */
     618             : static GEN
     619        5522 : FpX_radical(GEN f, GEN p)
     620             : {
     621             :   GEN u;
     622             :   long v0;
     623        5522 :   if (lgefint(p) == 3)
     624             :   {
     625        1739 :     ulong q = p[2];
     626        1739 :     return Flx_to_ZX( Flx_radical(ZX_to_Flx(f, q), q) );
     627             :   }
     628        3783 :   v0 = ZX_valrem(f, &f);
     629        3783 :   u = FpX_gcd(f,FpX_deriv(f, p), p);
     630        3516 :   if (degpol(u)) f = FpX_div(f, u, p);
     631        3516 :   if (v0) f = RgX_shift(f, 1);
     632        3516 :   return f;
     633             : }
     634             : /* f / a */
     635             : static GEN
     636     1527116 : zx_z_div(GEN f, ulong a)
     637             : {
     638     1527116 :   long i, l = lg(f);
     639     1527116 :   GEN g = cgetg(l, t_VECSMALL);
     640     1527091 :   g[1] = f[1];
     641     5162275 :   for (i = 2; i < l; i++) g[i] = f[i] / a;
     642     1527091 :   return g;
     643             : }
     644             : /* Dedekind criterion; return k = gcd(g,h, (f-gh)/p), where
     645             :  *   f = \prod f_i^e_i, g = \prod f_i, h = \prod f_i^{e_i-1}
     646             :  * k = 1 iff Z[X]/(f) is p-maximal */
     647             : static GEN
     648     1532657 : ZX_Dedekind(GEN F, GEN *pg, GEN p)
     649             : {
     650             :   GEN k, h, g, f, f2;
     651     1532657 :   ulong q = p[2];
     652     1532657 :   if (lgefint(p) == 3 && q < (1UL << BITS_IN_HALFULONG))
     653     1527057 :   {
     654     1527134 :     ulong q2 = q*q;
     655     1527134 :     f2 = ZX_to_Flx(F, q2);
     656     1527122 :     f = Flx_red(f2, q);
     657     1527087 :     g = Flx_radical(f, q);
     658     1527097 :     h = Flx_div(f, g, q);
     659     1527095 :     k = zx_z_div(Flx_sub(f2, Flx_mul(g,h,q2), q2), q);
     660     1527087 :     k = Flx_gcd(k, Flx_gcd(g,h,q), q);
     661     1527103 :     k = Flx_to_ZX(k);
     662     1527057 :     g = Flx_to_ZX(g);
     663             :   }
     664             :   else
     665             :   {
     666        5523 :     f2 = FpX_red(F, sqri(p));
     667        5522 :     f = FpX_red(f2, p);
     668        5522 :     g = FpX_radical(f, p);
     669        5249 :     h = FpX_div(f, g, p);
     670        5249 :     k = ZX_Z_divexact(ZX_sub(f2, ZX_mul(g,h)), p);
     671        5249 :     k = FpX_gcd(FpX_red(k, p), FpX_gcd(g,h,p), p);
     672             :   }
     673     1532301 :   *pg = g; return k;
     674             : }
     675             : 
     676             : /* p-maximal order of Z[x]/f; mf = v_p(Disc(f)) or < 0 [unknown].
     677             :  * Return gen_1 if p-maximal */
     678             : static GEN
     679     1532658 : maxord(GEN p, GEN f, long mf)
     680             : {
     681     1532658 :   const pari_sp av = avma;
     682     1532658 :   GEN res, g, k = ZX_Dedekind(f, &g, p);
     683     1532299 :   long dk = degpol(k);
     684     1532294 :   if (DEBUGLEVEL>2) err_printf("  ZX_Dedekind: gcd has degree %ld\n", dk);
     685     1532346 :   if (!dk) { set_avma(av); return gen_1; }
     686      871074 :   if (mf < 0) mf = ZpX_disc_val(f, p);
     687      871078 :   k = FpX_normalize(k, p);
     688      871084 :   if (2*dk >= mf-1)
     689      419175 :     res = dbasis(p, f, mf, NULL, FpX_div(f,k,p));
     690             :   else
     691             :   {
     692             :     GEN w, F1, F2;
     693             :     decomp_t S;
     694      451909 :     F1 = FpX_factor(k,p);
     695      451944 :     F2 = FpX_factor(FpX_div(g,k,p),p);
     696      451945 :     w = merge_sort_uniq(gel(F1,1),gel(F2,1),(void*)cmpii,&gen_cmp_RgX);
     697      451939 :     res = maxord_i(&S, p, f, mf, w, 0);
     698             :   }
     699      871118 :   return gerepilecopy(av,res);
     700             : }
     701             : /* T monic separable ZX, p prime */
     702             : GEN
     703           0 : ZpX_primedec(GEN T, GEN p)
     704             : {
     705           0 :   const pari_sp av = avma;
     706           0 :   GEN w, F1, F2, res, g, k = ZX_Dedekind(T, &g, p);
     707             :   decomp_t S;
     708           0 :   if (!degpol(k)) return zm_to_ZM(FpX_degfact(T, p));
     709           0 :   k = FpX_normalize(k, p);
     710           0 :   F1 = FpX_factor(k,p);
     711           0 :   F2 = FpX_factor(FpX_div(g,k,p),p);
     712           0 :   w = merge_sort_uniq(gel(F1,1),gel(F2,1),(void*)cmpii,&gen_cmp_RgX);
     713           0 :   res = maxord_i(&S, p, T, ZpX_disc_val(T, p), w, -1);
     714           0 :   if (!res)
     715             :   {
     716           0 :     long f = degpol(S.nu), e = degpol(T) / f;
     717           0 :     set_avma(av); retmkmat2(mkcols(f), mkcols(e));
     718             :   }
     719           0 :   return gerepilecopy(av,res);
     720             : }
     721             : 
     722             : static GEN
     723     4657356 : Zlx_sylvester_echelon(GEN f1, GEN f2, long early_abort, ulong p, ulong pm)
     724             : {
     725     4657356 :   long j, n = degpol(f1);
     726     4657343 :   GEN h, a = cgetg(n+1,t_MAT);
     727     4657327 :   f1 = Flx_get_red(f1, pm);
     728     4657318 :   h = Flx_rem(f2,f1,pm);
     729    16321061 :   for (j=1;; j++)
     730             :   {
     731    16321061 :     gel(a,j) = Flx_to_Flv(h, n);
     732    16320467 :     if (j == n) break;
     733    11663281 :     h = Flx_rem(Flx_shift(h, 1), f1, pm);
     734             :   }
     735     4657186 :   return zlm_echelon(a, early_abort, p, pm);
     736             : }
     737             : /* Sylvester's matrix, mod p^m (assumes f1 monic). If early_abort
     738             :  * is set, return NULL if one pivot is 0 mod p^m */
     739             : static GEN
     740       72957 : ZpX_sylvester_echelon(GEN f1, GEN f2, long early_abort, GEN p, GEN pm)
     741             : {
     742       72957 :   long j, n = degpol(f1);
     743       72957 :   GEN h, a = cgetg(n+1,t_MAT);
     744       72957 :   h = FpXQ_red(f2,f1,pm);
     745      416410 :   for (j=1;; j++)
     746             :   {
     747      416410 :     gel(a,j) = RgX_to_RgC(h, n);
     748      416410 :     if (j == n) break;
     749      343453 :     h = FpX_rem(RgX_shift_shallow(h, 1), f1, pm);
     750             :   }
     751       72957 :   return ZpM_echelon(a, early_abort, p, pm);
     752             : }
     753             : 
     754             : /* polynomial gcd mod p^m (assumes f1 monic). Return a QpX ! */
     755             : static GEN
     756      245183 : Zlx_gcd(GEN f1, GEN f2, ulong p, ulong pm)
     757             : {
     758      245183 :   pari_sp av = avma;
     759      245183 :   GEN a = Zlx_sylvester_echelon(f1,f2,0,p,pm);
     760      245183 :   long c, l = lg(a), sv = f1[1];
     761      749216 :   for (c = 1; c < l; c++)
     762             :   {
     763      749216 :     ulong t = ucoeff(a,c,c);
     764      749216 :     if (t)
     765             :     {
     766      245183 :       a = Flx_to_ZX(Flv_to_Flx(gel(a,c), sv));
     767      245176 :       if (t == 1) return gerepilecopy(av, a);
     768       74729 :       return gerepileupto(av, RgX_Rg_div(a, utoipos(t)));
     769             :     }
     770             :   }
     771           0 :   set_avma(av);
     772           0 :   a = cgetg(2,t_POL); a[1] = sv; return a;
     773             : }
     774             : GEN
     775      253366 : ZpX_gcd(GEN f1, GEN f2, GEN p, GEN pm)
     776             : {
     777      253366 :   pari_sp av = avma;
     778             :   GEN a;
     779             :   long c, l, v;
     780      253366 :   if (lgefint(pm) == 3)
     781             :   {
     782      245182 :     ulong q = pm[2];
     783      245182 :     return Zlx_gcd(ZX_to_Flx(f1, q), ZX_to_Flx(f2,q), p[2], q);
     784             :   }
     785        8184 :   a = ZpX_sylvester_echelon(f1,f2,0,p,pm);
     786        8184 :   l = lg(a); v = varn(f1);
     787       51483 :   for (c = 1; c < l; c++)
     788             :   {
     789       51483 :     GEN t = gcoeff(a,c,c);
     790       51483 :     if (signe(t))
     791             :     {
     792        8184 :       a = RgV_to_RgX(gel(a,c), v);
     793        8184 :       if (equali1(t)) return gerepilecopy(av, a);
     794        2364 :       return gerepileupto(av, RgX_Rg_div(a, t));
     795             :     }
     796             :   }
     797           0 :   set_avma(av); return pol_0(v);
     798             : }
     799             : 
     800             : /* Return m > 0, such that p^m ~ 2^16 for initial value of m; assume p prime */
     801             : static long
     802     4372990 : init_m(GEN p)
     803             : {
     804             :   ulong pp;
     805     4372990 :   if (lgefint(p) > 3) return 1;
     806     4371821 :   pp = p[2]; /* m ~ 16 / log2(pp) */
     807     4371821 :   if (pp < 41) switch(pp)
     808             :   {
     809     1186653 :     case 2: return 16;
     810      349276 :     case 3: return 10;
     811      245109 :     case 5: return 6;
     812      151407 :     case 7: return 5;
     813      210211 :     case 11: case 13: return 4;
     814      299516 :     default: return 3;
     815             :   }
     816     1929649 :   return pp < 257? 2: 1;
     817             : }
     818             : 
     819             : /* reduced resultant mod p^m (assumes x monic) */
     820             : GEN
     821      986817 : ZpX_reduced_resultant(GEN x, GEN y, GEN p, GEN pm)
     822             : {
     823      986817 :   pari_sp av = avma;
     824             :   GEN z;
     825      986817 :   if (lgefint(pm) == 3)
     826             :   {
     827      975450 :     ulong q = pm[2];
     828      975450 :     z = Zlx_sylvester_echelon(ZX_to_Flx(x,q), ZX_to_Flx(y,q),0,p[2],q);
     829      975505 :     if (lg(z) > 1)
     830             :     {
     831      975505 :       ulong c = ucoeff(z,1,1);
     832      975505 :       if (c) return gc_utoipos(av, c);
     833             :     }
     834             :   }
     835             :   else
     836             :   {
     837       11367 :     z = ZpX_sylvester_echelon(x,y,0,p,pm);
     838       11367 :     if (lg(z) > 1)
     839             :     {
     840       11367 :       GEN c = gcoeff(z,1,1);
     841       11367 :       if (signe(c)) return gerepileuptoint(av, c);
     842             :     }
     843             :   }
     844      127075 :   set_avma(av); return gen_0;
     845             : }
     846             : /* Assume Res(f,g) divides p^M. Return Res(f, g), using dynamic p-adic
     847             :  * precision (until result is nonzero or p^M). */
     848             : GEN
     849      927142 : ZpX_reduced_resultant_fast(GEN f, GEN g, GEN p, long M)
     850             : {
     851      927142 :   GEN R, q = NULL;
     852             :   long m;
     853      927142 :   m = init_m(p); if (m < 1) m = 1;
     854       59672 :   for(;; m <<= 1) {
     855      986803 :     if (M < 2*m) break;
     856       91665 :     q = q? sqri(q): powiu(p, m); /* p^m */
     857       91665 :     R = ZpX_reduced_resultant(f,g, p, q); if (signe(R)) return R;
     858             :   }
     859      895138 :   q = powiu(p, M);
     860      895151 :   R = ZpX_reduced_resultant(f,g, p, q); return signe(R)? R: q;
     861             : }
     862             : 
     863             : /* v_p(Res(x,y) mod p^m), assumes (lc(x),p) = 1 */
     864             : static long
     865     3490074 : ZpX_resultant_val_i(GEN x, GEN y, GEN p, GEN pm)
     866             : {
     867     3490074 :   pari_sp av = avma;
     868             :   GEN z;
     869             :   long i, l, v;
     870     3490074 :   if (lgefint(pm) == 3)
     871             :   {
     872     3436668 :     ulong q = pm[2], pp = p[2];
     873     3436668 :     z = Zlx_sylvester_echelon(ZX_to_Flx(x,q), ZX_to_Flx(y,q), 1, pp, q);
     874     3436754 :     if (!z) return gc_long(av,-1); /* failure */
     875     3252013 :     v = 0; l = lg(z);
     876    13533124 :     for (i = 1; i < l; i++) v += u_lval(ucoeff(z,i,i), pp);
     877             :   }
     878             :   else
     879             :   {
     880       53406 :     z = ZpX_sylvester_echelon(x, y, 1, p, pm);
     881       53406 :     if (!z) return gc_long(av,-1); /* failure */
     882       52718 :     v = 0; l = lg(z);
     883      194628 :     for (i = 1; i < l; i++) v += Z_pval(gcoeff(z,i,i), p);
     884             :   }
     885     3304738 :   return v;
     886             : }
     887             : 
     888             : /* assume (lc(f),p) = 1; no assumption on g */
     889             : long
     890     3445906 : ZpX_resultant_val(GEN f, GEN g, GEN p, long M)
     891             : {
     892     3445906 :   pari_sp av = avma;
     893     3445906 :   GEN q = NULL;
     894             :   long v, m;
     895     3445906 :   m = init_m(p); if (m < 2) m = 2;
     896       44129 :   for(;; m <<= 1) {
     897     3490027 :     if (m > M) m = M;
     898     3490027 :     q = q? sqri(q): powiu(p, m); /* p^m */
     899     3490076 :     v = ZpX_resultant_val_i(f,g, p, q); if (v >= 0) return gc_long(av,v);
     900      185428 :     if (m == M) return gc_long(av,M);
     901             :   }
     902             : }
     903             : 
     904             : /* assume f separable and (lc(f),p) = 1 */
     905             : long
     906      182539 : ZpX_disc_val(GEN f, GEN p)
     907             : {
     908      182539 :   pari_sp av = avma;
     909             :   long v;
     910      182539 :   if (degpol(f) == 1) return 0;
     911      182539 :   v = ZpX_resultant_val(f, ZX_deriv(f), p, LONG_MAX);
     912      182543 :   return gc_long(av,v);
     913             : }
     914             : 
     915             : /* *e a ZX, *d, *z in Z, *d = p^(*vd). Simplify e / d by cancelling a
     916             :  * common factor p^v; if z!=NULL, update it by cancelling the same power of p */
     917             : static void
     918     3527963 : update_den(GEN p, GEN *e, GEN *d, long *vd, GEN *z)
     919             : {
     920             :   GEN newe;
     921     3527963 :   long ve = ZX_pvalrem(*e, p, &newe);
     922     3527949 :   if (ve) {
     923             :     GEN newd;
     924     1732642 :     long v = minss(*vd, ve);
     925     1732636 :     if (v) {
     926     1732706 :       if (v == *vd)
     927             :       { /* rare, denominator cancelled */
     928      377672 :         if (ve != v) newe = ZX_Z_mul(newe, powiu(p, ve - v));
     929      377672 :         newd = gen_1;
     930      377672 :         *vd = 0;
     931      377672 :         if (z) *z =diviiexact(*z, powiu(p, v));
     932             :       }
     933             :       else
     934             :       { /* v = ve < vd, generic case */
     935     1355034 :         GEN q = powiu(p, v);
     936     1355085 :         newd = diviiexact(*d, q);
     937     1354931 :         *vd -= v;
     938     1354931 :         if (z) *z = diviiexact(*z, q);
     939             :       }
     940     1732573 :       *e = newe;
     941     1732573 :       *d = newd;
     942             :     }
     943             :   }
     944     3527810 : }
     945             : 
     946             : /* return denominator, a power of p */
     947             : static GEN
     948     2727044 : QpX_denom(GEN x)
     949             : {
     950     2727044 :   long i, l = lg(x);
     951     2727044 :   GEN maxd = gen_1;
     952     9402656 :   for (i=2; i<l; i++)
     953             :   {
     954     6675621 :     GEN d = gel(x,i);
     955     6675621 :     if (typ(d) == t_FRAC && cmpii(gel(d,2), maxd) > 0) maxd = gel(d,2);
     956             :   }
     957     2727035 :   return maxd;
     958             : }
     959             : static GEN
     960      506154 : QpXV_denom(GEN x)
     961             : {
     962      506154 :   long l = lg(x), i;
     963      506154 :   GEN maxd = gen_1;
     964     1503448 :   for (i = 1; i < l; i++)
     965             :   {
     966      997294 :     GEN d = QpX_denom(gel(x,i));
     967      997294 :     if (cmpii(d, maxd) > 0) maxd = d;
     968             :   }
     969      506154 :   return maxd;
     970             : }
     971             : 
     972             : static GEN
     973     1729766 : QpX_remove_denom(GEN x, GEN p, GEN *pdx, long *pv)
     974             : {
     975     1729766 :   *pdx = QpX_denom(x);
     976     1729768 :   if (*pdx == gen_1) { *pv = 0; *pdx = NULL; }
     977             :   else {
     978     1256250 :     x = Q_muli_to_int(x,*pdx);
     979     1256184 :     *pv = Z_pval(*pdx, p);
     980             :   }
     981     1729709 :   return x;
     982             : }
     983             : 
     984             : /* p^v * f o g mod (T,q). q = p^vq  */
     985             : static GEN
     986      284985 : compmod(GEN p, GEN f, GEN g, GEN T, GEN q, long v)
     987             : {
     988      284985 :   GEN D = NULL, z, df, dg, qD;
     989      284985 :   long vD = 0, vdf, vdg;
     990             : 
     991      284985 :   f = QpX_remove_denom(f, p, &df, &vdf);
     992      284988 :   if (typ(g) == t_VEC) /* [num,den,v_p(den)] */
     993           0 :   { vdg = itos(gel(g,3)); dg = gel(g,2); g = gel(g,1); }
     994             :   else
     995      284988 :     g = QpX_remove_denom(g, p, &dg, &vdg);
     996      284988 :   if (df) { D = df; vD = vdf; }
     997      284988 :   if (dg) {
     998       55148 :     long degf = degpol(f);
     999       55148 :     D = mul_content(D, powiu(dg, degf));
    1000       55147 :     vD += degf * vdg;
    1001             :   }
    1002      284987 :   qD = D ? mulii(q, D): q;
    1003      284985 :   if (dg) f = FpX_rescale(f, dg, qD);
    1004      284985 :   z = FpX_FpXQ_eval(f, g, T, qD);
    1005      284981 :   if (!D) {
    1006           0 :     if (v) {
    1007           0 :       if (v > 0)
    1008           0 :         z = ZX_Z_mul(z, powiu(p, v));
    1009             :       else
    1010           0 :         z = RgX_Rg_div(z, powiu(p, -v));
    1011             :     }
    1012           0 :     return z;
    1013             :   }
    1014      284981 :   update_den(p, &z, &D, &vD, NULL);
    1015      284985 :   qD = mulii(D,q);
    1016      284981 :   if (v) vD -= v;
    1017      284981 :   z = FpX_center_i(z, qD, shifti(qD,-1));
    1018      284983 :   if (vD > 0)
    1019      284983 :     z = RgX_Rg_div(z, powiu(p, vD));
    1020           0 :   else if (vD < 0)
    1021           0 :     z = ZX_Z_mul(z, powiu(p, -vD));
    1022      284991 :   return z;
    1023             : }
    1024             : 
    1025             : /* fast implementation of ZM_hnfmodid(M, D) / D, D = p^k */
    1026             : static GEN
    1027      451940 : ZpM_hnfmodid(GEN M, GEN p, GEN D)
    1028             : {
    1029      451940 :   long i, l = lg(M);
    1030      451940 :   M = RgM_Rg_div(ZpM_echelon(M,0,p,D), D);
    1031     2014749 :   for (i = 1; i < l; i++)
    1032     1562805 :     if (gequal0(gcoeff(M,i,i))) gcoeff(M,i,i) = gen_1;
    1033      451944 :   return M;
    1034             : }
    1035             : 
    1036             : /* Return Z-basis for Z[a] + U(a)/p Z[a] in Z[t]/(f), mf = v_p(disc f), U
    1037             :  * a ZX. Special cases: a = t is coded as NULL, U = 0 is coded as NULL */
    1038             : static GEN
    1039      618038 : dbasis(GEN p, GEN f, long mf, GEN a, GEN U)
    1040             : {
    1041      618038 :   long n = degpol(f), i, dU;
    1042             :   GEN b, h;
    1043             : 
    1044      618035 :   if (n == 1) return matid(1);
    1045      618035 :   if (a && gequalX(a)) a = NULL;
    1046      618034 :   if (DEBUGLEVEL>5)
    1047             :   {
    1048           0 :     err_printf("  entering Dedekind Basis with parameters p=%Ps\n",p);
    1049           0 :     err_printf("  f = %Ps,\n  a = %Ps\n",f, a? a: pol_x(varn(f)));
    1050             :   }
    1051      618036 :   if (a)
    1052             :   {
    1053      198867 :     GEN pd = powiu(p, mf >> 1);
    1054      198866 :     GEN da, pdp = mulii(pd,p), D = pdp;
    1055             :     long vda;
    1056      198865 :     dU = U ? degpol(U): 0;
    1057      198864 :     b = cgetg(n+1, t_MAT);
    1058      198865 :     h = scalarpol(pd, varn(f));
    1059      198865 :     a = QpX_remove_denom(a, p, &da, &vda);
    1060      198868 :     if (da) D = mulii(D, da);
    1061      198865 :     gel(b,1) = scalarcol_shallow(pd, n);
    1062      565512 :     for (i=2; i<=n; i++)
    1063             :     {
    1064      366646 :       if (i == dU+1)
    1065           0 :         h = compmod(p, U, mkvec3(a,da,stoi(vda)), f, pdp, (mf>>1) - 1);
    1066             :       else
    1067             :       {
    1068      366646 :         h = FpXQ_mul(h, a, f, D);
    1069      366638 :         if (da) h = ZX_Z_divexact(h, da);
    1070             :       }
    1071      366629 :       gel(b,i) = RgX_to_RgC(h,n);
    1072             :     }
    1073      198866 :     return ZpM_hnfmodid(b, p, pd);
    1074             :   }
    1075             :   else
    1076             :   {
    1077      419169 :     if (!U) return matid(n);
    1078      419169 :     dU = degpol(U);
    1079      419169 :     if (dU == n) return matid(n);
    1080      419169 :     U = FpX_normalize(U, p);
    1081      419172 :     b = cgetg(n+1, t_MAT);
    1082     1620935 :     for (i = 1; i <= dU; i++) gel(b,i) = vec_ei(n, i);
    1083      419174 :     h = RgX_Rg_div(U, p);
    1084      470731 :     for ( ; i <= n; i++)
    1085             :     {
    1086      470731 :       gel(b, i) = RgX_to_RgC(h,n);
    1087      470730 :       if (i == n) break;
    1088       51553 :       h = RgX_shift_shallow(h,1);
    1089             :     }
    1090      419177 :     return b;
    1091             :   }
    1092             : }
    1093             : 
    1094             : static GEN
    1095      506157 : get_partial_order_as_pols(GEN p, GEN f)
    1096             : {
    1097      506157 :   GEN O = maxord(p, f, -1);
    1098      506150 :   long v = varn(f);
    1099      506150 :   return O == gen_1? pol_x_powers(degpol(f), v): RgM_to_RgXV(O, v);
    1100             : }
    1101             : 
    1102             : static long
    1103        2198 : p_is_prime(decomp_t *S)
    1104             : {
    1105        2198 :   if (S->pisprime < 0) S->pisprime = BPSW_psp(S->p);
    1106        2198 :   return S->pisprime;
    1107             : }
    1108             : static GEN ZpX_monic_factor_squarefree(GEN f, GEN p, long prec);
    1109             : 
    1110             : /* if flag = 0, maximal order, else factorization to precision r = flag */
    1111             : static GEN
    1112      253363 : Decomp(decomp_t *S, long flag)
    1113             : {
    1114      253363 :   pari_sp av = avma;
    1115             :   GEN fred, pr2, pr, pk, ph2, ph, b1, b2, a, e, de, f1, f2, dt, th, chip;
    1116      253363 :   GEN p = S->p;
    1117      253363 :   long vde, vdt, k, r = maxss(flag, 2*S->df + 1);
    1118             : 
    1119      253363 :   if (DEBUGLEVEL>5) err_printf("  entering Decomp: %Ps^%ld\n  f = %Ps\n",
    1120             :                                p, r, S->f);
    1121      253363 :   else if (DEBUGLEVEL>2) err_printf("  entering Decomp\n");
    1122      253363 :   chip = FpX_red(S->chi, p);
    1123      253358 :   if (!FpX_valrem(chip, S->nu, p, &b1))
    1124             :   {
    1125           0 :     if (!p_is_prime(S)) pari_err_PRIME("Decomp",p);
    1126           0 :     pari_err_BUG("Decomp (not a factor)");
    1127             :   }
    1128      253362 :   b2 = FpX_div(chip, b1, p);
    1129      253359 :   a = FpX_mul(FpXQ_inv(b2, b1, p), b2, p);
    1130             :   /* E = e / de, e in Z[X], de in Z,  E = a(phi) mod (f, p) */
    1131      253357 :   th = QpX_remove_denom(S->phi, p, &dt, &vdt);
    1132      253359 :   if (dt)
    1133             :   {
    1134      122244 :     long dega = degpol(a);
    1135      122244 :     vde = dega * vdt;
    1136      122244 :     de = powiu(dt, dega);
    1137      122245 :     pr = mulii(p, de);
    1138      122244 :     a = FpX_rescale(a, dt, pr);
    1139             :   }
    1140             :   else
    1141             :   {
    1142      131115 :     vde = 0;
    1143      131115 :     de = gen_1;
    1144      131115 :     pr = p;
    1145             :   }
    1146      253360 :   e = FpX_FpXQ_eval(a, th, S->f, pr);
    1147      253363 :   update_den(p, &e, &de, &vde, NULL);
    1148             : 
    1149      253362 :   pk = p; k = 1;
    1150             :   /* E, (1 - E) tend to orthogonal idempotents in Zp[X]/(f) */
    1151     1171662 :   while (k < r + vde)
    1152             :   { /* E <-- E^2(3-2E) mod p^2k, with E = e/de */
    1153             :     GEN D;
    1154      918302 :     pk = sqri(pk); k <<= 1;
    1155      918287 :     e = ZX_mul(ZX_sqr(e), Z_ZX_sub(mului(3,de), gmul2n(e,1)));
    1156      918309 :     de= mulii(de, sqri(de));
    1157      918272 :     vde *= 3;
    1158      918272 :     D = mulii(pk, de);
    1159      918272 :     e = FpX_rem(e, centermod(S->f, D), D); /* e/de defined mod pk */
    1160      918271 :     update_den(p, &e, &de, &vde, NULL);
    1161             :   }
    1162             :   /* required precision of the factors */
    1163      253360 :   pr = powiu(p, r); pr2 = shifti(pr, -1);
    1164      253360 :   ph = mulii(de,pr);ph2 = shifti(ph, -1);
    1165      253357 :   e = FpX_center_i(FpX_red(e, ph), ph, ph2);
    1166      253366 :   fred = FpX_red(S->f, ph);
    1167             : 
    1168      253363 :   f1 = ZpX_gcd(fred, Z_ZX_sub(de, e), p, ph); /* p-adic gcd(f, 1-e) */
    1169      253364 :   if (!is_pm1(de))
    1170             :   {
    1171      122248 :     fred = FpX_red(fred, pr);
    1172      122248 :     f1 = FpX_red(f1, pr);
    1173             :   }
    1174      253362 :   f2 = FpX_div(fred,f1, pr);
    1175      253362 :   f1 = FpX_center_i(f1, pr, pr2);
    1176      253364 :   f2 = FpX_center_i(f2, pr, pr2);
    1177             : 
    1178      253361 :   if (DEBUGLEVEL>5)
    1179           0 :     err_printf("  leaving Decomp: f1 = %Ps\nf2 = %Ps\ne = %Ps\nde= %Ps\n", f1,f2,e,de);
    1180             : 
    1181      253361 :   if (flag < 0)
    1182             :   {
    1183           0 :     GEN m = vconcat(ZpX_primedec(f1, p), ZpX_primedec(f2, p));
    1184           0 :     return sort_factor(m, (void*)&cmpii, &cmp_nodata);
    1185             :   }
    1186      253361 :   else if (flag)
    1187             :   {
    1188         287 :     gerepileall(av, 2, &f1, &f2);
    1189         287 :     return shallowconcat(ZpX_monic_factor_squarefree(f1, p, flag),
    1190             :                          ZpX_monic_factor_squarefree(f2, p, flag));
    1191             :   } else {
    1192             :     GEN D, d1, d2, B1, B2, M;
    1193             :     long n, n1, n2, i;
    1194      253074 :     gerepileall(av, 4, &f1, &f2, &e, &de);
    1195      253079 :     D = de;
    1196      253079 :     B1 = get_partial_order_as_pols(p,f1); n1 = lg(B1)-1;
    1197      253078 :     B2 = get_partial_order_as_pols(p,f2); n2 = lg(B2)-1; n = n1+n2;
    1198      253078 :     d1 = QpXV_denom(B1);
    1199      253077 :     d2 = QpXV_denom(B2); if (cmpii(d1, d2) < 0) d1 = d2;
    1200      253078 :     if (d1 != gen_1) {
    1201      155849 :       B1 = Q_muli_to_int(B1, d1);
    1202      155849 :       B2 = Q_muli_to_int(B2, d1);
    1203      155848 :       D = mulii(d1, D);
    1204             :     }
    1205      253077 :     fred = centermod_i(S->f, D, shifti(D,-1));
    1206      253076 :     M = cgetg(n+1, t_MAT);
    1207      799717 :     for (i=1; i<=n1; i++)
    1208      546641 :       gel(M,i) = RgX_to_RgC(FpX_rem(FpX_mul(gel(B1,i),e,D), fred, D), n);
    1209      253076 :     e = Z_ZX_sub(de, e); B2 -= n1;
    1210      703724 :     for (   ; i<=n; i++)
    1211      450649 :       gel(M,i) = RgX_to_RgC(FpX_rem(FpX_mul(gel(B2,i),e,D), fred, D), n);
    1212      253075 :     return ZpM_hnfmodid(M, p, D);
    1213             :   }
    1214             : }
    1215             : 
    1216             : /* minimum extension valuation: L/E */
    1217             : static void
    1218      618915 : vstar(GEN p,GEN h, long *L, long *E)
    1219             : {
    1220      618915 :   long first, j, k, v, w, m = degpol(h);
    1221             : 
    1222      618915 :   first = 1; k = 1; v = 0;
    1223     2549051 :   for (j=1; j<=m; j++)
    1224             :   {
    1225     1930129 :     GEN c = gel(h, m-j+2);
    1226     1930129 :     if (signe(c))
    1227             :     {
    1228     1855846 :       w = Z_pval(c,p);
    1229     1855853 :       if (first || w*k < v*j) { v = w; k = j; }
    1230     1855853 :       first = 0;
    1231             :     }
    1232             :   }
    1233             :   /* v/k = min_j ( v_p(h_{m-j}) / j ) */
    1234      618922 :   w = (long)ugcd(v,k);
    1235      618925 :   *L = v/w;
    1236      618925 :   *E = k/w;
    1237      618925 : }
    1238             : 
    1239             : static GEN
    1240       63454 : redelt_i(GEN a, GEN N, GEN p, GEN *pda, long *pvda)
    1241             : {
    1242             :   GEN z;
    1243       63454 :   a = Q_remove_denom(a, pda);
    1244       63452 :   *pvda = 0;
    1245       63452 :   if (*pda)
    1246             :   {
    1247       63452 :     long v = Z_pvalrem(*pda, p, &z);
    1248       63452 :     if (v) {
    1249       63452 :       *pda = powiu(p, v);
    1250       63452 :       *pvda = v;
    1251       63452 :       N  = mulii(*pda, N);
    1252             :     }
    1253             :     else
    1254           0 :       *pda = NULL;
    1255       63449 :     if (!is_pm1(z)) a = ZX_Z_mul(a, Fp_inv(z, N));
    1256             :   }
    1257       63449 :   return centermod(a, N);
    1258             : }
    1259             : /* reduce the element a modulo N [ a power of p ], taking first care of the
    1260             :  * denominators */
    1261             : static GEN
    1262       48011 : redelt(GEN a, GEN N, GEN p)
    1263             : {
    1264             :   GEN da;
    1265             :   long vda;
    1266       48011 :   a = redelt_i(a, N, p, &da, &vda);
    1267       48011 :   if (da) a = RgX_Rg_div(a, da);
    1268       48010 :   return a;
    1269             : }
    1270             : 
    1271             : /* compute the c first Newton sums modulo pp of the
    1272             :    characteristic polynomial of a/d mod chi, d > 0 power of p (NULL = gen_1),
    1273             :    a, chi in Zp[X], vda = v_p(da)
    1274             :    ns = Newton sums of chi */
    1275             : static GEN
    1276      699641 : newtonsums(GEN p, GEN a, GEN da, long vda, GEN chi, long c, GEN pp, GEN ns)
    1277             : {
    1278             :   GEN va, pa, dpa, s;
    1279      699641 :   long j, k, vdpa, lns = lg(ns);
    1280             :   pari_sp av;
    1281             : 
    1282      699641 :   a = centermod(a, pp); av = avma;
    1283      699621 :   dpa = pa = NULL; /* -Wall */
    1284      699621 :   vdpa = 0;
    1285      699621 :   va = zerovec(c);
    1286     2876824 :   for (j = 1; j <= c; j++)
    1287             :   { /* pa/dpa = (a/d)^(j-1) mod (chi, pp), dpa = p^vdpa */
    1288             :     long l;
    1289     2183865 :     pa = j == 1? a: FpXQ_mul(pa, a, chi, pp);
    1290     2184010 :     l = lg(pa); if (l == 2) break;
    1291     2184010 :     if (lns < l) l = lns;
    1292             : 
    1293     2184010 :     if (da) {
    1294     2049546 :       dpa = j == 1? da: mulii(dpa, da);
    1295     2049438 :       vdpa += vda;
    1296     2049438 :       update_den(p, &pa, &dpa, &vdpa, &pp);
    1297             :     }
    1298     2183763 :     s = mulii(gel(pa,2), gel(ns,2)); /* k = 2 */
    1299    10742910 :     for (k = 3; k < l; k++) s = addii(s, mulii(gel(pa,k), gel(ns,k)));
    1300     2183594 :     if (da) {
    1301             :       GEN r;
    1302     2049154 :       s = dvmdii(s, dpa, &r);
    1303     2049082 :       if (r != gen_0) return NULL;
    1304             :     }
    1305     2176915 :     gel(va,j) = centermodii(s, pp, shifti(pp,-1));
    1306             : 
    1307     2176970 :     if (gc_needed(av, 1))
    1308             :     {
    1309           7 :       if(DEBUGMEM>1) pari_warn(warnmem, "newtonsums");
    1310           7 :       gerepileall(av, dpa?4:3, &pa, &va, &pp, &dpa);
    1311             :     }
    1312             :   }
    1313      692959 :   for (; j <= c; j++) gel(va,j) = gen_0;
    1314      692959 :   return va;
    1315             : }
    1316             : 
    1317             : /* compute the characteristic polynomial of a/da mod chi (a in Z[X]), given
    1318             :  * by its Newton sums to a precision of pp using Newton sums */
    1319             : static GEN
    1320      692964 : newtoncharpoly(GEN pp, GEN p, GEN NS)
    1321             : {
    1322      692964 :   long n = lg(NS)-1, j, k;
    1323      692964 :   GEN c = cgetg(n + 2, t_VEC), pp2 = shifti(pp,-1);
    1324             : 
    1325      692982 :   gel(c,1) = (n & 1 ? gen_m1: gen_1);
    1326     2860104 :   for (k = 2; k <= n+1; k++)
    1327             :   {
    1328     2167176 :     pari_sp av2 = avma;
    1329     2167176 :     GEN s = gen_0;
    1330             :     ulong z;
    1331     2167176 :     long v = u_pvalrem(k - 1, p, &z);
    1332     9121873 :     for (j = 1; j < k; j++)
    1333             :     {
    1334     6955351 :       GEN t = mulii(gel(NS,j), gel(c,k-j));
    1335     6954780 :       if (!odd(j)) t = negi(t);
    1336     6954915 :       s = addii(s, t);
    1337             :     }
    1338     2166522 :     if (v) {
    1339      828953 :       s = gdiv(s, powiu(p, v));
    1340      828972 :       if (typ(s) != t_INT) return NULL;
    1341             :     }
    1342     2166457 :     s = mulii(s, Fp_inv(utoipos(z), pp));
    1343     2166820 :     gel(c,k) = gerepileuptoint(av2, Fp_center_i(s, pp, pp2));
    1344             :   }
    1345     1840429 :   for (k = odd(n)? 1: 2; k <= n+1; k += 2) gel(c,k) = negi(gel(c,k));
    1346      692933 :   return gtopoly(c, 0);
    1347             : }
    1348             : 
    1349             : static void
    1350      699569 : manage_cache(decomp_t *S, GEN f, GEN pp)
    1351             : {
    1352      699569 :   GEN t = S->precns;
    1353             : 
    1354      699569 :   if (!t) t = mulii(S->pmf, powiu(S->p, S->df));
    1355      699572 :   if (cmpii(t, pp) < 0) t = pp;
    1356             : 
    1357      699580 :   if (!S->precns || !RgX_equal(f, S->nsf) || cmpii(S->precns, t) < 0)
    1358             :   {
    1359      517929 :     if (DEBUGLEVEL>4)
    1360           0 :       err_printf("  Precision for cached Newton sums for %Ps: %Ps -> %Ps\n",
    1361           0 :                  f, S->precns? S->precns: gen_0, t);
    1362      517929 :     S->nsf = f;
    1363      517929 :     S->ns = FpX_Newton(f, degpol(f), t);
    1364      517946 :     S->precns = t;
    1365             :   }
    1366      699611 : }
    1367             : 
    1368             : /* return NULL if a mod f is not an integer
    1369             :  * The denominator of any integer in Zp[X]/(f) divides pdr */
    1370             : static GEN
    1371      699631 : mycaract(decomp_t *S, GEN f, GEN a, GEN pp, GEN pdr)
    1372             : {
    1373             :   pari_sp av;
    1374             :   GEN d, chi, prec1, prec2, prec3, ns;
    1375      699631 :   long vd, n = degpol(f);
    1376             : 
    1377      699631 :   if (gequal0(a)) return pol_0(varn(f));
    1378             : 
    1379      699631 :   a = QpX_remove_denom(a, S->p, &d, &vd);
    1380      699618 :   prec1 = pp;
    1381      699618 :   if (lgefint(S->p) == 3)
    1382      699566 :     prec1 = mulii(prec1, powiu(S->p, factorial_lval(n, itou(S->p))));
    1383      699582 :   if (d)
    1384             :   {
    1385      635033 :     GEN p1 = powiu(d, n);
    1386      635062 :     prec2 = mulii(prec1, p1);
    1387      635035 :     prec3 = mulii(prec1, gmin_shallow(mulii(p1, d), pdr));
    1388             :   }
    1389             :   else
    1390       64549 :     prec2 = prec3 = prec1;
    1391      699575 :   manage_cache(S, f, prec3);
    1392             : 
    1393      699639 :   av = avma;
    1394      699639 :   ns = newtonsums(S->p, a, d, vd, f, n, prec2, S->ns);
    1395      699566 :   if (!ns) return NULL;
    1396      692959 :   chi = newtoncharpoly(prec1, S->p, ns);
    1397      693026 :   if (!chi) return NULL;
    1398      692942 :   setvarn(chi, varn(f));
    1399      692942 :   return gerepileupto(av, centermod(chi, pp));
    1400             : }
    1401             : 
    1402             : static GEN
    1403      635749 : get_nu(GEN chi, GEN p, long *ptl)
    1404             : { /* split off powers of x first for efficiency */
    1405      635749 :   long v = ZX_valrem(FpX_red(chi,p), &chi), n;
    1406             :   GEN P;
    1407      635738 :   if (!degpol(chi)) { *ptl = 1; return pol_x(varn(chi)); }
    1408      470948 :   P = gel(FpX_factor(chi,p), 1); n = lg(P)-1;
    1409      470964 :   *ptl = v? n+1: n; return gel(P,n);
    1410             : }
    1411             : 
    1412             : /* Factor characteristic polynomial chi of phi mod p. If it splits, update
    1413             :  * S->{phi, chi, nu} and return 1. In any case, set *nu to an irreducible
    1414             :  * factor mod p of chi */
    1415             : static int
    1416      475569 : split_char(decomp_t *S, GEN chi, GEN phi, GEN phi0, GEN *nu)
    1417             : {
    1418             :   long l;
    1419      475569 :   *nu  = get_nu(chi, S->p, &l);
    1420      475577 :   if (l == 1) return 0; /* single irreducible factor: doesn't split */
    1421             :   /* phi o phi0 mod (p, f) */
    1422      122251 :   S->phi = compmod(S->p, phi, phi0, S->f, S->p, 0);
    1423      122250 :   S->chi = chi;
    1424      122250 :   S->nu = *nu; return 1;
    1425             : }
    1426             : 
    1427             : /* Return the prime element in Zp[phi], a t_INT (iff *Ep = 1) or QX;
    1428             :  * nup, chip are ZX. phi = NULL codes X
    1429             :  * If *Ep < oE or Ep divides Ediv (!=0) return NULL (uninteresting) */
    1430             : static GEN
    1431      558454 : getprime(decomp_t *S, GEN phi, GEN chip, GEN nup, long *Lp, long *Ep,
    1432             :          long oE, long Ediv)
    1433             : {
    1434             :   GEN z, chin, q, qp;
    1435             :   long r, s;
    1436             : 
    1437      558454 :   if (phi && dvdii(constant_coeff(chip), S->psc))
    1438             :   {
    1439        1636 :     chip = mycaract(S, S->chi, phi, S->pmf, S->prc);
    1440        1636 :     if (dvdii(constant_coeff(chip), S->pmf))
    1441        1242 :       chip = ZXQ_charpoly(phi, S->chi, varn(chip));
    1442             :   }
    1443      558455 :   if (degpol(nup) == 1)
    1444             :   {
    1445      520265 :     GEN c = gel(nup,2); /* nup = X + c */
    1446      520265 :     chin = signe(c)? RgX_translate(chip, negi(c)): chip;
    1447             :   }
    1448             :   else
    1449       38190 :     chin = ZXQ_charpoly(nup, chip, varn(chip));
    1450             : 
    1451      558461 :   vstar(S->p, chin, Lp, Ep);
    1452      558473 :   if (*Ep < oE || (Ediv && Ediv % *Ep == 0)) return NULL;
    1453             : 
    1454      439886 :   if (*Ep == 1) return S->p;
    1455      303351 :   (void)cbezout(*Lp, -*Ep, &r, &s); /* = 1 */
    1456      303354 :   if (r <= 0)
    1457             :   {
    1458       60030 :     long t = 1 + ((-r) / *Ep);
    1459       60030 :     r += t * *Ep;
    1460       60030 :     s += t * *Lp;
    1461             :   }
    1462             :   /* r > 0 minimal such that r L/E - s = 1/E
    1463             :    * pi = nu^r / p^s is an element of valuation 1/E,
    1464             :    * so is pi + O(p) since 1/E < 1. May compute nu^r mod p^(s+1) */
    1465      303354 :   q = powiu(S->p, s); qp = mulii(q, S->p);
    1466      303339 :   nup = FpXQ_powu(nup, r, S->chi, qp);
    1467      303349 :   if (!phi) return RgX_Rg_div(nup, q); /* phi = X : no composition */
    1468       48011 :   z = compmod(S->p, nup, phi, S->chi, qp, -s);
    1469       48011 :   return signe(z)? z: NULL;
    1470             : }
    1471             : 
    1472             : static int
    1473      274910 : update_phi(decomp_t *S)
    1474             : {
    1475      274910 :   GEN PHI = NULL, prc, psc, X = pol_x(varn(S->f));
    1476             :   long k, vpsc;
    1477      274908 :   for (k = 1;; k++)
    1478             :   {
    1479      277190 :     prc = ZpX_reduced_resultant_fast(S->chi, ZX_deriv(S->chi), S->p, S->vpsc);
    1480             :     /* if prc == S->psc then either chi is not separable or
    1481             :        the reduced discriminant of chi is too large */
    1482      277191 :     if (!equalii(prc, S->psc)) break;
    1483             : 
    1484             :     /* increase precision */
    1485        2282 :     S->vpsc = maxss(S->vpsf, S->vpsc + 1);
    1486        2282 :     S->psc = (S->vpsc == S->vpsf)? S->psf: mulii(S->psc, S->p);
    1487             : 
    1488        2282 :     PHI = S->phi;
    1489        2282 :     if (S->phi0) PHI = compmod(S->p, PHI, S->phi0, S->f, S->psc, 0);
    1490             :     /* change phi (in case not separable) */
    1491        2282 :     PHI = gadd(PHI, ZX_Z_mul(X, mului(k, S->p)));
    1492        2282 :     S->chi = mycaract(S, S->f, PHI, S->psc, S->pdf);
    1493             :   }
    1494      274909 :   psc = mulii(sqri(prc), S->p);
    1495      274903 :   vpsc = 2*Z_pval(prc, S->p) + 1;
    1496             : 
    1497      274902 :   if (!PHI) /* break out of above loop immediately (k = 1) */
    1498             :   {
    1499      272621 :     PHI = S->phi;
    1500      272621 :     if (S->phi0) PHI = compmod(S->p, PHI, S->phi0, S->f, psc, 0);
    1501      272622 :     if (S->phi0 || cmpii(psc,S->psc) > 0)
    1502             :     {
    1503             :       for(;;)
    1504             :       {
    1505      113024 :         S->chi = mycaract(S, S->f, PHI, psc, S->pdf);
    1506      113029 :         prc = ZpX_reduced_resultant_fast(S->chi, ZX_deriv(S->chi), S->p, vpsc);
    1507      113029 :         if (!equalii(prc, psc)) break;
    1508         497 :         psc = mulii(psc, S->p); vpsc++;
    1509             :         /* it can happen that S->chi is never squarefree: then change PHI */
    1510         497 :         if (vpsc > 2*S->mf) PHI = gadd(PHI, ZX_Z_mul(X, S->p));
    1511             :       }
    1512      112532 :       psc = mulii(sqri(prc), S->p);
    1513      112530 :       vpsc = 2*Z_pval(prc, S->p) + 1;
    1514             :     }
    1515             :   }
    1516      274906 :   S->phi = PHI;
    1517      274906 :   S->chi = FpX_red(S->chi, psc);
    1518             : 
    1519             :   /* may happen if p is unramified */
    1520      274902 :   if (is_pm1(prc)) return 0;
    1521      230455 :   S->prc = prc;
    1522      230455 :   S->psc = psc;
    1523      230455 :   S->vpsc = vpsc; return 1;
    1524             : }
    1525             : 
    1526             : /* return 1 if at least 2 factors mod p ==> chi splits
    1527             :  * Replace S->phi such that F increases (to D) */
    1528             : static int
    1529       66718 : testb2(decomp_t *S, long D, GEN theta)
    1530             : {
    1531       66718 :   long v = varn(S->chi), dlim = degpol(S->chi)-1;
    1532       66718 :   GEN T0 = S->phi, chi, phi, nu;
    1533       66718 :   if (DEBUGLEVEL>4) err_printf("  Increasing Fa\n");
    1534             :   for (;;)
    1535             :   {
    1536       66780 :     phi = gadd(theta, random_FpX(dlim, v, S->p));
    1537       66780 :     chi = mycaract(S, S->chi, phi, S->psf, S->prc);
    1538             :     /* phi nonprimary ? */
    1539       66779 :     if (split_char(S, chi, phi, T0, &nu)) return 1;
    1540       66781 :     if (degpol(nu) == D) break;
    1541             :   }
    1542             :   /* F_phi=lcm(F_alpha, F_theta)=D and E_phi=E_alpha */
    1543       66719 :   S->phi0 = T0;
    1544       66719 :   S->chi = chi;
    1545       66719 :   S->phi = phi;
    1546       66719 :   S->nu = nu; return 0;
    1547             : }
    1548             : 
    1549             : /* return 1 if at least 2 factors mod p ==> chi can be split.
    1550             :  * compute a new S->phi such that E = lcm(Ea, Et);
    1551             :  * A a ZX, T a t_INT (iff Et = 1, probably impossible ?) or QX */
    1552             : static int
    1553       48011 : testc2(decomp_t *S, GEN A, long Ea, GEN T, long Et)
    1554             : {
    1555       48011 :   GEN c, chi, phi, nu, T0 = S->phi;
    1556             : 
    1557       48011 :   if (DEBUGLEVEL>4) err_printf("  Increasing Ea\n");
    1558       48011 :   if (Et == 1) /* same as other branch, split for efficiency */
    1559           0 :     c = A; /* Et = 1 => s = 1, r = 0, t = 0 */
    1560             :   else
    1561             :   {
    1562             :     long r, s, t;
    1563       48011 :     (void)cbezout(Ea, Et, &r, &s); t = 0;
    1564       48109 :     while (r < 0) { r = r + Et; t++; }
    1565       48193 :     while (s < 0) { s = s + Ea; t++; }
    1566             : 
    1567             :     /* A^s T^r / p^t */
    1568       48011 :     c = RgXQ_mul(RgXQ_powu(A, s, S->chi), RgXQ_powu(T, r, S->chi), S->chi);
    1569       48011 :     c = RgX_Rg_div(c, powiu(S->p, t));
    1570       48011 :     c = redelt(c, S->psc, S->p);
    1571             :   }
    1572       48010 :   phi = RgX_add(c,  pol_x(varn(S->chi)));
    1573       48011 :   chi = mycaract(S, S->chi, phi, S->psf, S->prc);
    1574       48011 :   if (split_char(S, chi, phi, T0, &nu)) return 1;
    1575             :   /* E_phi = lcm(E_alpha,E_theta) */
    1576       48011 :   S->phi0 = T0;
    1577       48011 :   S->chi = chi;
    1578       48011 :   S->phi = phi;
    1579       48011 :   S->nu = nu; return 0;
    1580             : }
    1581             : 
    1582             : /* Return h^(-degpol(P)) P(x * h) if result is integral, NULL otherwise */
    1583             : static GEN
    1584       59752 : ZX_rescale_inv(GEN P, GEN h)
    1585             : {
    1586       59752 :   long i, l = lg(P);
    1587       59752 :   GEN Q = cgetg(l,t_POL), hi = h;
    1588       59752 :   gel(Q,l-1) = gel(P,l-1);
    1589      173339 :   for (i=l-2; i>=2; i--)
    1590             :   {
    1591             :     GEN r;
    1592      173337 :     gel(Q,i) = dvmdii(gel(P,i), hi, &r);
    1593      173338 :     if (signe(r)) return NULL;
    1594      173338 :     if (i == 2) break;
    1595      113586 :     hi = mulii(hi,h);
    1596             :   }
    1597       59754 :   Q[1] = P[1]; return Q;
    1598             : }
    1599             : 
    1600             : /* x p^-eq nu^-er mod p */
    1601             : static GEN
    1602      299760 : get_gamma(decomp_t *S, GEN x, long eq, long er)
    1603             : {
    1604      299760 :   GEN q, g = x, Dg = powiu(S->p, eq);
    1605      299756 :   long vDg = eq;
    1606      299756 :   if (er)
    1607             :   {
    1608       22142 :     if (!S->invnu)
    1609             :     {
    1610       15443 :       while (gdvd(S->chi, S->nu)) S->nu = RgX_Rg_add(S->nu, S->p);
    1611       15443 :       S->invnu = QXQ_inv(S->nu, S->chi);
    1612       15443 :       S->invnu = redelt_i(S->invnu, S->psc, S->p, &S->Dinvnu, &S->vDinvnu);
    1613             :     }
    1614       22142 :     if (S->Dinvnu) {
    1615       22142 :       Dg = mulii(Dg, powiu(S->Dinvnu, er));
    1616       22142 :       vDg += er * S->vDinvnu;
    1617             :     }
    1618       22142 :     q = mulii(S->p, Dg);
    1619       22142 :     g = ZX_mul(g, FpXQ_powu(S->invnu, er, S->chi, q));
    1620       22142 :     g = FpX_rem(g, S->chi, q);
    1621       22142 :     update_den(S->p, &g, &Dg, &vDg, NULL);
    1622       22142 :     g = centermod(g, mulii(S->p, Dg));
    1623             :   }
    1624      299756 :   if (!is_pm1(Dg)) g = RgX_Rg_div(g, Dg);
    1625      299757 :   return g;
    1626             : }
    1627             : static GEN
    1628      352818 : get_g(decomp_t *S, long Ea, long L, long E, GEN beta, GEN *pchig,
    1629             :       long *peq, long *per)
    1630             : {
    1631             :   long eq, er;
    1632      352818 :   GEN g, chig, chib = NULL;
    1633             :   for(;;) /* at most twice */
    1634             :   {
    1635      359509 :     if (L < 0)
    1636             :     {
    1637       60451 :       chib = ZXQ_charpoly(beta, S->chi, varn(S->chi));
    1638       60453 :       vstar(S->p, chib, &L, &E);
    1639             :     }
    1640      359511 :     eq = L / E; er = L*Ea / E - eq*Ea;
    1641             :     /* floor(L Ea/E) = eq Ea + er */
    1642      359511 :     if (er || !chib)
    1643             :     { /* g might not be an integer ==> chig = NULL */
    1644      299759 :       g = get_gamma(S, beta, eq, er);
    1645      299757 :       chig = mycaract(S, S->chi, g, S->psc, S->prc);
    1646             :     }
    1647             :     else
    1648             :     { /* g = beta/p^eq, special case of the above */
    1649       59752 :       GEN h = powiu(S->p, eq);
    1650       59752 :       g = RgX_Rg_div(beta, h);
    1651       59752 :       chig = ZX_rescale_inv(chib, h); /* chib(x h) / h^N */
    1652       59752 :       if (chig) chig = FpX_red(chig, S->pmf);
    1653             :     }
    1654             :     /* either success or second consecutive failure */
    1655      359508 :     if (chig || chib) break;
    1656             :     /* if g fails the v*-test, v(beta) was wrong. Retry once */
    1657        6691 :     L = -1;
    1658             :   }
    1659      352817 :   *pchig = chig; *peq = eq; *per = er; return g;
    1660             : }
    1661             : 
    1662             : /* return 1 if at least 2 factors mod p ==> chi can be split */
    1663             : static int
    1664      236978 : loop(decomp_t *S, long Ea)
    1665             : {
    1666      236978 :   pari_sp av = avma;
    1667      236978 :   GEN beta = FpXQ_powu(S->nu, Ea, S->chi, S->p);
    1668      236977 :   long N = degpol(S->f), v = varn(S->f);
    1669      236977 :   S->invnu = NULL;
    1670             :   for (;;)
    1671      115840 :   { /* beta tends to a factor of chi */
    1672             :     long L, i, Fg, eq, er;
    1673      352817 :     GEN chig = NULL, d, g, nug;
    1674             : 
    1675      352817 :     if (DEBUGLEVEL>4) err_printf("  beta = %Ps\n", beta);
    1676      352817 :     L = ZpX_resultant_val(S->chi, beta, S->p, S->mf+1);
    1677      352818 :     if (L > S->mf) L = -1; /* from scratch */
    1678      352818 :     g = get_g(S, Ea, L, N, beta, &chig, &eq, &er);
    1679      352817 :     if (DEBUGLEVEL>4) err_printf("  (eq,er) = (%ld,%ld)\n", eq,er);
    1680             :     /* g = beta p^-eq  nu^-er (a unit), chig = charpoly(g) */
    1681      469564 :     if (split_char(S, chig, g,S->phi, &nug)) return 1;
    1682             : 
    1683      232587 :     Fg = degpol(nug);
    1684      232587 :     if (Fg == 1)
    1685             :     { /* frequent special case nug = x - d */
    1686             :       long Le, Ee;
    1687             :       GEN chie, nue, e, pie;
    1688      157905 :       d = negi(gel(nug,2));
    1689      157905 :       chie = RgX_translate(chig, d);
    1690      157904 :       nue = pol_x(v);
    1691      157903 :       e = RgX_Rg_sub(g, d);
    1692      157902 :       pie = getprime(S, e, chie, nue, &Le, &Ee,  0,Ea);
    1693      157905 :       if (pie) return testc2(S, S->nu, Ea, pie, Ee);
    1694             :     }
    1695             :     else
    1696             :     {
    1697       74682 :       long Fa = degpol(S->nu), vdeng;
    1698             :       GEN deng, numg, nume;
    1699       78122 :       if (Fa % Fg) return testb2(S, ulcm(Fa,Fg), g);
    1700             :       /* nu & nug irreducible mod p, deg nug | deg nu. To improve beta, look
    1701             :        * for a root d of nug in Fp[phi] such that v_p(g - d) > 0 */
    1702        7964 :       if (ZX_equal(nug, S->nu))
    1703        5766 :         d = pol_x(v);
    1704             :       else
    1705             :       {
    1706        2198 :         if (!p_is_prime(S)) pari_err_PRIME("FpX_ffisom",S->p);
    1707        2198 :         d = FpX_ffisom(nug, S->nu, S->p);
    1708             :       }
    1709             :       /* write g = numg / deng, e = nume / deng */
    1710        7964 :       numg = QpX_remove_denom(g, S->p, &deng, &vdeng);
    1711       12631 :       for (i = 1; i <= Fg; i++)
    1712             :       {
    1713             :         GEN chie, nue, e;
    1714       12631 :         if (i != 1) d = FpXQ_pow(d, S->p, S->nu, S->p); /* next root */
    1715       12631 :         nume = ZX_sub(numg, ZX_Z_mul(d, deng));
    1716             :         /* test e = nume / deng */
    1717       12631 :         if (ZpX_resultant_val(S->chi, nume, S->p, vdeng*N+1) <= vdeng*N)
    1718        4667 :           continue;
    1719        7964 :         e = RgX_Rg_div(nume, deng);
    1720        7964 :         chie = mycaract(S, S->chi, e, S->psc, S->prc);
    1721        9387 :         if (split_char(S, chie, e,S->phi, &nue)) return 1;
    1722        5947 :         if (RgX_is_monomial(nue))
    1723             :         { /* v_p(e) = v_p(g - d) > 0 */
    1724             :           long Le, Ee;
    1725             :           GEN pie;
    1726        5947 :           pie = getprime(S, e, chie, nue, &Le, &Ee,  0,Ea);
    1727        5947 :           if (pie) return testc2(S, S->nu, Ea, pie, Ee);
    1728        4524 :           break;
    1729             :         }
    1730             :       }
    1731        4524 :       if (i > Fg)
    1732             :       {
    1733           0 :         if (!p_is_prime(S)) pari_err_PRIME("nilord",S->p);
    1734           0 :         pari_err_BUG("nilord (no root)");
    1735             :       }
    1736             :     }
    1737      115841 :     if (eq) d = gmul(d, powiu(S->p,  eq));
    1738      115837 :     if (er) d = gmul(d, gpowgs(S->nu, er));
    1739      115836 :     beta = gsub(beta, d);
    1740             : 
    1741      115840 :     if (gc_needed(av,1))
    1742             :     {
    1743           0 :       if (DEBUGMEM > 1) pari_warn(warnmem, "nilord");
    1744           0 :       gerepileall(av, S->invnu? 6: 4, &beta, &(S->precns), &(S->ns), &(S->nsf), &(S->invnu), &(S->Dinvnu));
    1745             :     }
    1746             :   }
    1747             : }
    1748             : 
    1749             : /* E and F cannot decrease; return 1 if O = Zp[phi], 2 if we can get a
    1750             :  * decomposition and 0 otherwise */
    1751             : static long
    1752      391864 : progress(decomp_t *S, GEN *ppa, long *pE)
    1753             : {
    1754      391864 :   long E = *pE, F;
    1755      391864 :   GEN pa = *ppa;
    1756      391864 :   S->phi0 = NULL; /* no delayed composition */
    1757             :   for(;;)
    1758        2745 :   {
    1759             :     long l, La, Ea; /* N.B If E = 0, getprime cannot return NULL */
    1760      394609 :     GEN pia  = getprime(S, NULL, S->chi, S->nu, &La, &Ea, E,0);
    1761      394623 :     if (pia) { /* success, we break out in THIS loop */
    1762      391877 :       pa = (typ(pia) == t_POL)? RgX_RgXQ_eval(pia, S->phi, S->f): pia;
    1763      391880 :       E = Ea;
    1764      391880 :       if (La == 1) break; /* no need to change phi so that nu = pia */
    1765             :     }
    1766             :     /* phi += prime elt */
    1767       64814 :     S->phi = typ(pa) == t_INT? RgX_Rg_add_shallow(S->phi, pa)
    1768      160182 :                              : RgX_add(S->phi, pa);
    1769             :     /* recompute char. poly. chi from scratch */
    1770      160182 :     S->chi = mycaract(S, S->f, S->phi, S->psf, S->pdf);
    1771      160183 :     S->nu = get_nu(S->chi, S->p, &l);
    1772      160180 :     if (l > 1) return 2;
    1773      160180 :     if (!update_phi(S)) return 1; /* unramified */
    1774      160179 :     if (pia) break;
    1775             :   }
    1776      391878 :   *pE = E; *ppa = pa; F = degpol(S->nu);
    1777      391878 :   if (DEBUGLEVEL>4) err_printf("  (E, F) = (%ld,%ld)\n", E, F);
    1778      391878 :   if (E * F == degpol(S->f)) return 1;
    1779      236977 :   if (loop(S, E)) return 2;
    1780      114730 :   if (!update_phi(S)) return 1;
    1781       70276 :   return 0;
    1782             : }
    1783             : 
    1784             : /* flag != 0 iff we're looking for the p-adic factorization,
    1785             :    in which case it is the p-adic precision we want */
    1786             : static GEN
    1787      452709 : maxord_i(decomp_t *S, GEN p, GEN f, long mf, GEN w, long flag)
    1788             : {
    1789      452709 :   long oE, n = lg(w)-1; /* factor of largest degree */
    1790      452709 :   GEN opa, D = ZpX_reduced_resultant_fast(f, ZX_deriv(f), p, mf);
    1791      452707 :   S->pisprime = -1;
    1792      452707 :   S->p = p;
    1793      452707 :   S->mf = mf;
    1794      452707 :   S->nu = gel(w,n);
    1795      452707 :   S->df = Z_pval(D, p);
    1796      452705 :   S->pdf = powiu(p, S->df);
    1797      452697 :   S->phi = pol_x(varn(f));
    1798      452698 :   S->chi = S->f = f;
    1799      452698 :   if (n > 1) return Decomp(S, flag); /* FIXME: use bezout_lift_fact */
    1800             : 
    1801      321587 :   if (DEBUGLEVEL>4)
    1802           0 :     err_printf("  entering Nilord: %Ps^%ld\n  f = %Ps, nu = %Ps\n",
    1803             :                p, S->df, S->f, S->nu);
    1804      321587 :   else if (DEBUGLEVEL>2) err_printf("  entering Nilord\n");
    1805      321587 :   S->psf = S->psc = mulii(sqri(D), p);
    1806      321585 :   S->vpsf = S->vpsc = 2*S->df + 1;
    1807      321585 :   S->prc = mulii(D, p);
    1808      321589 :   S->chi = FpX_red(S->f, S->psc);
    1809      321585 :   S->pmf = powiu(p, S->mf+1);
    1810      321589 :   S->precns = NULL;
    1811      321589 :   for(opa = NULL, oE = 0;;)
    1812       70275 :   {
    1813      391864 :     long n = progress(S, &opa, &oE);
    1814      391875 :     if (n == 1) return flag? NULL: dbasis(p, S->f, S->mf, S->phi, S->chi);
    1815      192525 :     if (n == 2) return Decomp(S, flag);
    1816             :   }
    1817             : }
    1818             : 
    1819             : static int
    1820         812 : expo_is_squarefree(GEN e)
    1821             : {
    1822         812 :   long i, l = lg(e);
    1823        1183 :   for (i=1; i<l; i++)
    1824         945 :     if (e[i] != 1) return 0;
    1825         238 :   return 1;
    1826             : }
    1827             : /* pure round 4 */
    1828             : static GEN
    1829         770 : ZpX_round4(GEN f, GEN p, GEN w, long prec)
    1830             : {
    1831             :   decomp_t S;
    1832         770 :   GEN L = maxord_i(&S, p, f, ZpX_disc_val(f,p), w, prec);
    1833         770 :   return L? L: mkvec(f);
    1834             : }
    1835             : /* f a squarefree ZX with leading_coeff 1, degree > 0. Return list of
    1836             :  * irreducible factors in Zp[X] (computed mod p^prec) */
    1837             : static GEN
    1838        1071 : ZpX_monic_factor_squarefree(GEN f, GEN p, long prec)
    1839             : {
    1840        1071 :   pari_sp av = avma;
    1841             :   GEN L, fa, w, e;
    1842             :   long i, l;
    1843        1071 :   if (degpol(f) == 1) return mkvec(f);
    1844         812 :   fa = FpX_factor(f,p); w = gel(fa,1); e = gel(fa,2);
    1845             :   /* no repeated factors: Hensel lift */
    1846         812 :   if (expo_is_squarefree(e)) return ZpX_liftfact(f, w, powiu(p,prec), p, prec);
    1847         574 :   l = lg(w);
    1848         574 :   if (l == 2)
    1849             :   {
    1850         371 :     L = ZpX_round4(f,p,w,prec);
    1851         371 :     if (lg(L) == 2) { set_avma(av); return mkvec(f); }
    1852             :   }
    1853             :   else
    1854             :   { /* >= 2 factors mod p: partial Hensel lift */
    1855         203 :     GEN D = ZpX_reduced_resultant_fast(f, ZX_deriv(f), p, ZpX_disc_val(f,p));
    1856         203 :     long r = maxss(2*Z_pval(D,p)+1, prec);
    1857         203 :     GEN W = cgetg(l, t_VEC);
    1858         665 :     for (i = 1; i < l; i++)
    1859         462 :       gel(W,i) = e[i] == 1? gel(w,i): FpX_powu(gel(w,i), e[i], p);
    1860         203 :     L = ZpX_liftfact(f, W, powiu(p,r), p, r);
    1861         665 :     for (i = 1; i < l; i++)
    1862         462 :       gel(L,i) = e[i] == 1? mkvec(gel(L,i))
    1863         462 :                           : ZpX_round4(gel(L,i), p, mkvec(gel(w,i)), prec);
    1864         203 :     L = shallowconcat1(L);
    1865             :   }
    1866         343 :   return gerepilecopy(av, L);
    1867             : }
    1868             : 
    1869             : /* assume T a ZX with leading_coeff 1, degree > 0 */
    1870             : GEN
    1871         490 : ZpX_monic_factor(GEN T, GEN p, long prec)
    1872             : {
    1873             :   GEN Q, P, E, F;
    1874             :   long L, l, i, v;
    1875             : 
    1876         490 :   if (degpol(T) == 1) return mkmat2(mkcol(T), mkcol(gen_1));
    1877         490 :   v = ZX_valrem(T, &T);
    1878         490 :   Q = ZX_squff(T, &F); l = lg(Q); L = v? l + 1: l;
    1879         490 :   P = cgetg(L, t_VEC);
    1880         490 :   E = cgetg(L, t_VEC);
    1881         987 :   for (i = 1; i < l; i++)
    1882             :   {
    1883         497 :     GEN w = ZpX_monic_factor_squarefree(gel(Q,i), p, prec);
    1884         497 :     gel(P,i) = w; settyp(w, t_COL);
    1885         497 :     gel(E,i) = const_col(lg(w)-1, utoipos(F[i]));
    1886             :   }
    1887         490 :   if (v) { gel(P,i) = pol_x(varn(T)); gel(E,i) = utoipos(v); }
    1888         490 :   return mkmat2(shallowconcat1(P), shallowconcat1(E));
    1889             : }
    1890             : 
    1891             : /* DT = multiple of disc(T) or NULL
    1892             :  * Return a multiple of the denominator of an algebraic integer (in Q[X]/(T))
    1893             :  * when expressed in terms of the power basis */
    1894             : GEN
    1895       44114 : indexpartial(GEN T, GEN DT)
    1896             : {
    1897       44114 :   pari_sp av = avma;
    1898             :   long i, nb;
    1899       44114 :   GEN fa, E, P, U, res = gen_1, dT = ZX_deriv(T);
    1900             : 
    1901       44110 :   if (!DT) DT = ZX_disc(T);
    1902       44110 :   fa = absZ_factor_limit_strict(DT, 0, &U);
    1903       44113 :   P = gel(fa,1);
    1904       44113 :   E = gel(fa,2); nb = lg(P)-1;
    1905      211900 :   for (i = 1; i <= nb; i++)
    1906             :   {
    1907      167786 :     long e = itou(gel(E,i)), e2 = e >> 1;
    1908      167786 :     GEN p = gel(P,i), q = p;
    1909      167786 :     if (e2 >= 2) q = ZpX_reduced_resultant_fast(T, dT, p, e2);
    1910      167792 :     res = mulii(res, q);
    1911             :   }
    1912       44114 :   if (U)
    1913             :   {
    1914        1921 :     long e = itou(gel(U,2)), e2 = e >> 1;
    1915        1921 :     GEN p = gel(U,1), q = powiu(p, odd(e)? e2+1: e2);
    1916        1921 :     res = mulii(res, q);
    1917             :   }
    1918       44114 :   return gerepileuptoint(av,res);
    1919             : }
    1920             : 
    1921             : /*******************************************************************/
    1922             : /*                                                                 */
    1923             : /*    2-ELT REPRESENTATION FOR PRIME IDEALS (dividing index)       */
    1924             : /*                                                                 */
    1925             : /*******************************************************************/
    1926             : /* to compute norm of elt in basis form */
    1927             : typedef struct {
    1928             :   long r1;
    1929             :   GEN M;  /* via embed_norm */
    1930             : 
    1931             :   GEN D, w, T; /* via resultant if M = NULL */
    1932             : } norm_S;
    1933             : 
    1934             : static GEN
    1935      501978 : get_norm(norm_S *S, GEN a)
    1936             : {
    1937      501978 :   if (S->M)
    1938             :   {
    1939             :     long e;
    1940      500572 :     GEN N = grndtoi( embed_norm(RgM_RgC_mul(S->M, a), S->r1), &e );
    1941      500616 :     if (e > -5) pari_err_PREC( "get_norm");
    1942      500616 :     return N;
    1943             :   }
    1944        1406 :   if (S->w) a = RgV_RgC_mul(S->w, a);
    1945        1406 :   return ZX_resultant_all(S->T, a, S->D, 0);
    1946             : }
    1947             : static void
    1948      214409 : init_norm(norm_S *S, GEN nf, GEN p)
    1949             : {
    1950      214409 :   GEN T = nf_get_pol(nf), M = nf_get_M(nf);
    1951      214411 :   long N = degpol(T), ex = gexpo(M) + gexpo(mului(8 * N, p));
    1952             : 
    1953      214416 :   S->r1 = nf_get_r1(nf);
    1954      214416 :   if (N * ex <= gprecision(M) - 20)
    1955             :   { /* enough prec to use embed_norm */
    1956      214240 :     S->M = M;
    1957      214240 :     S->D = NULL;
    1958      214240 :     S->w = NULL;
    1959      214240 :     S->T = NULL;
    1960             :   }
    1961             :   else
    1962             :   {
    1963         191 :     GEN w = leafcopy(nf_get_zkprimpart(nf)), D = nf_get_zkden(nf), Dp = sqri(p);
    1964             :     long i;
    1965         191 :     if (!equali1(D))
    1966             :     {
    1967         191 :       GEN w1 = D;
    1968         191 :       long v = Z_pval(D, p);
    1969         191 :       D = powiu(p, v);
    1970         191 :       Dp = mulii(D, Dp);
    1971         191 :       gel(w, 1) = remii(w1, Dp);
    1972             :     }
    1973        3969 :     for (i=2; i<=N; i++) gel(w,i) = FpX_red(gel(w,i), Dp);
    1974         191 :     S->M = NULL;
    1975         191 :     S->D = D;
    1976         191 :     S->w = w;
    1977         191 :     S->T = T;
    1978             :   }
    1979      214431 : }
    1980             : /* f = f(pr/p), q = p^(f+1), a in pr.
    1981             :  * Return 1 if v_pr(a) = 1, and 0 otherwise */
    1982             : static int
    1983      501970 : is_uniformizer(GEN a, GEN q, norm_S *S) { return !dvdii(get_norm(S,a), q); }
    1984             : 
    1985             : /* Return x * y, x, y are t_MAT (Fp-basis of in O_K/p), assume (x,y)=1.
    1986             :  * Either x or y may be NULL (= O_K), not both */
    1987             : static GEN
    1988      701098 : mul_intersect(GEN x, GEN y, GEN p)
    1989             : {
    1990      701098 :   if (!x) return y;
    1991      372466 :   if (!y) return x;
    1992      262922 :   return FpM_intersect_i(x, y, p);
    1993             : }
    1994             : /* Fp-basis of (ZK/pr): applied to the primes found in primedec_aux()
    1995             :  * true nf */
    1996             : static GEN
    1997      306729 : Fp_basis(GEN nf, GEN pr)
    1998             : {
    1999             :   long i, j, l;
    2000             :   GEN x, y;
    2001             :   /* already in basis form (from Buchman-Lenstra) ? */
    2002      306729 :   if (typ(pr) == t_MAT) return pr;
    2003             :   /* ordinary prid (from Kummer) */
    2004       72854 :   x = pr_hnf(nf, pr);
    2005       72854 :   l = lg(x);
    2006       72854 :   y = cgetg(l, t_MAT);
    2007      613643 :   for (i=j=1; i<l; i++)
    2008      540789 :     if (gequal1(gcoeff(x,i,i))) gel(y,j++) = gel(x,i);
    2009       72854 :   setlg(y, j); return y;
    2010             : }
    2011             : /* Let Ip = prod_{ P | p } P be the p-radical. The list L contains the
    2012             :  * P (mod Ip) seen as sub-Fp-vector spaces of ZK/Ip.
    2013             :  * Return the list of (Ip / P) (mod Ip).
    2014             :  * N.B: All ideal multiplications are computed as intersections of Fp-vector
    2015             :  * spaces. true nf */
    2016             : static GEN
    2017      214438 : get_LV(GEN nf, GEN L, GEN p, long N)
    2018             : {
    2019      214438 :   long i, l = lg(L)-1;
    2020             :   GEN LV, LW, A, B;
    2021             : 
    2022      214438 :   LV = cgetg(l+1, t_VEC);
    2023      214435 :   if (l == 1) { gel(LV,1) = matid(N); return LV; }
    2024      109544 :   LW = cgetg(l+1, t_VEC);
    2025      416273 :   for (i=1; i<=l; i++) gel(LW,i) = Fp_basis(nf, gel(L,i));
    2026             : 
    2027             :   /* A[i] = L[1]...L[i-1], i = 2..l */
    2028      109544 :   A = cgetg(l+1, t_VEC); gel(A,1) = NULL;
    2029      306729 :   for (i=1; i < l; i++) gel(A,i+1) = mul_intersect(gel(A,i), gel(LW,i), p);
    2030             :   /* B[i] = L[i+1]...L[l], i = 1..(l-1) */
    2031      109544 :   B = cgetg(l+1, t_VEC); gel(B,l) = NULL;
    2032      306729 :   for (i=l; i>=2; i--) gel(B,i-1) = mul_intersect(gel(B,i), gel(LW,i), p);
    2033      416272 :   for (i=1; i<=l; i++) gel(LV,i) = mul_intersect(gel(A,i), gel(B,i), p);
    2034      109543 :   return LV;
    2035             : }
    2036             : 
    2037             : static void
    2038           0 : errprime(GEN p) { pari_err_PRIME("idealprimedec",p); }
    2039             : 
    2040             : /* P = Fp-basis (over O_K/p) for pr.
    2041             :  * V = Z-basis for I_p/pr. ramif != 0 iff some pr|p is ramified.
    2042             :  * Return a p-uniformizer for pr. Assume pr not inert, i.e. m > 0 */
    2043             : static GEN
    2044      296329 : uniformizer(GEN nf, norm_S *S, GEN P, GEN V, GEN p, int ramif)
    2045             : {
    2046      296329 :   long i, l, f, m = lg(P)-1, N = nf_get_degree(nf);
    2047             :   GEN u, Mv, x, q;
    2048             : 
    2049      296329 :   f = N - m; /* we want v_p(Norm(x)) = p^f */
    2050      296329 :   q = powiu(p,f+1);
    2051             : 
    2052      296298 :   u = FpM_FpC_invimage(shallowconcat(P, V), col_ei(N,1), p);
    2053      296333 :   setlg(u, lg(P));
    2054      296333 :   u = centermod(ZM_ZC_mul(P, u), p);
    2055      296305 :   if (is_uniformizer(u, q, S)) return u;
    2056      157895 :   if (signe(gel(u,1)) <= 0) /* make sure u[1] in ]-p,p] */
    2057      133897 :     gel(u,1) = addii(gel(u,1), p); /* try u + p */
    2058             :   else
    2059       23998 :     gel(u,1) = subii(gel(u,1), p); /* try u - p */
    2060      157887 :   if (!ramif || is_uniformizer(u, q, S)) return u;
    2061             : 
    2062             :   /* P/p ramified, u in P^2, not in Q for all other Q|p */
    2063       85794 :   Mv = zk_multable(nf, Z_ZC_sub(gen_1,u));
    2064       85802 :   l = lg(P);
    2065      115184 :   for (i=1; i<l; i++)
    2066             :   {
    2067      115184 :     x = centermod(ZC_add(u, ZM_ZC_mul(Mv, gel(P,i))), p);
    2068      115179 :     if (is_uniformizer(x, q, S)) return x;
    2069             :   }
    2070           0 :   errprime(p);
    2071             :   return NULL; /* LCOV_EXCL_LINE */
    2072             : }
    2073             : 
    2074             : /*******************************************************************/
    2075             : /*                                                                 */
    2076             : /*                   BUCHMANN-LENSTRA ALGORITHM                    */
    2077             : /*                                                                 */
    2078             : /*******************************************************************/
    2079             : static GEN
    2080     4256664 : mk_pr(GEN p, GEN u, long e, long f, GEN t)
    2081     4256664 : { return mkvec5(p, u, utoipos(e), utoipos(f), t); }
    2082             : 
    2083             : /* nf a true nf, u in Z[X]/(T); pr = p Z_K + u Z_K of ramification index e */
    2084             : GEN
    2085     3800297 : idealprimedec_kummer(GEN nf,GEN u,long e,GEN p)
    2086             : {
    2087     3800297 :   GEN t, T = nf_get_pol(nf);
    2088     3800289 :   long f = degpol(u), N = degpol(T);
    2089             : 
    2090     3800266 :   if (f == N)
    2091             :   { /* inert */
    2092      624852 :     u = scalarcol_shallow(p,N);
    2093      624868 :     t = gen_1;
    2094             :   }
    2095             :   else
    2096             :   {
    2097     3175414 :     t = centermod(poltobasis(nf, FpX_div(T, u, p)), p);
    2098     3175099 :     u = centermod(poltobasis(nf, u), p);
    2099     3175161 :     if (e == 1)
    2100             :     { /* make sure v_pr(u) = 1 (automatic if e>1) */
    2101     2897711 :       GEN cw, w = Q_primitive_part(nf_to_scalar_or_alg(nf, u), &cw);
    2102     2897928 :       long v = cw? f - Q_pval(cw, p) * N: f;
    2103     2897928 :       if (ZpX_resultant_val(T, w, p, v + 1) > v)
    2104             :       {
    2105      107797 :         GEN c = gel(u,1);
    2106      107797 :         gel(u,1) = signe(c) > 0? subii(c, p): addii(c, p);
    2107             :       }
    2108             :     }
    2109     3175452 :     t = zk_multable(nf, t);
    2110             :   }
    2111     3800244 :   return mk_pr(p,u,e,f,t);
    2112             : }
    2113             : 
    2114             : typedef struct {
    2115             :   GEN nf, p;
    2116             :   long I;
    2117             : } eltmod_muldata;
    2118             : 
    2119             : static GEN
    2120      821209 : sqr_mod(void *data, GEN x)
    2121             : {
    2122      821209 :   eltmod_muldata *D = (eltmod_muldata*)data;
    2123      821209 :   return FpC_red(nfsqri(D->nf, x), D->p);
    2124             : }
    2125             : static GEN
    2126      347359 : ei_msqr_mod(void *data, GEN x)
    2127             : {
    2128      347359 :   GEN x2 = sqr_mod(data, x);
    2129      347353 :   eltmod_muldata *D = (eltmod_muldata*)data;
    2130      347353 :   return FpC_red(zk_ei_mul(D->nf, x2, D->I), D->p);
    2131             : }
    2132             : /* nf a true nf; compute lift(nf.zk[I]^p mod p) */
    2133             : static GEN
    2134      737441 : pow_ei_mod_p(GEN nf, long I, GEN p)
    2135             : {
    2136      737441 :   pari_sp av = avma;
    2137             :   eltmod_muldata D;
    2138      737441 :   long N = nf_get_degree(nf);
    2139      737441 :   GEN y = col_ei(N,I);
    2140      737442 :   if (I == 1) return y;
    2141      520676 :   D.nf = nf;
    2142      520676 :   D.p = p;
    2143      520676 :   D.I = I;
    2144      520676 :   y = gen_pow_fold(y, p, (void*)&D, &sqr_mod, &ei_msqr_mod);
    2145      520684 :   return gerepileupto(av,y);
    2146             : }
    2147             : 
    2148             : /* nf a true nf; return a Z basis of Z_K's p-radical, phi = x--> x^p-x */
    2149             : static GEN
    2150      214438 : pradical(GEN nf, GEN p, GEN *phi)
    2151             : {
    2152      214438 :   long i, N = nf_get_degree(nf);
    2153             :   GEN q,m,frob,rad;
    2154             : 
    2155             :   /* matrix of Frob: x->x^p over Z_K/p */
    2156      214438 :   frob = cgetg(N+1,t_MAT);
    2157      942247 :   for (i=1; i<=N; i++) gel(frob,i) = pow_ei_mod_p(nf,i,p);
    2158             : 
    2159      214437 :   m = frob; q = p;
    2160      303929 :   while (abscmpiu(q,N) < 0) { q = mulii(q,p); m = FpM_mul(m, frob, p); }
    2161      214437 :   rad = FpM_ker(m, p); /* m = Frob^k, s.t p^k >= N */
    2162      942213 :   for (i=1; i<=N; i++) gcoeff(frob,i,i) = subiu(gcoeff(frob,i,i), 1);
    2163      214412 :   *phi = frob; return rad;
    2164             : }
    2165             : 
    2166             : /* return powers of a: a^0, ... , a^d,  d = dim A */
    2167             : static GEN
    2168      158932 : get_powers(GEN mul, GEN p)
    2169             : {
    2170      158932 :   long i, d = lgcols(mul);
    2171      158933 :   GEN z, pow = cgetg(d+2,t_MAT), P = pow+1;
    2172             : 
    2173      158933 :   gel(P,0) = scalarcol_shallow(gen_1, d-1);
    2174      158933 :   z = gel(mul,1);
    2175      753469 :   for (i=1; i<=d; i++)
    2176             :   {
    2177      594540 :     gel(P,i) = z; /* a^i */
    2178      594540 :     if (i!=d) z = FpM_FpC_mul(mul, z, p);
    2179             :   }
    2180      158929 :   return pow;
    2181             : }
    2182             : 
    2183             : /* minimal polynomial of a in A (dim A = d).
    2184             :  * mul = multiplication table by a in A */
    2185             : static GEN
    2186      117231 : pol_min(GEN mul, GEN p)
    2187             : {
    2188      117231 :   pari_sp av = avma;
    2189      117231 :   GEN z = FpM_deplin(get_powers(mul, p), p);
    2190      117229 :   return gerepilecopy(av, RgV_to_RgX(z,0));
    2191             : }
    2192             : 
    2193             : static GEN
    2194      411294 : get_pr(GEN nf, norm_S *S, GEN p, GEN P, GEN V, int ramif, long N, long flim)
    2195             : {
    2196             :   GEN u, t;
    2197             :   long e, f;
    2198             : 
    2199      411294 :   if (typ(P) == t_VEC)
    2200             :   { /* already done (Kummer) */
    2201       72853 :     f = pr_get_f(P);
    2202       72853 :     if (flim > 0 && f > flim) return NULL;
    2203       71961 :     if (flim == -2) return (GEN)f;
    2204       71954 :     return P;
    2205             :   }
    2206      338441 :   f = N - (lg(P)-1);
    2207      338441 :   if (flim > 0 && f > flim) return NULL;
    2208      336842 :   if (flim == -2) return (GEN)f;
    2209             :   /* P = (p,u) prime. t is an anti-uniformizer: Z_K + t/p Z_K = P^(-1),
    2210             :    * so that v_P(t) = e(P/p)-1 */
    2211      336464 :   if (f == N) {
    2212       40136 :     u = scalarcol_shallow(p,N);
    2213       40136 :     t = gen_1;
    2214       40136 :     e = 1;
    2215             :   } else {
    2216             :     GEN mt;
    2217      296328 :     u = uniformizer(nf, S, P, V, p, ramif);
    2218      296295 :     t = FpM_deplin(zk_multable(nf,u), p);
    2219      296330 :     mt = zk_multable(nf, t);
    2220      296326 :     e = ramif? 1 + ZC_nfval(t,mk_pr(p,u,0,0,mt)): 1;
    2221      296308 :     t = mt;
    2222             :   }
    2223      336444 :   return mk_pr(p,u,e,f,t);
    2224             : }
    2225             : 
    2226             : /* true nf */
    2227             : static GEN
    2228      214438 : primedec_end(GEN nf, GEN L, GEN p, long flim)
    2229             : {
    2230      214438 :   long i, j, l = lg(L), N = nf_get_degree(nf);
    2231      214438 :   GEN LV = get_LV(nf, L,p,N);
    2232      214437 :   int ramif = dvdii(nf_get_disc(nf), p);
    2233      214406 :   norm_S S; init_norm(&S, nf, p);
    2234      625326 :   for (i = j = 1; i < l; i++)
    2235             :   {
    2236      411292 :     GEN P = get_pr(nf, &S, p, gel(L,i), gel(LV,i), ramif, N, flim);
    2237      411288 :     if (!P) continue;
    2238      408797 :     gel(L,j++) = P;
    2239      408797 :     if (flim == -1) return P;
    2240             :   }
    2241      214034 :   setlg(L, j); return L;
    2242             : }
    2243             : 
    2244             : /* prime ideal decomposition of p; if flim>0, restrict to f(P,p) <= flim
    2245             :  * if flim = -1 return only the first P
    2246             :  * if flim = -2 return only the f(P/p) in a t_VECSMALL; true nf */
    2247             : static GEN
    2248     2707892 : primedec_aux(GEN nf, GEN p, long flim)
    2249             : {
    2250     2707892 :   const long TYP = (flim == -2)? t_VECSMALL: t_VEC;
    2251     2707892 :   GEN E, F, L, Ip, phi, f, g, h, UN, T = nf_get_pol(nf);
    2252             :   long i, k, c, iL, N;
    2253             :   int kummer;
    2254             : 
    2255     2707886 :   F = FpX_factor(T, p);
    2256     2707967 :   E = gel(F,2);
    2257     2707967 :   F = gel(F,1);
    2258             : 
    2259     2707967 :   k = lg(F); if (k == 1) errprime(p);
    2260     2707967 :   if ( !dvdii(nf_get_index(nf),p) ) /* p doesn't divide index */
    2261             :   {
    2262     2491929 :     L = cgetg(k, TYP);
    2263     6075851 :     for (i=1; i<k; i++)
    2264             :     {
    2265     4139878 :       GEN t = gel(F,i);
    2266     4139878 :       long f = degpol(t);
    2267     4139883 :       if (flim > 0 && f > flim) { setlg(L, i); break; }
    2268     3588613 :       if (flim == -2)
    2269           0 :         L[i] = f;
    2270             :       else
    2271     3588613 :         gel(L,i) = idealprimedec_kummer(nf, t, E[i],p);
    2272     3588722 :       if (flim == -1) return gel(L,1);
    2273             :     }
    2274     2487240 :     return L;
    2275             :   }
    2276             : 
    2277      215827 :   kummer = 0;
    2278      215827 :   g = FpXV_prod(F, p);
    2279      215827 :   h = FpX_div(T,g,p);
    2280      215830 :   f = FpX_red(ZX_Z_divexact(ZX_sub(ZX_mul(g,h), T), p), p);
    2281             : 
    2282      215812 :   N = degpol(T);
    2283      215817 :   L = cgetg(N+1,TYP);
    2284      215823 :   iL = 1;
    2285      524994 :   for (i=1; i<k; i++)
    2286      310556 :     if (E[i] == 1 || signe(FpX_rem(f,gel(F,i),p)))
    2287       72853 :     {
    2288       74247 :       GEN t = gel(F,i);
    2289       74247 :       kummer = 1;
    2290       74247 :       gel(L,iL++) = idealprimedec_kummer(nf, t, E[i],p);
    2291       74246 :       if (flim == -1) return gel(L,1);
    2292             :     }
    2293             :     else /* F[i] | (f,g,h), happens at least once by Dedekind criterion */
    2294      236318 :       E[i] = 0;
    2295             : 
    2296             :   /* phi matrix of x -> x^p - x in algebra Z_K/p */
    2297      214438 :   Ip = pradical(nf,p,&phi);
    2298             : 
    2299             :   /* split etale algebra Z_K / (p,Ip) */
    2300      214427 :   h = cgetg(N+1,t_VEC);
    2301      214426 :   if (kummer)
    2302             :   { /* split off Kummer factors */
    2303       46218 :     GEN mb, b = NULL;
    2304      172793 :     for (i=1; i<k; i++)
    2305      126575 :       if (!E[i]) b = b? FpX_mul(b, gel(F,i), p): gel(F,i);
    2306       46218 :     if (!b) errprime(p);
    2307       46218 :     b = FpC_red(poltobasis(nf,b), p);
    2308       46219 :     mb = FpM_red(zk_multable(nf,b), p);
    2309             :     /* Fp-base of ideal (Ip, b) in ZK/p */
    2310       46219 :     gel(h,1) = FpM_image(shallowconcat(mb,Ip), p);
    2311             :   }
    2312             :   else
    2313      168208 :     gel(h,1) = Ip;
    2314             : 
    2315      214427 :   UN = col_ei(N, 1);
    2316      467763 :   for (c=1; c; c--)
    2317             :   { /* Let A:= (Z_K/p) / Ip etale; split A2 := A / Im H ~ Im M2
    2318             :        H * ? + M2 * Mi2 = Id_N ==> M2 * Mi2 projector A --> A2 */
    2319      253325 :     GEN M, Mi, M2, Mi2, phi2, mat1, H = gel(h,c); /* maximal rank */
    2320      253325 :     long dim, r = lg(H)-1;
    2321             : 
    2322      253325 :     M   = FpM_suppl(shallowconcat(H,UN), p);
    2323      253331 :     Mi  = FpM_inv(M, p);
    2324      253326 :     M2  = vecslice(M, r+1,N); /* M = (H|M2) invertible */
    2325      253326 :     Mi2 = rowslice(Mi,r+1,N);
    2326             :     /* FIXME: FpM_mul(,M2) could be done with vecpermute */
    2327      253327 :     phi2 = FpM_mul(Mi2, FpM_mul(phi,M2, p), p);
    2328      253331 :     mat1 = FpM_ker(phi2, p);
    2329      253330 :     dim = lg(mat1)-1; /* A2 product of 'dim' fields */
    2330      253330 :     if (dim > 1)
    2331             :     { /* phi2 v = 0 => a = M2 v in Ker phi, a not in Fp.1 + H */
    2332      117229 :       GEN R, a, mula, mul2, v = gel(mat1,2);
    2333             :       long n;
    2334             : 
    2335      117229 :       a = FpM_FpC_mul(M2,v, p); /* not a scalar */
    2336      117227 :       mula = FpM_red(zk_multable(nf,a), p);
    2337      117222 :       mul2 = FpM_mul(Mi2, FpM_mul(mula,M2, p), p);
    2338      117231 :       R = FpX_roots(pol_min(mul2,p), p); /* totally split mod p */
    2339      117230 :       n = lg(R)-1;
    2340      358792 :       for (i=1; i<=n; i++)
    2341             :       {
    2342      241562 :         GEN I = RgM_Rg_sub_shallow(mula, gel(R,i));
    2343      241559 :         gel(h,c++) = FpM_image(shallowconcat(H, I), p);
    2344             :       }
    2345      117230 :       if (n == dim)
    2346      302495 :         for (i=1; i<=n; i++) gel(L,iL++) = gel(h,--c);
    2347             :     }
    2348             :     else /* A2 field ==> H maximal, f = N-r = dim(A2) */
    2349      136101 :       gel(L,iL++) = H;
    2350             :   }
    2351      214438 :   setlg(L, iL);
    2352      214438 :   return primedec_end(nf, L, p, flim);
    2353             : }
    2354             : 
    2355             : GEN
    2356     2700979 : idealprimedec_limit_f(GEN nf, GEN p, long f)
    2357             : {
    2358     2700979 :   pari_sp av = avma;
    2359             :   GEN v;
    2360     2700979 :   if (typ(p) != t_INT) pari_err_TYPE("idealprimedec",p);
    2361     2700979 :   if (f < 0) pari_err_DOMAIN("idealprimedec", "f", "<", gen_0, stoi(f));
    2362     2700979 :   v = primedec_aux(checknf(nf), p, f);
    2363     2700789 :   v = gen_sort(v, (void*)&cmp_prime_over_p, &cmp_nodata);
    2364     2700869 :   return gerepileupto(av,v);
    2365             : }
    2366             : /* true nf */
    2367             : GEN
    2368        6552 : idealprimedec_galois(GEN nf, GEN p)
    2369             : {
    2370        6552 :   pari_sp av = avma;
    2371        6552 :   GEN v = primedec_aux(nf, p, -1);
    2372        6552 :   return gerepilecopy(av,v);
    2373             : }
    2374             : /* true nf */
    2375             : GEN
    2376         371 : idealprimedec_degrees(GEN nf, GEN p)
    2377             : {
    2378         371 :   pari_sp av = avma;
    2379         371 :   GEN v = primedec_aux(nf, p, -2);
    2380         371 :   vecsmall_sort(v); return gerepileuptoleaf(av, v);
    2381             : }
    2382             : GEN
    2383      505227 : idealprimedec_limit_norm(GEN nf, GEN p, GEN B)
    2384      505227 : { return idealprimedec_limit_f(nf, p, logint(B,p)); }
    2385             : GEN
    2386     1273082 : idealprimedec(GEN nf, GEN p)
    2387     1273082 : { return idealprimedec_limit_f(nf, p, 0); }
    2388             : static GEN
    2389       26572 : nf_pV_to_prVV(GEN nf, GEN x)
    2390       89523 : { pari_APPLY_same(idealprimedec(nf, gel(x,i))); }
    2391             : GEN
    2392       38563 : nf_pV_to_prV(GEN nf, GEN x)
    2393             : {
    2394       38563 :   if (lg(x) == 1) return leafcopy(x);
    2395       26572 :   return shallowconcat1(nf_pV_to_prVV(nf, x));
    2396             : }
    2397             : 
    2398             : /* return [Fp[x]: Fp] */
    2399             : static long
    2400        4109 : ffdegree(GEN x, GEN frob, GEN p)
    2401             : {
    2402        4109 :   pari_sp av = avma;
    2403        4109 :   long d, f = lg(frob)-1;
    2404        4109 :   GEN y = x;
    2405             : 
    2406       13209 :   for (d=1; d < f; d++)
    2407             :   {
    2408       10878 :     y = FpM_FpC_mul(frob, y, p);
    2409       10878 :     if (ZV_equal(y, x)) break;
    2410             :   }
    2411        4109 :   return gc_long(av,d);
    2412             : }
    2413             : 
    2414             : static GEN
    2415       91827 : lift_to_zk(GEN v, GEN c, long N)
    2416             : {
    2417       91827 :   GEN w = zerocol(N);
    2418       91827 :   long i, l = lg(c);
    2419      306449 :   for (i=1; i<l; i++) gel(w,c[i]) = gel(v,i);
    2420       91827 :   return w;
    2421             : }
    2422             : 
    2423             : /* return t = 1 mod pr, t = 0 mod p / pr^e(pr/p) */
    2424             : GEN
    2425      967484 : pr_anti_uniformizer(GEN nf, GEN pr)
    2426             : {
    2427      967484 :   long N = nf_get_degree(nf), e = pr_get_e(pr);
    2428             :   GEN p, b, z;
    2429             : 
    2430      967467 :   if (e * pr_get_f(pr) == N) return gen_1;
    2431      460002 :   p = pr_get_p(pr);
    2432      459999 :   b = pr_get_tau(pr); /* ZM */
    2433      459999 :   if (e != 1)
    2434             :   {
    2435       22652 :     GEN q = powiu(pr_get_p(pr), e-1);
    2436       22652 :     b = ZM_Z_divexact(ZM_powu(b,e), q);
    2437             :   }
    2438             :   /* b = tau^e / p^(e-1), v_pr(b) = 0, v_Q(b) >= e(Q/p) for other Q | p */
    2439      459999 :   z = ZM_hnfmodid(FpM_red(b,p), p); /* ideal (p) / pr^e, coprime to pr */
    2440      460015 :   z = idealaddtoone_raw(nf, pr, z);
    2441      460004 :   return Z_ZC_sub(gen_1, FpC_center(FpC_red(z,p), p, shifti(p,-1)));
    2442             : }
    2443             : 
    2444             : #define mpr_TAU 1
    2445             : #define mpr_FFP 2
    2446             : #define mpr_NFP 5
    2447             : #define SMALLMODPR 4
    2448             : #define LARGEMODPR 6
    2449             : static GEN
    2450     3526338 : modpr_TAU(GEN modpr)
    2451             : {
    2452     3526338 :   GEN tau = gel(modpr,mpr_TAU);
    2453     3526338 :   return isintzero(tau)? NULL: tau;
    2454             : }
    2455             : 
    2456             : /* prh = HNF matrix, which is identity but for the first line. Return a
    2457             :  * projector to ZK / prh ~ Z/prh[1,1] */
    2458             : GEN
    2459     1030742 : dim1proj(GEN prh)
    2460             : {
    2461     1030742 :   long i, N = lg(prh)-1;
    2462     1030742 :   GEN ffproj = cgetg(N+1, t_VEC);
    2463     1030733 :   GEN x, q = gcoeff(prh,1,1);
    2464     1030733 :   gel(ffproj,1) = gen_1;
    2465     2376135 :   for (i=2; i<=N; i++)
    2466             :   {
    2467     1345485 :     x = gcoeff(prh,1,i);
    2468     1345485 :     if (signe(x)) x = subii(q,x);
    2469     1345402 :     gel(ffproj,i) = x;
    2470             :   }
    2471     1030650 :   return ffproj;
    2472             : }
    2473             : 
    2474             : /* p not necessarily prime, but coprime to denom(basis) */
    2475             : GEN
    2476         203 : QXQV_to_FpM(GEN basis, GEN T, GEN p)
    2477             : {
    2478         203 :   long i, l = lg(basis), f = degpol(T);
    2479         203 :   GEN z = cgetg(l, t_MAT);
    2480        4515 :   for (i = 1; i < l; i++)
    2481             :   {
    2482        4312 :     GEN w = gel(basis,i);
    2483        4312 :     if (typ(w) == t_INT)
    2484           0 :       w = scalarcol_shallow(w, f);
    2485             :     else
    2486             :     {
    2487             :       GEN dx;
    2488        4312 :       w = Q_remove_denom(w, &dx);
    2489        4312 :       w = FpXQ_red(w, T, p);
    2490        4312 :       if (dx)
    2491             :       {
    2492           0 :         dx = Fp_inv(dx, p);
    2493           0 :         if (!equali1(dx)) w = FpX_Fp_mul(w, dx, p);
    2494             :       }
    2495        4312 :       w = RgX_to_RgC(w, f);
    2496             :     }
    2497        4312 :     gel(z,i) = w; /* w_i mod (T,p) */
    2498             :   }
    2499         203 :   return z;
    2500             : }
    2501             : 
    2502             : /* initialize reduction mod pr; if zk = 1, will only init data required to
    2503             :  * reduce *integral* element.  Realize (O_K/pr) as Fp[X] / (T), for a
    2504             :  * *monic* T; use variable vT for varn(T) */
    2505             : static GEN
    2506     1158897 : modprinit(GEN nf, GEN pr, int zk, long vT)
    2507             : {
    2508     1158897 :   pari_sp av = avma;
    2509             :   GEN res, tau, mul, x, p, T, pow, ffproj, nfproj, prh, c;
    2510             :   long N, i, k, f;
    2511             : 
    2512     1158897 :   nf = checknf(nf); checkprid(pr);
    2513     1158870 :   if (vT < 0) vT = nf_get_varn(nf);
    2514     1158864 :   f = pr_get_f(pr);
    2515     1158856 :   N = nf_get_degree(nf);
    2516     1158855 :   prh = pr_hnf(nf, pr);
    2517     1158891 :   tau = zk? gen_0: pr_anti_uniformizer(nf, pr);
    2518     1158860 :   p = pr_get_p(pr);
    2519             : 
    2520     1158862 :   if (f == 1)
    2521             :   {
    2522     1012499 :     res = cgetg(SMALLMODPR, t_COL);
    2523     1012504 :     gel(res,mpr_TAU) = tau;
    2524     1012504 :     gel(res,mpr_FFP) = dim1proj(prh);
    2525     1012420 :     gel(res,3) = pr; return gerepilecopy(av, res);
    2526             :   }
    2527             : 
    2528      146363 :   c = cgetg(f+1, t_VECSMALL);
    2529      146370 :   ffproj = cgetg(N+1, t_MAT);
    2530      601201 :   for (k=i=1; i<=N; i++)
    2531             :   {
    2532      454831 :     x = gcoeff(prh, i,i);
    2533      454831 :     if (!is_pm1(x)) { c[k] = i; gel(ffproj,i) = col_ei(N, i); k++; }
    2534             :     else
    2535      128044 :       gel(ffproj,i) = ZC_neg(gel(prh,i));
    2536             :   }
    2537      146370 :   ffproj = rowpermute(ffproj, c);
    2538      146369 :   if (! dvdii(nf_get_index(nf), p))
    2539             :   {
    2540      104667 :     GEN basis = nf_get_zkprimpart(nf), D = nf_get_zkden(nf);
    2541      104667 :     if (N == f)
    2542             :     { /* pr inert */
    2543       45647 :       T = nf_get_pol(nf);
    2544       45647 :       T = FpX_red(T,p);
    2545       45647 :       ffproj = RgV_to_RgM(basis, lg(basis)-1);
    2546             :     }
    2547             :     else
    2548             :     {
    2549       59020 :       T = RgV_RgC_mul(basis, pr_get_gen(pr));
    2550       59020 :       T = FpX_normalize(FpX_red(T,p),p);
    2551       59020 :       basis = FqV_red(vecpermute(basis,c), T, p);
    2552       59020 :       basis = RgV_to_RgM(basis, lg(basis)-1);
    2553       59020 :       ffproj = ZM_mul(basis, ffproj);
    2554             :     }
    2555      104667 :     setvarn(T, vT);
    2556      104667 :     ffproj = FpM_red(ffproj, p);
    2557      104667 :     if (!equali1(D))
    2558             :     {
    2559       33035 :       D = modii(D,p);
    2560       33035 :       if (!equali1(D)) ffproj = FpM_Fp_mul(ffproj, Fp_inv(D,p), p);
    2561             :     }
    2562             : 
    2563      104667 :     res = cgetg(SMALLMODPR+1, t_COL);
    2564      104667 :     gel(res,mpr_TAU) = tau;
    2565      104667 :     gel(res,mpr_FFP) = ffproj;
    2566      104667 :     gel(res,3) = pr;
    2567      104667 :     gel(res,4) = T; return gerepilecopy(av, res);
    2568             :   }
    2569             : 
    2570       41702 :   if (uisprime(f))
    2571             :   {
    2572       39371 :     mul = ei_multable(nf, c[2]);
    2573       39371 :     mul = vecpermute(mul, c);
    2574             :   }
    2575             :   else
    2576             :   {
    2577             :     GEN v, u, u2, frob;
    2578             :     long deg,deg1,deg2;
    2579             : 
    2580             :     /* matrix of Frob: x->x^p over Z_K/pr = < w[c1], ..., w[cf] > over Fp */
    2581        2331 :     frob = cgetg(f+1, t_MAT);
    2582       11963 :     for (i=1; i<=f; i++)
    2583             :     {
    2584        9632 :       x = pow_ei_mod_p(nf,c[i],p);
    2585        9632 :       gel(frob,i) = FpM_FpC_mul(ffproj, x, p);
    2586             :     }
    2587        2331 :     u = col_ei(f,2); k = 2;
    2588        2331 :     deg1 = ffdegree(u, frob, p);
    2589        4102 :     while (deg1 < f)
    2590             :     {
    2591        1771 :       k++; u2 = col_ei(f, k);
    2592        1771 :       deg2 = ffdegree(u2, frob, p);
    2593        1771 :       deg = ulcm(deg1,deg2);
    2594        1771 :       if (deg == deg1) continue;
    2595        1764 :       if (deg == deg2) { deg1 = deg2; u = u2; continue; }
    2596           7 :       u = ZC_add(u, u2);
    2597           7 :       while (ffdegree(u, frob, p) < deg) u = ZC_add(u, u2);
    2598           7 :       deg1 = deg;
    2599             :     }
    2600        2331 :     v = lift_to_zk(u,c,N);
    2601             : 
    2602        2331 :     mul = cgetg(f+1,t_MAT);
    2603        2331 :     gel(mul,1) = v; /* assume w_1 = 1 */
    2604        9632 :     for (i=2; i<=f; i++) gel(mul,i) = zk_ei_mul(nf,v,c[i]);
    2605             :   }
    2606             : 
    2607             :   /* Z_K/pr = Fp(v), mul = mul by v */
    2608       41702 :   mul = FpM_red(mul, p);
    2609       41703 :   mul = FpM_mul(ffproj, mul, p);
    2610             : 
    2611       41703 :   pow = get_powers(mul, p);
    2612       41703 :   T = RgV_to_RgX(FpM_deplin(pow, p), vT);
    2613       41703 :   nfproj = cgetg(f+1, t_MAT);
    2614      131199 :   for (i=1; i<=f; i++) gel(nfproj,i) = lift_to_zk(gel(pow,i), c, N);
    2615             : 
    2616       41703 :   setlg(pow, f+1);
    2617       41703 :   ffproj = FpM_mul(FpM_inv(pow, p), ffproj, p);
    2618             : 
    2619       41703 :   res = cgetg(LARGEMODPR, t_COL);
    2620       41703 :   gel(res,mpr_TAU) = tau;
    2621       41703 :   gel(res,mpr_FFP) = ffproj;
    2622       41703 :   gel(res,3) = pr;
    2623       41703 :   gel(res,4) = T;
    2624       41703 :   gel(res,mpr_NFP) = nfproj; return gerepilecopy(av, res);
    2625             : }
    2626             : 
    2627             : GEN
    2628           7 : nfmodprinit(GEN nf, GEN pr) { return modprinit(nf, pr, 0, -1); }
    2629             : GEN
    2630      175425 : zkmodprinit(GEN nf, GEN pr) { return modprinit(nf, pr, 1, -1); }
    2631             : GEN
    2632          77 : nfmodprinit0(GEN nf, GEN pr, long v) { return modprinit(nf, pr, 0, v); }
    2633             : 
    2634             : /* x may be a modpr */
    2635             : static int
    2636     4364593 : ok_modpr(GEN x)
    2637     4364593 : { return typ(x) == t_COL && lg(x) >= SMALLMODPR && lg(x) <= LARGEMODPR; }
    2638             : void
    2639         210 : checkmodpr(GEN x)
    2640             : {
    2641         210 :   if (!ok_modpr(x)) pari_err_TYPE("checkmodpr [use nfmodprinit]", x);
    2642         210 :   checkprid(modpr_get_pr(x));
    2643         210 : }
    2644             : GEN
    2645      137746 : get_modpr(GEN x)
    2646      137746 : { return ok_modpr(x)? x: NULL; }
    2647             : 
    2648             : int
    2649    22903407 : checkprid_i(GEN x)
    2650             : {
    2651    22084788 :   return (typ(x) == t_VEC && lg(x) == 6
    2652    22011770 :           && typ(gel(x,2)) == t_COL && typ(gel(x,3)) == t_INT
    2653    44988195 :           && typ(gel(x,5)) != t_COL); /* tau changed to t_MAT/t_INT in 2.6 */
    2654             : }
    2655             : void
    2656    17934619 : checkprid(GEN x)
    2657    17934619 : { if (!checkprid_i(x)) pari_err_TYPE("checkprid",x); }
    2658             : GEN
    2659      939099 : get_prid(GEN x)
    2660             : {
    2661      939099 :   long lx = lg(x);
    2662      939099 :   if (lx == 3 && typ(x) == t_VEC) x = gel(x,1);
    2663      939099 :   if (checkprid_i(x)) return x;
    2664      694477 :   if (ok_modpr(x)) {
    2665      108465 :     x = modpr_get_pr(x);
    2666      108465 :     if (checkprid_i(x)) return x;
    2667             :   }
    2668      586012 :   return NULL;
    2669             : }
    2670             : 
    2671             : static GEN
    2672     3532163 : to_ff_init(GEN nf, GEN *pr, GEN *T, GEN *p, int zk)
    2673             : {
    2674     3532163 :   GEN modpr = ok_modpr(*pr)? *pr: modprinit(nf, *pr, zk, -1);
    2675     3532254 :   *T = modpr_get_T(modpr);
    2676     3532211 :   *pr = modpr_get_pr(modpr);
    2677     3532197 :   *p = pr_get_p(*pr); return modpr;
    2678             : }
    2679             : 
    2680             : /* Return an element of O_K which is set to x Mod T */
    2681             : GEN
    2682        4403 : modpr_genFq(GEN modpr)
    2683             : {
    2684        4403 :   switch(lg(modpr))
    2685             :   {
    2686         917 :     case SMALLMODPR: /* Fp */
    2687         917 :       return gen_1;
    2688        1568 :     case LARGEMODPR:  /* painful case, p \mid index */
    2689        1568 :       return gmael(modpr,mpr_NFP, 2);
    2690        1918 :     default: /* trivial case : p \nmid index */
    2691             :     {
    2692        1918 :       long v = varn( modpr_get_T(modpr) );
    2693        1918 :       return pol_x(v);
    2694             :     }
    2695             :   }
    2696             : }
    2697             : 
    2698             : GEN
    2699     3513408 : nf_to_Fq_init(GEN nf, GEN *pr, GEN *T, GEN *p) {
    2700     3513408 :   GEN modpr = to_ff_init(nf,pr,T,p,0);
    2701     3513441 :   GEN tau = modpr_TAU(modpr);
    2702     3513418 :   if (!tau) gel(modpr,mpr_TAU) = pr_anti_uniformizer(nf, *pr);
    2703     3513418 :   return modpr;
    2704             : }
    2705             : GEN
    2706       18739 : zk_to_Fq_init(GEN nf, GEN *pr, GEN *T, GEN *p) {
    2707       18739 :   return to_ff_init(nf,pr,T,p,1);
    2708             : }
    2709             : 
    2710             : /* assume x in 'basis' form (t_COL) */
    2711             : GEN
    2712     7126689 : zk_to_Fq(GEN x, GEN modpr)
    2713             : {
    2714     7126689 :   GEN pr = modpr_get_pr(modpr), p = pr_get_p(pr);
    2715     7126677 :   GEN ffproj = gel(modpr,mpr_FFP);
    2716     7126677 :   GEN T = modpr_get_T(modpr);
    2717     7126689 :   return T? FpM_FpC_mul_FpX(ffproj,x, p, varn(T)): FpV_dotproduct(ffproj,x, p);
    2718             : }
    2719             : 
    2720             : /* REDUCTION Modulo a prime ideal */
    2721             : 
    2722             : /* nf a true nf, not GC-clean, OK for gerepileupto */
    2723             : static GEN
    2724    15207423 : nf_to_Fq_i(GEN nf, GEN x0, GEN modpr)
    2725             : {
    2726    15207423 :   GEN x = x0, den, pr = modpr_get_pr(modpr), p = pr_get_p(pr);
    2727    15207413 :   long tx = typ(x);
    2728             : 
    2729    15207413 :   if (tx == t_POLMOD) { x = gel(x,2); tx = typ(x); }
    2730    15207413 :   switch(tx)
    2731             :   {
    2732     8162301 :     case t_INT: return modii(x, p);
    2733        8962 :     case t_FRAC: return Rg_to_Fp(x, p);
    2734      208404 :     case t_POL:
    2735      208404 :       switch(lg(x))
    2736             :       {
    2737         224 :         case 2: return gen_0;
    2738       25793 :         case 3: return Rg_to_Fp(gel(x,2), p);
    2739             :       }
    2740      182387 :       x = Q_remove_denom(x, &den);
    2741      182402 :       x = poltobasis(nf, x);
    2742             :       /* content(x) and den may not be coprime */
    2743      182192 :       break;
    2744     6827775 :     case t_COL:
    2745     6827775 :       x = Q_remove_denom(x, &den);
    2746             :       /* content(x) and den are coprime */
    2747     6827770 :       if (lg(x)-1 == nf_get_degree(nf)) break;
    2748          48 :     default: pari_err_TYPE("Rg_to_ff",x);
    2749             :       return NULL;/*LCOV_EXCL_LINE*/
    2750             :   }
    2751     7009905 :   if (den)
    2752             :   {
    2753      137864 :     long v = Z_pvalrem(den, p, &den);
    2754      137864 :     if (v)
    2755             :     {
    2756       13489 :       if (tx == t_POL) v -= ZV_pvalrem(x, p, &x);
    2757             :       /* now v = valuation(true denominator of x) */
    2758       13489 :       if (v > 0)
    2759             :       {
    2760       12901 :         GEN tau = modpr_TAU(modpr);
    2761       12901 :         if (!tau) pari_err_TYPE("zk_to_ff", x0);
    2762       12901 :         x = nfmuli(nf,x, nfpow_u(nf, tau, v));
    2763       12901 :         v -= ZV_pvalrem(x, p, &x);
    2764             :       }
    2765       13489 :       if (v > 0) pari_err_INV("Rg_to_ff", mkintmod(gen_0,p));
    2766       13461 :       if (v) return gen_0;
    2767        8652 :       if (is_pm1(den)) den = NULL;
    2768             :     }
    2769      133027 :     x = FpC_red(x, p);
    2770             :   }
    2771     7005068 :   x = zk_to_Fq(x, modpr);
    2772     7005103 :   if (den)
    2773             :   {
    2774      127682 :     GEN c = Fp_inv(den, p);
    2775      127693 :     x = typ(x) == t_INT? Fp_mul(x,c,p): FpX_Fp_mul(x,c,p);
    2776             :   }
    2777     7005114 :   return x;
    2778             : }
    2779             : 
    2780             : GEN
    2781         210 : nfreducemodpr(GEN nf, GEN x, GEN modpr)
    2782             : {
    2783         210 :   pari_sp av = avma;
    2784         210 :   nf = checknf(nf); checkmodpr(modpr);
    2785         210 :   return gerepileupto(av, algtobasis(nf, Fq_to_nf(nf_to_Fq_i(nf,x,modpr),modpr)));
    2786             : }
    2787             : 
    2788             : GEN
    2789         350 : nfmodpr(GEN nf, GEN x, GEN pr)
    2790             : {
    2791         350 :   pari_sp av = avma;
    2792             :   GEN T, p, modpr;
    2793         350 :   nf = checknf(nf);
    2794         350 :   modpr = nf_to_Fq_init(nf, &pr, &T, &p);
    2795         343 :   if (typ(x) == t_MAT && lg(x) == 3)
    2796          42 :   {
    2797          49 :     GEN y, v = famat_nfvalrem(nf, x, pr, &y);
    2798          49 :     long s = signe(v);
    2799          49 :     if (s < 0) pari_err_INV("nfmodpr", mkintmod(gen_0,p));
    2800          42 :     if (s > 0)
    2801          28 :       x = gen_0;
    2802             :     else
    2803          14 :       x = FqV_factorback(nfV_to_FqV(gel(y,1), nf, modpr), gel(y,2), T, p);
    2804             :   }
    2805             :   else
    2806         294 :     x = nf_to_Fq_i(nf, x, modpr);
    2807         224 :   if (!T) return gerepileupto(av, Fp_to_mod(x, p));
    2808          56 :   x = Fq_to_FF(x, Tp_to_FF(T,p));
    2809          56 :   return gerepilecopy(av, x);
    2810             : }
    2811             : GEN
    2812          77 : nfmodprlift(GEN nf, GEN x, GEN pr)
    2813             : {
    2814          77 :   pari_sp av = avma;
    2815             :   GEN T, p, modpr;
    2816             :   long d;
    2817          77 :   nf = checknf(nf);
    2818          77 :   switch(typ(x))
    2819             :   {
    2820           7 :     case t_INT: return icopy(x);
    2821          28 :     case t_INTMOD: return icopy(gel(x,2));
    2822          14 :     case t_FFELT: break;
    2823          28 :     case t_VEC: case t_COL: case t_MAT:
    2824          63 :       pari_APPLY_same(nfmodprlift(nf,gel(x,i),pr));
    2825           0 :     default: pari_err_TYPE("nfmodprlit",x);
    2826             :   }
    2827          14 :   x = FF_to_FpXQ(x);
    2828          14 :   setvarn(x, nf_get_varn(nf));
    2829          14 :   d = degpol(x);
    2830          14 :   if (d <= 0) { set_avma(av); return d? gen_0: icopy(gel(x,2)); }
    2831          14 :   modpr = nf_to_Fq_init(nf, &pr, &T, &p);
    2832          14 :   return gerepilecopy(av, Fq_to_nf(x, modpr));
    2833             : }
    2834             : 
    2835             : /* lift A from residue field to nf */
    2836             : GEN
    2837     3239279 : Fq_to_nf(GEN A, GEN modpr)
    2838             : {
    2839             :   long dA;
    2840     3239279 :   if (typ(A) == t_INT || lg(modpr) < LARGEMODPR) return A;
    2841       44428 :   dA = degpol(A);
    2842       44428 :   if (dA <= 0) return dA ? gen_0: gel(A,2);
    2843       40444 :   return ZM_ZX_mul(gel(modpr,mpr_NFP), A);
    2844             : }
    2845             : GEN
    2846           0 : FqV_to_nfV(GEN x, GEN modpr)
    2847           0 : { pari_APPLY_same(Fq_to_nf(gel(x,i), modpr)) }
    2848             : GEN
    2849       10610 : FqM_to_nfM(GEN A, GEN modpr)
    2850             : {
    2851       10610 :   long i,j,h,l = lg(A);
    2852       10610 :   GEN B = cgetg(l, t_MAT);
    2853             : 
    2854       10610 :   if (l == 1) return B;
    2855        9883 :   h = lgcols(A);
    2856       44216 :   for (j=1; j<l; j++)
    2857             :   {
    2858       34333 :     GEN Aj = gel(A,j), Bj = cgetg(h,t_COL); gel(B,j) = Bj;
    2859      223126 :     for (i=1; i<h; i++) gel(Bj,i) = Fq_to_nf(gel(Aj,i), modpr);
    2860             :   }
    2861        9883 :   return B;
    2862             : }
    2863             : GEN
    2864       12669 : FqX_to_nfX(GEN x, GEN modpr)
    2865             : {
    2866       12669 :   if (typ(x) != t_POL) return icopy(x); /* scalar */
    2867       55213 :   pari_APPLY_pol(Fq_to_nf(gel(x,i), modpr));
    2868             : }
    2869             : 
    2870             : /* true nf */
    2871             : static GEN
    2872    15206912 : gc_nf_to_Fq(GEN nf, GEN A, GEN modpr)
    2873             : {
    2874    15206912 :   pari_sp av = avma;
    2875    15206912 :   return gerepileupto(av, nf_to_Fq_i(nf, A, modpr));
    2876             : }
    2877             : GEN
    2878    12634136 : nf_to_Fq(GEN nf, GEN A, GEN modpr)
    2879    12634136 : { return gc_nf_to_Fq(checknf(nf), A, modpr); }
    2880             : /* A t_VEC/t_COL */
    2881             : GEN
    2882      167403 : nfV_to_FqV(GEN x, GEN nf, GEN modpr)
    2883             : {
    2884      167403 :   nf = checknf(nf);
    2885      916788 :   pari_APPLY_same(gc_nf_to_Fq(nf, gel(x,i), modpr));
    2886             : }
    2887             : /* A  t_MAT */
    2888             : GEN
    2889        5809 : nfM_to_FqM(GEN A, GEN nf, GEN modpr)
    2890             : {
    2891        5809 :   long i,j,h,l = lg(A);
    2892        5809 :   GEN B = cgetg(l,t_MAT);
    2893             : 
    2894        5809 :   if (l == 1) return B;
    2895        5809 :   h = lgcols(A); nf = checknf(nf);
    2896      159665 :   for (j=1; j<l; j++)
    2897             :   {
    2898      153856 :     GEN Aj = gel(A,j), Bj = cgetg(h,t_COL); gel(B,j) = Bj;
    2899     1073774 :     for (i=1; i<h; i++) gel(Bj,i) = gc_nf_to_Fq(nf, gel(Aj,i), modpr);
    2900             :   }
    2901        5809 :   return B;
    2902             : }
    2903             : /* A t_POL */
    2904             : GEN
    2905       10857 : nfX_to_FqX(GEN x, GEN nf, GEN modpr)
    2906             : {
    2907       10857 :   nf = checknf(nf);
    2908       59688 :   pari_APPLY_pol(gc_nf_to_Fq(nf, gel(x,i), modpr));
    2909             : }
    2910             : 
    2911             : /*******************************************************************/
    2912             : /*                                                                 */
    2913             : /*                       RELATIVE ROUND 2                          */
    2914             : /*                                                                 */
    2915             : /*******************************************************************/
    2916             : /* Shallow functions */
    2917             : /* FIXME: use a bb_field and export the nfX_* routines */
    2918             : static GEN
    2919        4872 : nfX_sub(GEN nf, GEN x, GEN y)
    2920             : {
    2921        4872 :   long i, lx = lg(x), ly = lg(y);
    2922             :   GEN z;
    2923        4872 :   if (ly <= lx) {
    2924        4872 :     z = cgetg(lx,t_POL); z[1] = x[1];
    2925       29435 :     for (i=2; i < ly; i++) gel(z,i) = nfsub(nf,gel(x,i),gel(y,i));
    2926        4872 :     for (   ; i < lx; i++) gel(z,i) = gel(x,i);
    2927        4872 :     z = normalizepol_lg(z, lx);
    2928             :   } else {
    2929           0 :     z = cgetg(ly,t_POL); z[1] = y[1];
    2930           0 :     for (i=2; i < lx; i++) gel(z,i) = nfsub(nf,gel(x,i),gel(y,i));
    2931           0 :     for (   ; i < ly; i++) gel(z,i) = gneg(gel(y,i));
    2932           0 :     z = normalizepol_lg(z, ly);
    2933             :   }
    2934        4872 :   return z;
    2935             : }
    2936             : /* FIXME: quadratic multiplication */
    2937             : static GEN
    2938       67794 : nfX_mul(GEN nf, GEN a, GEN b)
    2939             : {
    2940       67794 :   long da = degpol(a), db = degpol(b), dc, lc, k;
    2941             :   GEN c;
    2942       67794 :   if (da < 0 || db < 0) return gen_0;
    2943       67794 :   dc = da + db;
    2944       67794 :   if (dc == 0) return nfmul(nf, gel(a,2),gel(b,2));
    2945       67794 :   lc = dc+3;
    2946       67794 :   c = cgetg(lc, t_POL); c[1] = a[1];
    2947      538310 :   for (k = 0; k <= dc; k++)
    2948             :   {
    2949      470516 :     long i, I = minss(k, da);
    2950      470516 :     GEN d = NULL;
    2951     1594824 :     for (i = maxss(k-db, 0); i <= I; i++)
    2952             :     {
    2953     1124308 :       GEN e = nfmul(nf, gel(a, i+2), gel(b, k-i+2));
    2954     1124308 :       d = d? nfadd(nf, d, e): e;
    2955             :     }
    2956      470516 :     gel(c, k+2) = d;
    2957             :   }
    2958       67794 :   return normalizepol_lg(c, lc);
    2959             : }
    2960             : /* assume b monic */
    2961             : static GEN
    2962       62922 : nfX_rem(GEN nf, GEN a, GEN b)
    2963             : {
    2964       62922 :   long da = degpol(a), db = degpol(b);
    2965       62922 :   if (da < 0) return gen_0;
    2966       62922 :   a = leafcopy(a);
    2967      150386 :   while (da >= db)
    2968             :   {
    2969       87464 :     long i, k = da;
    2970       87464 :     GEN A = gel(a, k+2);
    2971      632930 :     for (i = db-1, k--; i >= 0; i--, k--)
    2972      545466 :       gel(a,k+2) = nfsub(nf, gel(a,k+2), nfmul(nf, A, gel(b,i+2)));
    2973       87464 :     a = normalizepol_lg(a, lg(a)-1);
    2974       87464 :     da = degpol(a);
    2975             :   }
    2976       62922 :   return a;
    2977             : }
    2978             : static GEN
    2979       62922 : nfXQ_mul(GEN nf, GEN a, GEN b, GEN T)
    2980             : {
    2981       62922 :   GEN c = nfX_mul(nf, a, b);
    2982       62922 :   if (typ(c) != t_POL) return c;
    2983       62922 :   return nfX_rem(nf, c, T);
    2984             : }
    2985             : 
    2986             : static void
    2987       13368 : fill(long l, GEN H, GEN Hx, GEN I, GEN Ix)
    2988             : {
    2989             :   long i;
    2990       13368 :   if (typ(Ix) == t_VEC) /* standard */
    2991       48479 :     for (i=1; i<l; i++) { gel(H,i) = gel(Hx,i); gel(I,i) = gel(Ix,i); }
    2992             :   else /* constant ideal */
    2993       13698 :     for (i=1; i<l; i++) { gel(H,i) = gel(Hx,i); gel(I,i) = Ix; }
    2994       13368 : }
    2995             : 
    2996             : /* given MODULES x and y by their pseudo-bases, returns a pseudo-basis of the
    2997             :  * module generated by x and y. */
    2998             : static GEN
    2999        6684 : rnfjoinmodules_i(GEN nf, GEN Hx, GEN Ix, GEN Hy, GEN Iy)
    3000             : {
    3001        6684 :   long lx = lg(Hx), ly = lg(Hy), l = lx+ly-1;
    3002        6684 :   GEN H = cgetg(l, t_MAT), I = cgetg(l, t_VEC);
    3003        6684 :   fill(lx, H     , Hx, I     , Ix);
    3004        6684 :   fill(ly, H+lx-1, Hy, I+lx-1, Iy); return nfhnf(nf, mkvec2(H, I));
    3005             : }
    3006             : static GEN
    3007        2316 : rnfjoinmodules(GEN nf, GEN x, GEN y)
    3008             : {
    3009        2316 :   if (!x) return y;
    3010        1379 :   if (!y) return x;
    3011        1379 :   return rnfjoinmodules_i(nf, gel(x,1), gel(x,2), gel(y,1), gel(y,2));
    3012             : }
    3013             : 
    3014             : typedef struct {
    3015             :   GEN multab, T,p;
    3016             :   long h;
    3017             : } rnfeltmod_muldata;
    3018             : 
    3019             : static GEN
    3020       71293 : _sqr(void *data, GEN x)
    3021             : {
    3022       71293 :   rnfeltmod_muldata *D = (rnfeltmod_muldata *) data;
    3023       49090 :   GEN z = x? tablesqr(D->multab,x)
    3024       71293 :            : tablemul_ei_ej(D->multab,D->h,D->h);
    3025       71293 :   return FqC_red(z,D->T,D->p);
    3026             : }
    3027             : static GEN
    3028       11557 : _msqr(void *data, GEN x)
    3029             : {
    3030       11557 :   GEN x2 = _sqr(data, x), z;
    3031       11557 :   rnfeltmod_muldata *D = (rnfeltmod_muldata *) data;
    3032       11557 :   z = tablemul_ei(D->multab, x2, D->h);
    3033       11557 :   return FqC_red(z,D->T,D->p);
    3034             : }
    3035             : 
    3036             : /* Compute W[h]^n mod (T,p) in the extension, assume n >= 0. T a ZX */
    3037             : static GEN
    3038       22203 : rnfeltid_powmod(GEN multab, long h, GEN n, GEN T, GEN p)
    3039             : {
    3040       22203 :   pari_sp av = avma;
    3041             :   GEN y;
    3042             :   rnfeltmod_muldata D;
    3043             : 
    3044       22203 :   if (!signe(n)) return gen_1;
    3045             : 
    3046       22203 :   D.multab = multab;
    3047       22203 :   D.h = h;
    3048       22203 :   D.T = T;
    3049       22203 :   D.p = p;
    3050       22203 :   y = gen_pow_fold(NULL, n, (void*)&D, &_sqr, &_msqr);
    3051       22203 :   return gerepilecopy(av, y);
    3052             : }
    3053             : 
    3054             : /* P != 0 has at most degpol(P) roots. Look for an element in Fq which is not
    3055             :  * a root, cf repres() */
    3056             : static GEN
    3057          21 : FqX_non_root(GEN P, GEN T, GEN p)
    3058             : {
    3059          21 :   long dP = degpol(P), f, vT;
    3060             :   long i, j, k, pi, pp;
    3061             :   GEN v;
    3062             : 
    3063          21 :   if (dP == 0) return gen_1;
    3064          21 :   pp = is_bigint(p) ? dP+1: itos(p);
    3065          21 :   v = cgetg(dP + 2, t_VEC);
    3066          21 :   gel(v,1) = gen_0;
    3067          21 :   if (T)
    3068           0 :   { f = degpol(T); vT = varn(T); }
    3069             :   else
    3070          21 :   { f = 1; vT = 0; }
    3071          42 :   for (i=pi=1; i<=f; i++,pi*=pp)
    3072             :   {
    3073          21 :     GEN gi = i == 1? gen_1: pol_xn(i-1, vT), jgi = gi;
    3074          42 :     for (j=1; j<pp; j++)
    3075             :     {
    3076          42 :       for (k=1; k<=pi; k++)
    3077             :       {
    3078          21 :         GEN z = Fq_add(gel(v,k), jgi, T,p);
    3079          21 :         if (!gequal0(FqX_eval(P, z, T,p))) return z;
    3080          21 :         gel(v, j*pi+k) = z;
    3081             :       }
    3082          21 :       if (j < pp-1) jgi = Fq_add(jgi, gi, T,p); /* j*g[i] */
    3083             :     }
    3084             :   }
    3085          21 :   return NULL;
    3086             : }
    3087             : 
    3088             : /* true nf, x t_POL */
    3089             : static int
    3090       12313 : nfpolisintegral_i(GEN nf, GEN x)
    3091             : {
    3092       12313 :   GEN d, T = nf_get_pol(nf);
    3093       12313 :   long l = lg(x);
    3094       12313 :   if (varn(x) != varn(T)) pari_err_VAR("nfisintegral", x,T);
    3095       12313 :   if (l >= lg(T)) { x = RgX_rem(x, T); l = lg(x); }
    3096       12313 :   if (l == 2) return 1;
    3097       12313 :   if (l == 3)
    3098             :   {
    3099           0 :     switch(typ(gel(x,2)))
    3100             :     {
    3101           0 :       case t_INT: return 1;
    3102           0 :       case t_FRAC: return 0;
    3103           0 :       default: pari_err_TYPE("nfisintegral",x);
    3104             :     }
    3105             :   }
    3106       12313 :   x = Q_remove_denom(x, &d);
    3107       12313 :   if (!RgX_is_ZX(x)) pari_err_TYPE("nfisintegral",x);
    3108       12313 :   if (!d) return 1;
    3109         889 :   x = ZM_ZX_mul(nf_get_invzk(nf), x);
    3110         889 :   return ZV_Z_dvd(x, d);
    3111             : }
    3112             : static int
    3113       12313 : nfpolisintegral(GEN nf, GEN x)
    3114       12313 : { pari_sp av = avma; return gc_int(av, nfpolisintegral_i(nf, x)); }
    3115             : 
    3116             : /* true nf */
    3117             : static int
    3118       34307 : nfisintegral(GEN nf, GEN x)
    3119             : {
    3120       34307 :   switch(typ(x))
    3121             :   {
    3122       21987 :     case t_INT: return 1;
    3123           7 :     case t_FRAC: return 0;
    3124           0 :     case t_POLMOD:
    3125           0 :       x = checknfelt_mod(nf,x,"nfisintegral");
    3126           0 :       switch(typ(x))
    3127             :       {
    3128           0 :         case t_INT: return 1;
    3129           0 :         case t_FRAC: return 0;
    3130           0 :         case t_POL: return nfpolisintegral(nf,x);
    3131             :       }
    3132           0 :       break;
    3133       12313 :     case t_POL: return nfpolisintegral(nf,x);
    3134           0 :     case t_COL:
    3135           0 :       if (lg(x)-1 != nf_get_degree(nf)) break;
    3136           0 :       return RgV_is_ZV(x);
    3137             :   }
    3138           0 :   pari_err_TYPE("nfisintegral",x);
    3139             :   return 0; /* LCOV_EXCL_LINE */
    3140             : }
    3141             : /* true nf */
    3142             : static int
    3143        7490 : nfXisintegral(GEN nf, GEN x)
    3144             : {
    3145        7490 :   long i, l = lg(x);
    3146       41783 :   for (i = 2; i < l; i++)
    3147       34307 :     if (!nfisintegral(nf, gel(x,i))) return 0;
    3148        7476 :   return 1;
    3149             : }
    3150             : 
    3151             : /* Relative Dedekind criterion over (true) nf, applied to the order defined by a
    3152             :  * root of monic irreducible polynomial P, modulo the prime ideal pr. Assume
    3153             :  * vdisc = v_pr( disc(P) ).
    3154             :  * Return NULL if nf[X]/P is pr-maximal. Otherwise, return [flag, O, v]:
    3155             :  *   O = enlarged order, given by a pseudo-basis
    3156             :  *   flag = 1 if O is proven pr-maximal (may be 0 and O nevertheless pr-maximal)
    3157             :  *   v = v_pr(disc(O)). */
    3158             : static GEN
    3159        4900 : rnfdedekind_i(GEN nf, GEN P, GEN pr, long vdisc, long only_maximal)
    3160             : {
    3161             :   GEN Ppr, A, I, p, tau, g, h, k, base, T, gzk, hzk, prinvp, pal, nfT, modpr;
    3162             :   long m, vt, r, d, i, j, mpr;
    3163             : 
    3164        4900 :   if (vdisc < 0) pari_err_TYPE("rnfdedekind [non integral pol]", P);
    3165        4893 :   if (vdisc == 1) return NULL; /* pr-maximal */
    3166        4893 :   if (!only_maximal && !gequal1(leading_coeff(P)))
    3167           0 :     pari_err_IMPL( "the full Dedekind criterion in the nonmonic case");
    3168        4893 :   if (!nfXisintegral(nf, P))
    3169           0 :     pari_err_IMPL("non integral polynomial in rnfdedekind");
    3170             :   /* either monic OR only_maximal = 1 */
    3171        4893 :   m = degpol(P);
    3172        4893 :   nfT = nf_get_pol(nf);
    3173        4893 :   modpr = nf_to_Fq_init(nf,&pr, &T, &p);
    3174        4893 :   Ppr = nfX_to_FqX(P, nf, modpr);
    3175        4893 :   mpr = degpol(Ppr);
    3176        4893 :   if (mpr < m) /* nonmonic => only_maximal = 1 */
    3177             :   {
    3178          21 :     if (mpr < 0) return NULL;
    3179          21 :     if (! RgX_valrem(Ppr, &Ppr))
    3180             :     { /* nonzero constant coefficient */
    3181           0 :       Ppr = RgX_shift_shallow(RgX_recip_i(Ppr), m - mpr);
    3182           0 :       P = RgX_recip_i(P);
    3183             :     }
    3184             :     else
    3185             :     {
    3186          21 :       GEN z = FqX_non_root(Ppr, T, p);
    3187          21 :       if (!z) pari_err_IMPL( "Dedekind in the difficult case");
    3188           0 :       z = Fq_to_nf(z, modpr);
    3189           0 :       if (typ(z) == t_INT)
    3190           0 :         P = RgX_translate(P, z);
    3191             :       else
    3192           0 :         P = RgXQX_translate(P, z, T);
    3193           0 :       P = RgX_recip_i(P);
    3194           0 :       Ppr = nfX_to_FqX(P, nf, modpr); /* degpol(P) = degpol(Ppr) = m */
    3195             :     }
    3196             :   }
    3197        4872 :   A = gel(FqX_factor(Ppr,T,p),1);
    3198        4872 :   r = lg(A); /* > 1 */
    3199        4872 :   g = gel(A,1);
    3200        9394 :   for (i=2; i<r; i++) g = FqX_mul(g, gel(A,i), T, p);
    3201        4872 :   h = FqX_div(Ppr,g, T, p);
    3202        4872 :   gzk = FqX_to_nfX(g, modpr);
    3203        4872 :   hzk = FqX_to_nfX(h, modpr);
    3204        4872 :   k = nfX_sub(nf, P, nfX_mul(nf, gzk,hzk));
    3205        4872 :   tau = pr_get_tau(pr);
    3206        4872 :   switch(typ(tau))
    3207             :   {
    3208        2121 :     case t_INT: k = gdiv(k, p); break;
    3209        2751 :     case t_MAT: k = RgX_Rg_div(tablemulvec(NULL,tau, k), p); break;
    3210             :   }
    3211        4872 :   k = nfX_to_FqX(k, nf, modpr);
    3212        4872 :   k = FqX_normalize(FqX_gcd(FqX_gcd(g,h,  T,p), k, T,p), T,p);
    3213        4872 :   d = degpol(k);  /* <= m */
    3214        4872 :   if (!d) return NULL; /* pr-maximal */
    3215        2939 :   if (only_maximal) return gen_0; /* not maximal */
    3216             : 
    3217        2918 :   A = cgetg(m+d+1,t_MAT);
    3218        2918 :   I = cgetg(m+d+1,t_VEC); base = mkvec2(A, I);
    3219             :  /* base[2] temporarily multiplied by p, for the final nfhnfmod,
    3220             :   * which requires integral ideals */
    3221        2918 :   prinvp = pr_inv_p(pr); /* again multiplied by p */
    3222       16419 :   for (j=1; j<=m; j++)
    3223             :   {
    3224       13501 :     gel(A,j) = col_ei(m, j);
    3225       13501 :     gel(I,j) = p;
    3226             :   }
    3227        2918 :   pal = FqX_to_nfX(FqX_div(Ppr,k, T,p), modpr);
    3228        6242 :   for (   ; j<=m+d; j++)
    3229             :   {
    3230        3324 :     gel(A,j) = RgX_to_RgC(pal,m);
    3231        3324 :     gel(I,j) = prinvp;
    3232        3324 :     if (j < m+d) pal = RgXQX_rem(RgX_shift_shallow(pal,1),P,nfT);
    3233             :   }
    3234             :   /* the modulus is integral */
    3235        2918 :   base = nfhnfmod(nf,base, idealmulpowprime(nf, powiu(p,m), pr, utoineg(d)));
    3236        2918 :   gel(base,2) = gdiv(gel(base,2), p); /* cancel the factor p */
    3237        2918 :   vt = vdisc - 2*d;
    3238        2918 :   return mkvec3(vt < 2? gen_1: gen_0, base, stoi(vt));
    3239             : }
    3240             : 
    3241             : /* [L:K] = n */
    3242             : static GEN
    3243        1296 : triv_order(long n)
    3244             : {
    3245        1296 :   GEN z = cgetg(3, t_VEC);
    3246        1296 :   gel(z,1) = matid(n);
    3247        1296 :   gel(z,2) = const_vec(n, gen_1); return z;
    3248             : }
    3249             : 
    3250             : /* if flag is set, return gen_1 (resp. gen_0) if the order K[X]/(P)
    3251             :  * is pr-maximal (resp. not pr-maximal). */
    3252             : GEN
    3253          91 : rnfdedekind(GEN nf, GEN P, GEN pr, long flag)
    3254             : {
    3255          91 :   pari_sp av = avma;
    3256             :   GEN z, dP;
    3257             :   long v;
    3258             : 
    3259          91 :   nf = checknf(nf);
    3260          91 :   P = RgX_nffix("rnfdedekind", nf_get_pol(nf), P, 1);
    3261          91 :   dP = nfX_disc(nf, P);
    3262          91 :   if (gequal0(dP))
    3263           7 :     pari_err_DOMAIN("rnfdedekind","issquarefree(pol)","=",gen_0,P);
    3264          84 :   if (!pr)
    3265             :   {
    3266          21 :     GEN fa = idealfactor(nf, dP);
    3267          21 :     GEN Q = gel(fa,1), E = gel(fa,2);
    3268          21 :     pari_sp av2 = avma;
    3269          21 :     long i, l = lg(Q);
    3270          21 :     for (i = 1; i < l; i++, set_avma(av2))
    3271             :     {
    3272          21 :       v = itos(gel(E,i));
    3273          21 :       if (rnfdedekind_i(nf,P,gel(Q,i),v,1)) { set_avma(av); return gen_0; }
    3274           0 :       set_avma(av2);
    3275             :     }
    3276           0 :     set_avma(av); return gen_1;
    3277             :   }
    3278          63 :   else if (typ(pr) == t_VEC)
    3279             :   { /* flag = 1 is implicit */
    3280          63 :     if (lg(pr) == 1) { set_avma(av); return gen_1; }
    3281          63 :     if (typ(gel(pr,1)) == t_VEC)
    3282             :     { /* list of primes */
    3283          14 :       GEN Q = pr;
    3284          14 :       pari_sp av2 = avma;
    3285          14 :       long i, l = lg(Q);
    3286          14 :       for (i = 1; i < l; i++, set_avma(av2))
    3287             :       {
    3288          14 :         v = nfval(nf, dP, gel(Q,i));
    3289          14 :         if (rnfdedekind_i(nf,P,gel(Q,i),v,1)) { set_avma(av); return gen_0; }
    3290             :       }
    3291           0 :       set_avma(av); return gen_1;
    3292             :     }
    3293             :   }
    3294             :   /* single prime */
    3295          49 :   v = nfval(nf, dP, pr);
    3296          49 :   z = rnfdedekind_i(nf, P, pr, v, flag);
    3297          42 :   if (z)
    3298             :   {
    3299          21 :     if (flag) { set_avma(av); return gen_0; }
    3300          14 :     z = gerepilecopy(av, z);
    3301             :   }
    3302             :   else
    3303             :   {
    3304          21 :     set_avma(av); if (flag) return gen_1;
    3305           7 :     z = cgetg(4, t_VEC);
    3306           7 :     gel(z,1) = gen_1;
    3307           7 :     gel(z,2) = triv_order(degpol(P));
    3308           7 :     gel(z,3) = stoi(v);
    3309             :   }
    3310          21 :   return z;
    3311             : }
    3312             : 
    3313             : static int
    3314       28355 : ideal_is1(GEN x) {
    3315       28355 :   switch(typ(x))
    3316             :   {
    3317       12235 :     case t_INT: return is_pm1(x);
    3318       15217 :     case t_MAT: return RgM_isidentity(x);
    3319             :   }
    3320         903 :   return 0;
    3321             : }
    3322             : 
    3323             : /* return a in ideal A such that v_pr(a) = v_pr(A) */
    3324             : static GEN
    3325       15966 : minval(GEN nf, GEN A, GEN pr)
    3326             : {
    3327       15966 :   GEN ab = idealtwoelt(nf,A), a = gel(ab,1), b = gel(ab,2);
    3328       15966 :   if (nfval(nf,a,pr) > nfval(nf,b,pr)) a = b;
    3329       15966 :   return a;
    3330             : }
    3331             : 
    3332             : /* nf a true nf. Return NULL if power order is pr-maximal */
    3333             : static GEN
    3334        4816 : rnfmaxord(GEN nf, GEN pol, GEN pr, long vdisc)
    3335             : {
    3336        4816 :   pari_sp av = avma, av1;
    3337             :   long i, j, k, n, nn, vpol, cnt, sep;
    3338             :   GEN q, q1, p, T, modpr, W, I, p1;
    3339             :   GEN prhinv, mpi, Id;
    3340             : 
    3341        4816 :   if (DEBUGLEVEL>1) err_printf(" treating %Ps^%ld\n", pr, vdisc);
    3342        4816 :   modpr = nf_to_Fq_init(nf,&pr,&T,&p);
    3343        4816 :   av1 = avma;
    3344        4816 :   p1 = rnfdedekind_i(nf, pol, modpr, vdisc, 0);
    3345        4816 :   if (!p1) return gc_NULL(av);
    3346        2904 :   if (is_pm1(gel(p1,1))) return gerepilecopy(av,gel(p1,2));
    3347        1364 :   sep = itos(gel(p1,3));
    3348        1364 :   W = gmael(p1,2,1);
    3349        1364 :   I = gmael(p1,2,2);
    3350        1364 :   gerepileall(av1, 2, &W, &I);
    3351             : 
    3352        1364 :   mpi = zk_multable(nf, pr_get_gen(pr));
    3353        1364 :   n = degpol(pol); nn = n*n;
    3354        1364 :   vpol = varn(pol);
    3355        1364 :   q1 = q = pr_norm(pr);
    3356        1882 :   while (abscmpiu(q1,n) < 0) q1 = mulii(q1,q);
    3357        1364 :   Id = matid(n);
    3358        1364 :   prhinv = pr_inv(pr);
    3359        1364 :   av1 = avma;
    3360        1364 :   for(cnt=1;; cnt++)
    3361        4445 :   {
    3362        5809 :     GEN I0 = leafcopy(I), W0 = leafcopy(W);
    3363             :     GEN Wa, Winv, Ip, A, MW, MWmod, F, pseudo, C, G;
    3364        5809 :     GEN Tauinv = cgetg(n+1, t_VEC), Tau = cgetg(n+1, t_VEC);
    3365             : 
    3366        5809 :     if (DEBUGLEVEL>1) err_printf("    pass no %ld\n",cnt);
    3367       33821 :     for (j=1; j<=n; j++)
    3368             :     {
    3369             :       GEN tau, tauinv;
    3370       28012 :       if (ideal_is1(gel(I,j)))
    3371             :       {
    3372       12046 :         gel(I,j) = gel(Tau,j) = gel(Tauinv,j) = gen_1;
    3373       12046 :         continue;
    3374             :       }
    3375       15966 :       gel(Tau,j) = tau = minval(nf, gel(I,j), pr);
    3376       15966 :       gel(Tauinv,j) = tauinv = nfinv(nf, tau);
    3377       15966 :       gel(W,j) = nfC_nf_mul(nf, gel(W,j), tau);
    3378       15966 :       gel(I,j) = idealmul(nf, tauinv, gel(I,j)); /* v_pr(I[j]) = 0 */
    3379             :     }
    3380             :     /* W = (Z_K/pr)-basis of O/pr. O = (W0,I0) ~ (W, I) */
    3381             : 
    3382             :    /* compute MW: W_i*W_j = sum MW_k,(i,j) W_k */
    3383        5809 :     Wa = RgM_to_RgXV(W,vpol);
    3384        5809 :     Winv = nfM_inv(nf, W);
    3385        5809 :     MW = cgetg(nn+1, t_MAT);
    3386             :     /* W_1 = 1 */
    3387       33821 :     for (j=1; j<=n; j++) gel(MW, j) = gel(MW, (j-1)*n+1) = gel(Id,j);
    3388       28012 :     for (i=2; i<=n; i++)
    3389       85125 :       for (j=i; j<=n; j++)
    3390             :       {
    3391       62922 :         GEN z = nfXQ_mul(nf, gel(Wa,i), gel(Wa,j), pol);
    3392       62922 :         if (typ(z) != t_POL)
    3393           0 :           z = nfC_nf_mul(nf, gel(Winv,1), z);
    3394             :         else
    3395             :         {
    3396       62922 :           z = RgX_to_RgC(z, lg(Winv)-1);
    3397       62922 :           z = nfM_nfC_mul(nf, Winv, z);
    3398             :         }
    3399       62922 :         gel(MW, (i-1)*n+j) = gel(MW, (j-1)*n+i) = z;
    3400             :       }
    3401             : 
    3402             :     /* compute Ip =  pr-radical [ could use Ker(trace) if q large ] */
    3403        5809 :     MWmod = nfM_to_FqM(MW,nf,modpr);
    3404        5809 :     F = cgetg(n+1, t_MAT); gel(F,1) = gel(Id,1);
    3405       28012 :     for (j=2; j<=n; j++) gel(F,j) = rnfeltid_powmod(MWmod, j, q1, T,p);
    3406        5809 :     Ip = FqM_ker(F,T,p);
    3407        5809 :     if (lg(Ip) == 1) { W = W0; I = I0; break; }
    3408             : 
    3409             :     /* Fill C: W_k A_j = sum_i C_(i,j),k A_i */
    3410        5305 :     A = FqM_to_nfM(FqM_suppl(Ip,T,p), modpr);
    3411       13935 :     for (j = lg(Ip); j<=n; j++) gel(A,j) = nfC_multable_mul(gel(A,j), mpi);
    3412        5305 :     MW = nfM_mul(nf, nfM_inv(nf,A), MW);
    3413        5305 :     C = cgetg(n+1, t_MAT);
    3414       31245 :     for (k=1; k<=n; k++)
    3415             :     {
    3416       25940 :       GEN mek = vecslice(MW, (k-1)*n+1, k*n), Ck;
    3417       25940 :       gel(C,k) = Ck = cgetg(nn+1, t_COL);
    3418      169240 :       for (j = 1; j <= n; j++)
    3419             :       {
    3420      143300 :         GEN z = nfM_nfC_mul(nf, mek, gel(A,j));
    3421      997936 :         for (i = 1; i <= n; i++)
    3422      854636 :           gel(Ck, (j-1)*n+i) = gc_nf_to_Fq(nf,gel(z,i),modpr);
    3423             :       }
    3424             :     }
    3425        5305 :     G = FqM_to_nfM(FqM_ker(C,T,p), modpr);
    3426             : 
    3427        5305 :     pseudo = rnfjoinmodules_i(nf, G,prhinv, Id,I);
    3428             :     /* express W in terms of the power basis */
    3429        5305 :     W = nfM_mul(nf, W, gel(pseudo,1));
    3430        5305 :     I = gel(pseudo,2);
    3431             :     /* restore the HNF property W[i,i] = 1. NB: W upper triangular, with
    3432             :      * W[i,i] = Tau[i] */
    3433       31245 :     for (j=1; j<=n; j++)
    3434       25940 :       if (gel(Tau,j) != gen_1)
    3435             :       {
    3436       14615 :         gel(W,j) = nfC_nf_mul(nf, gel(W,j), gel(Tauinv,j));
    3437       14615 :         gel(I,j) = idealmul(nf, gel(Tau,j), gel(I,j));
    3438             :       }
    3439        5305 :     if (DEBUGLEVEL>3) err_printf(" new order:\n%Ps\n%Ps\n", W, I);
    3440        5305 :     if (sep <= 3 || gequal(I,I0)) break;
    3441             : 
    3442        4445 :     if (gc_needed(av1,2))
    3443             :     {
    3444           0 :       if(DEBUGMEM>1) pari_warn(warnmem,"rnfmaxord");
    3445           0 :       gerepileall(av1,2, &W,&I);
    3446             :     }
    3447             :   }
    3448        1364 :   return gerepilecopy(av, mkvec2(W, I));
    3449             : }
    3450             : 
    3451             : GEN
    3452      906885 : Rg_nffix(const char *f, GEN T, GEN c, int lift)
    3453             : {
    3454      906885 :   switch(typ(c))
    3455             :   {
    3456      493105 :     case t_INT: case t_FRAC: return c;
    3457       68307 :     case t_POL:
    3458       68307 :       if (lg(c) >= lg(T)) c = RgX_rem(c,T);
    3459       68307 :       break;
    3460      345466 :     case t_POLMOD:
    3461      345466 :       if (!RgX_equal_var(gel(c,1), T)) pari_err_MODULUS(f, gel(c,1),T);
    3462      344885 :       c = gel(c,2);
    3463      344885 :       switch(typ(c))
    3464             :       {
    3465      300976 :         case t_POL: break;
    3466       43909 :         case t_INT: case t_FRAC: return c;
    3467           0 :         default: pari_err_TYPE(f, c);
    3468             :       }
    3469      300976 :       break;
    3470           7 :     default: pari_err_TYPE(f,c);
    3471             :   }
    3472             :   /* typ(c) = t_POL */
    3473      369283 :   if (varn(c) != varn(T)) pari_err_VAR(f, c,T);
    3474      369269 :   switch(lg(c))
    3475             :   {
    3476       13353 :     case 2: return gen_0;
    3477       30071 :     case 3:
    3478       30071 :       c = gel(c,2); if (is_rational_t(typ(c))) return c;
    3479           0 :       pari_err_TYPE(f,c);
    3480             :   }
    3481      325845 :   RgX_check_QX(c, f);
    3482      325824 :   return lift? c: mkpolmod(c, T);
    3483             : }
    3484             : /* check whether x is a polynomials with coeffs in number field Q[y]/(T)
    3485             :  * and returned a normalized copy. If 'lift' is set return lifted coefs
    3486             :  * (t_POL/t_FRAC/t_INT) else t_POLMOD/t_FRAC/t_INT */
    3487             : GEN
    3488      303860 : RgX_nffix(const char *f, GEN T, GEN x, int lift)
    3489             : {
    3490      303860 :   long vT = varn(T);
    3491      303860 :   if (typ(x) != t_POL) pari_err_TYPE(stack_strcat(f," [t_POL expected]"), x);
    3492      303860 :   if (varncmp(varn(x), vT) >= 0) pari_err_PRIORITY(f, x, ">=", vT);
    3493     1147169 :   pari_APPLY_pol_normalized(Rg_nffix(f, T, gel(x,i), lift));
    3494             : }
    3495             : GEN
    3496          49 : RgV_nffix(const char *f, GEN T, GEN x, int lift)
    3497         119 : { pari_APPLY_same(Rg_nffix(f, T, gel(x,i), lift)); }
    3498             : 
    3499             : static GEN
    3500        2653 : get_d(GEN nf, GEN d)
    3501             : {
    3502        2653 :   GEN b = idealredmodpower(nf, d, 2, 100000);
    3503        2653 :   return nfmul(nf, d, nfsqr(nf,b));
    3504             : }
    3505             : 
    3506             : /* true nf */
    3507             : static GEN
    3508        4361 : pr_factorback(GEN nf, GEN fa)
    3509             : {
    3510        4361 :   GEN P = gel(fa,1), E = gel(fa,2), z = gen_1;
    3511        4361 :   long i, l = lg(P);
    3512        9765 :   for (i = 1; i < l; i++) z = idealmulpowprime(nf, z, gel(P,i), gel(E,i));
    3513        4361 :   return z;
    3514             : }
    3515             : /* true nf */
    3516             : static GEN
    3517        4361 : pr_factorback_scal(GEN nf, GEN fa)
    3518             : {
    3519        4361 :   GEN D = pr_factorback(nf,fa);
    3520        4361 :   if (typ(D) == t_MAT && RgM_isscalar(D,NULL)) D = gcoeff(D,1,1);
    3521        4361 :   return D;
    3522             : }
    3523             : 
    3524             : /* nf = base field K
    3525             :  * pol= monic polynomial in Z_K[X] defining a relative extension L = K[X]/(pol).
    3526             :  * Returns a pseudo-basis [A,I] of Z_L, set *pD to [D,d] and *pf to the
    3527             :  * index-ideal; rnf is used when lim != 0 and may be NULL */
    3528             : GEN
    3529        2604 : rnfallbase(GEN nf, GEN pol, GEN lim, GEN rnf, GEN *pD, GEN *pf, GEN *pDKP)
    3530             : {
    3531             :   long i, j, jf, l;
    3532             :   GEN fa, E, P, Ef, Pf, z, disc;
    3533             : 
    3534        2604 :   nf = checknf(nf); pol = liftpol_shallow(pol);
    3535        2604 :   if (!gequal1(leading_coeff(pol)))
    3536           7 :     pari_err_IMPL("nonmonic relative polynomials in rnfallbase");
    3537        2597 :   if (!nfXisintegral(nf, pol))
    3538          14 :     pari_err_IMPL("non integral polynomial in rnfallbase");
    3539        2583 :   disc = nf_to_scalar_or_basis(nf, nfX_disc(nf, pol));
    3540        2583 :   if (gequal0(disc))
    3541           7 :     pari_err_DOMAIN("rnfpseudobasis","issquarefree(pol)","=",gen_0, pol);
    3542        2576 :   if (lim)
    3543             :   {
    3544             :     GEN rnfeq, zknf, dzknf, U, vU, dA, A, MB, dB, BdB, vj, B, Tabs;
    3545         406 :     GEN D = idealhnf_shallow(nf, disc), extendP = NULL;
    3546         406 :     long rU, m = nf_get_degree(nf), n = degpol(pol), N = n*m;
    3547             :     nfmaxord_t S;
    3548             : 
    3549         406 :     if (typ(lim) == t_INT)
    3550         112 :       P = ZV_union_shallow(nf_get_ramified_primes(nf),
    3551         112 :                            gel(Z_factor_limit(gcoeff(D,1,1), itou(lim)), 1));
    3552             :     else
    3553             :     {
    3554         294 :       P = cgetg_copy(lim, &l);
    3555         882 :       for (i = 1; i < l; i++)
    3556             :       {
    3557         588 :         GEN p = gel(lim,i);
    3558         588 :         if (typ(p) != t_INT) p = pr_get_p(p);
    3559         588 :         gel(P,i) = p;
    3560             :       }
    3561         294 :       P = ZV_sort_uniq_shallow(P);
    3562             :     }
    3563         406 :     if (rnf)
    3564             :     {
    3565         357 :       rnfeq = rnf_get_map(rnf);
    3566         357 :       zknf = rnf_get_nfzk(rnf);
    3567             :     }
    3568             :     else
    3569             :     {
    3570          49 :       rnfeq = nf_rnfeq(nf, pol);
    3571          49 :       zknf = nf_nfzk(nf, rnfeq);
    3572             :     }
    3573         406 :     dzknf = gel(zknf,1);
    3574         406 :     if (gequal1(dzknf)) dzknf = NULL;
    3575         273 : RESTART:
    3576         413 :     if (extendP)
    3577             :     {
    3578           7 :       GEN oldP = P;
    3579           7 :       if (typ(extendP)==t_POL)
    3580             :       {
    3581           0 :         long l = lg(extendP);
    3582           0 :         for (i = 2; i < l; i++)
    3583             :         {
    3584           0 :           GEN q = gel(extendP,i);
    3585           0 :           if (typ(q) == t_FRAC) P = ZV_cba_extend(P, gel(q,2));
    3586             :         }
    3587             :       } else /*t_FRAC*/
    3588           7 :         P = ZV_cba_extend(P, gel(extendP,2));
    3589           7 :       if (ZV_equal(P, oldP))
    3590           0 :         pari_err(e_MISC, "rnfpseudobasis fails, try increasing B");
    3591           7 :       extendP = NULL;
    3592             :     }
    3593         413 :     Tabs = gel(rnfeq,1);
    3594         413 :     nfmaxord(&S, mkvec2(Tabs,P), 0);
    3595         413 :     B = RgXV_unscale(S.basis, S.unscale);
    3596         413 :     BdB = Q_remove_denom(B, &dB);
    3597         413 :     MB = RgXV_to_RgM(BdB, N); /* HNF */
    3598             : 
    3599         413 :     vU = cgetg(N+1, t_VEC);
    3600         413 :     vj = cgetg(N+1, t_VECSMALL);
    3601         413 :     gel(vU,1) = U = cgetg(m+1, t_MAT);
    3602         413 :     gel(U,1) = col_ei(N, 1);
    3603         413 :     A = dB? (dzknf? gdiv(dB,dzknf): dB): NULL;
    3604         413 :     if (A)
    3605             :     {
    3606         364 :       if (typ(A) != t_INT) { extendP = A; goto RESTART; }
    3607         357 :       if (equali1(A)) A = NULL;
    3608             :     }
    3609         784 :     for (j = 2; j <= m; j++)
    3610             :     {
    3611         378 :       GEN t = gel(zknf,j);
    3612         378 :       if (!RgX_is_ZX(t)) { extendP = t; goto RESTART; }
    3613         378 :       if (A) t = ZX_Z_mul(t, A);
    3614         378 :       gel(U,j) = hnf_solve(MB, RgX_to_RgC(t, N));
    3615             :     }
    3616        2450 :     for (i = 2; i <= N; i++)
    3617             :     {
    3618        2044 :       GEN b = gel(BdB,i);
    3619        2044 :       gel(vU,i) = U = cgetg(m+1, t_MAT);
    3620        2044 :       gel(U,1) = hnf_solve(MB, RgX_to_RgC(b, N));
    3621        4354 :       for (j = 2; j <= m; j++)
    3622             :       {
    3623        2310 :         GEN t = ZX_rem(ZX_mul(b, gel(zknf,j)), Tabs);
    3624        2310 :         if (dzknf)
    3625             :         {
    3626        1694 :           t = RgX_Rg_div(t, dzknf);
    3627        1694 :           if (!RgX_is_ZX(t)) { extendP = t; goto RESTART; }
    3628             :         }
    3629        2310 :         gel(U,j) = hnf_solve(MB, RgX_to_RgC(t, N));
    3630             :       }
    3631             :     }
    3632         406 :     vj[1] = 1; U = gel(vU,1); rU = m;
    3633         945 :     for (i = j = 2; i <= N; i++)
    3634             :     {
    3635         938 :       GEN V = shallowconcat(U, gel(vU,i));
    3636         938 :       if (ZM_rank(V) != rU)
    3637             :       {
    3638         938 :         U = V; rU += m; vj[j++] = i;
    3639         938 :         if (rU == N) break;
    3640             :       }
    3641             :     }
    3642         406 :     if (dB) for(;;)
    3643         420 :     {
    3644         777 :       GEN c = gen_1, H = ZM_hnfmodid(U, dB);
    3645         777 :       long ic = 0;
    3646        6650 :       for (i = 1; i <= N; i++)
    3647        5873 :         if (cmpii(gcoeff(H,i,i), c) > 0) { c = gcoeff(H,i,i); ic = i; }
    3648         777 :       if (!ic) break;
    3649         420 :       vj[j++] = ic;
    3650         420 :       U = shallowconcat(H, gel(vU, ic));
    3651             :     }
    3652         406 :     setlg(vj, j);
    3653         406 :     B = vecpermute(B, vj);
    3654             : 
    3655         406 :     l = lg(B);
    3656         406 :     A = cgetg(l,t_MAT);
    3657        2170 :     for (j = 1; j < l; j++)
    3658             :     {
    3659        1764 :       GEN t = eltabstorel_lift(rnfeq, gel(B,j));
    3660        1764 :       gel(A,j) = Rg_to_RgC(t, n);
    3661             :     }
    3662         406 :     A = RgM_to_nfM(nf, A);
    3663         406 :     A = Q_remove_denom(A, &dA);
    3664         406 :     if (!dA)
    3665             :     { /* order is maximal */
    3666          56 :       z = triv_order(n);
    3667          56 :       if (pf) *pf = gen_1;
    3668             :     }
    3669             :     else
    3670             :     {
    3671             :       GEN fi;
    3672             :       /* the first n columns of A are probably in HNF already */
    3673         350 :       A = shallowconcat(vecslice(A,n+1,lg(A)-1), vecslice(A,1,n));
    3674         350 :       A = mkvec2(A, const_vec(l-1,gen_1));
    3675         350 :       if (DEBUGLEVEL > 2) err_printf("rnfallbase: nfhnf in dim %ld\n", l-1);
    3676         350 :       z = nfhnfmod(nf, A, nfdetint(nf,A));
    3677         350 :       gel(z,2) = gdiv(gel(z,2), dA);
    3678         350 :       fi = idealprod(nf,gel(z,2));
    3679         350 :       D = idealmul(nf, D, idealsqr(nf, fi));
    3680         350 :       if (pf) *pf = idealinv(nf, fi);
    3681             :     }
    3682         406 :     if (RgM_isscalar(D,NULL)) D = gcoeff(D,1,1);
    3683         406 :     if (pDKP) *pDKP = S.dKP;
    3684         406 :     *pD = mkvec2(D, get_d(nf, disc)); return z;
    3685             :   }
    3686        2170 :   fa = idealfactor(nf, disc);
    3687        2170 :   P = gel(fa,1); l = lg(P); z = NULL;
    3688        2170 :   E = gel(fa,2);
    3689        2170 :   Pf = cgetg(l, t_COL);
    3690        2170 :   Ef = cgetg(l, t_COL);
    3691        6875 :   for (i = j = jf = 1; i < l; i++)
    3692             :   {
    3693        4705 :     GEN pr = gel(P,i);
    3694        4705 :     long e = itos(gel(E,i));
    3695        4705 :     if (e > 1)
    3696             :     {
    3697        3633 :       GEN vD = rnfmaxord(nf, pol, pr, e);
    3698        3633 :       if (vD)
    3699             :       {
    3700        2316 :         long ef = idealprodval(nf, gel(vD,2), pr);
    3701        2316 :         z = rnfjoinmodules(nf, z, vD);
    3702        2316 :         if (ef) { gel(Pf, jf) = pr; gel(Ef, jf++) = stoi(-ef); }
    3703        2316 :         e += 2 * ef;
    3704             :       }
    3705             :     }
    3706        4705 :     if (e) { gel(P, j) = pr; gel(E, j++) = stoi(e); }
    3707             :   }
    3708        2170 :   setlg(P,j);
    3709        2170 :   setlg(E,j);
    3710        2170 :   if (pDKP) *pDKP = prV_primes(P);
    3711        2170 :   if (pf)
    3712             :   {
    3713        2114 :     setlg(Pf, jf);
    3714        2114 :     setlg(Ef, jf); *pf = pr_factorback_scal(nf, mkmat2(Pf,Ef));
    3715             :   }
    3716        2170 :   *pD = mkvec2(pr_factorback_scal(nf,fa), get_d(nf, disc));
    3717        2170 :   return z? z: triv_order(degpol(pol));
    3718             : }
    3719             : 
    3720             : static GEN
    3721        1638 : RgX_to_algX(GEN nf, GEN x)
    3722        8743 : { pari_APPLY_pol_normalized(nf_to_scalar_or_alg(nf, gel(x,i))); }
    3723             : 
    3724             : GEN
    3725        1652 : nfX_to_monic(GEN nf, GEN T, GEN *pL)
    3726             : {
    3727             :   GEN lT, g, a;
    3728        1652 :   long i, l = lg(T);
    3729        1652 :   if (l == 2) return pol_0(varn(T));
    3730        1652 :   if (l == 3) return pol_1(varn(T));
    3731        1652 :   nf = checknf(nf);
    3732        1652 :   T = Q_primpart(RgX_to_nfX(nf, T));
    3733        1652 :   lT = leading_coeff(T); if (pL) *pL = lT;
    3734        1652 :   if (isint1(T)) return T;
    3735        1652 :   g = cgetg_copy(T, &l); g[1] = T[1]; a = lT;
    3736        1652 :   gel(g, l-1) = gen_1;
    3737        1652 :   gel(g, l-2) = gel(T,l-2);
    3738        1652 :   if (l == 4) { gel(g,l-2) = nf_to_scalar_or_alg(nf, gel(g,l-2)); return g; }
    3739        1638 :   if (typ(lT) == t_INT)
    3740             :   {
    3741        1624 :     gel(g, l-3) = gmul(a, gel(T,l-3));
    3742        3808 :     for (i = l-4; i > 1; i--) { a = mulii(a,lT); gel(g,i) = gmul(a, gel(T,i)); }
    3743             :   }
    3744             :   else
    3745             :   {
    3746          14 :     gel(g, l-3) = nfmul(nf, a, gel(T,l-3));
    3747          35 :     for (i = l-3; i > 1; i--)
    3748             :     {
    3749          21 :       a = nfmul(nf,a,lT);
    3750          21 :       gel(g,i) = nfmul(nf, a, gel(T,i));
    3751             :     }
    3752             :   }
    3753        1638 :   return RgX_to_algX(nf, g);
    3754             : }
    3755             : 
    3756             : GEN
    3757         854 : rnfdisc_factored(GEN nf, GEN pol, GEN *pd)
    3758             : {
    3759             :   long i, j, l;
    3760             :   GEN fa, E, P, disc, lim;
    3761             : 
    3762         854 :   pol = rnfdisc_get_T(nf, pol, &lim);
    3763         854 :   disc = nf_to_scalar_or_basis(nf, nfX_disc(nf, pol));
    3764         854 :   if (gequal0(disc))
    3765           0 :     pari_err_DOMAIN("rnfdisc","issquarefree(pol)","=",gen_0, pol);
    3766         854 :   pol = nfX_to_monic(nf, pol, NULL);
    3767         854 :   fa = idealfactor_partial(nf, disc, lim);
    3768         854 :   P = gel(fa,1); l = lg(P);
    3769         854 :   E = gel(fa,2);
    3770        2310 :   for (i = j = 1; i < l; i++)
    3771             :   {
    3772        1456 :     long e = itos(gel(E,i));
    3773        1456 :     GEN pr = gel(P,i);
    3774        1456 :     if (e > 1)
    3775             :     {
    3776        1183 :       GEN vD = rnfmaxord(nf, pol, pr, e);
    3777        1183 :       if (vD) e += 2*idealprodval(nf, gel(vD,2), pr);
    3778             :     }
    3779        1456 :     if (e) { gel(P, j) = pr; gel(E, j++) = stoi(e); }
    3780             :   }
    3781         854 :   if (pd) *pd = get_d(nf, disc);
    3782         854 :   setlg(P, j);
    3783         854 :   setlg(E, j); return fa;
    3784             : }
    3785             : GEN
    3786          77 : rnfdiscf(GEN nf, GEN pol)
    3787             : {
    3788          77 :   pari_sp av = avma;
    3789             :   GEN d, fa;
    3790          77 :   nf = checknf(nf); fa = rnfdisc_factored(nf, pol, &d);
    3791          77 :   return gerepilecopy(av, mkvec2(pr_factorback_scal(nf,fa), d));
    3792             : }
    3793             : 
    3794             : GEN
    3795          35 : gen_if_principal(GEN bnf, GEN x)
    3796             : {
    3797          35 :   pari_sp av = avma;
    3798          35 :   GEN z = bnfisprincipal0(bnf,x, nf_GEN_IF_PRINCIPAL | nf_FORCE);
    3799          35 :   return isintzero(z)? gc_NULL(av): z;
    3800             : }
    3801             : 
    3802             : /* given bnf and a HNF pseudo-basis of a proj. module, simplify the HNF as
    3803             :  * much as possible. The resulting matrix will be upper triangular but the
    3804             :  * diagonal coefficients will not be equal to 1. The ideals are integral and
    3805             :  * primitive. */
    3806             : GEN
    3807           0 : rnfsimplifybasis(GEN bnf, GEN M)
    3808             : {
    3809           0 :   pari_sp av = avma;
    3810             :   long i, l;
    3811             :   GEN y, Az, Iz, nf, A, I;
    3812             : 
    3813           0 :   bnf = checkbnf(bnf); nf = bnf_get_nf(bnf);
    3814           0 :   if (!check_ZKmodule_i(M)) pari_err_TYPE("rnfsimplifybasis",M);
    3815           0 :   A = gel(M,1);
    3816           0 :   I = gel(M,2); l = lg(I);
    3817           0 :   Az = cgetg(l, t_MAT);
    3818           0 :   Iz = cgetg(l, t_VEC); y = mkvec2(Az, Iz);
    3819           0 :   for (i = 1; i < l; i++)
    3820             :   {
    3821             :     GEN c, d;
    3822           0 :     if (ideal_is1(gel(I,i)))
    3823             :     {
    3824           0 :       gel(Iz,i) = gen_1;
    3825           0 :       gel(Az,i) = gel(A,i); continue;
    3826             :     }
    3827             : 
    3828           0 :     gel(Iz,i) = Q_primitive_part(gel(I,i), &c);
    3829           0 :     gel(Az,i) = c? RgC_Rg_mul(gel(A,i),c): gel(A,i);
    3830           0 :     if (c && ideal_is1(gel(Iz,i))) continue;
    3831             : 
    3832           0 :     d = gen_if_principal(bnf, gel(Iz,i));
    3833           0 :     if (d)
    3834             :     {
    3835           0 :       gel(Iz,i) = gen_1;
    3836           0 :       gel(Az,i) = nfC_nf_mul(nf, gel(Az,i), d);
    3837             :     }
    3838             :   }
    3839           0 :   return gerepilecopy(av, y);
    3840             : }
    3841             : 
    3842             : static GEN
    3843          63 : get_module(GEN nf, GEN O, const char *s)
    3844             : {
    3845          63 :   if (typ(O) == t_POL) return rnfpseudobasis(nf, O);
    3846          56 :   if (!check_ZKmodule_i(O)) pari_err_TYPE(s, O);
    3847          56 :   return shallowcopy(O);
    3848             : }
    3849             : 
    3850             : GEN
    3851          14 : rnfdet(GEN nf, GEN M)
    3852             : {
    3853          14 :   pari_sp av = avma;
    3854             :   GEN D;
    3855          14 :   nf = checknf(nf);
    3856          14 :   M = get_module(nf, M, "rnfdet");
    3857          14 :   D = idealmul(nf, nfM_det(nf, gel(M,1)), idealprod(nf, gel(M,2)));
    3858          14 :   return gerepileupto(av, D);
    3859             : }
    3860             : 
    3861             : /* Given two fractional ideals a and b, gives x in a, y in b, z in b^-1,
    3862             :    t in a^-1 such that xt-yz=1. In the present version, z is in Z. */
    3863             : static void
    3864          63 : nfidealdet1(GEN nf, GEN a, GEN b, GEN *px, GEN *py, GEN *pz, GEN *pt)
    3865             : {
    3866             :   GEN x, uv, y, da, db;
    3867             : 
    3868          63 :   a = idealinv(nf,a);
    3869          63 :   a = Q_remove_denom(a, &da);
    3870          63 :   b = Q_remove_denom(b, &db);
    3871          63 :   x = idealcoprime(nf,a,b);
    3872          63 :   uv = idealaddtoone(nf, idealmul(nf,x,a), b);
    3873          63 :   y = gel(uv,2);
    3874          63 :   if (da) x = gmul(x,da);
    3875          63 :   if (db) y = gdiv(y,db);
    3876          63 :   *px = x;
    3877          63 :   *py = y;
    3878          63 :   *pz = db ? negi(db): gen_m1;
    3879          63 :   *pt = nfdiv(nf, gel(uv,1), x);
    3880          63 : }
    3881             : 
    3882             : /* given a pseudo-basis of a proj. module in HNF [A,I] (or [A,I,D,d]), gives
    3883             :  * an n x n matrix (not HNF) of a pseudo-basis and an ideal vector
    3884             :  * [1,...,1,I] such that M ~ Z_K^(n-1) x I. Uses the approximation theorem.*/
    3885             : GEN
    3886          28 : rnfsteinitz(GEN nf, GEN M)
    3887             : {
    3888          28 :   pari_sp av = avma;
    3889             :   long i, n;
    3890             :   GEN A, I;
    3891             : 
    3892          28 :   nf = checknf(nf);
    3893          28 :   M = get_module(nf, M, "rnfsteinitz");
    3894          28 :   A = RgM_to_nfM(nf, gel(M,1));
    3895          28 :   I = leafcopy(gel(M,2)); n = lg(A)-1;
    3896         189 :   for (i = 1; i < n; i++)
    3897             :   {
    3898         161 :     GEN c1, c2, b, a = gel(I,i);
    3899         161 :     gel(I,i) = gen_1;
    3900         161 :     if (ideal_is1(a)) continue;
    3901             : 
    3902          63 :     c1 = gel(A,i);
    3903          63 :     c2 = gel(A,i+1);
    3904          63 :     b = gel(I,i+1);
    3905          63 :     if (ideal_is1(b))
    3906             :     {
    3907           0 :       gel(A,i) = c2;
    3908           0 :       gel(A,i+1) = gneg(c1);
    3909           0 :       gel(I,i+1) = a;
    3910             :     }
    3911             :     else
    3912             :     {
    3913          63 :       pari_sp av2 = avma;
    3914             :       GEN x, y, z, t, c;
    3915          63 :       nfidealdet1(nf,a,b, &x,&y,&z,&t);
    3916          63 :       x = RgC_add(nfC_nf_mul(nf, c1, x), nfC_nf_mul(nf, c2, y));
    3917          63 :       y = RgC_add(nfC_nf_mul(nf, c1, z), nfC_nf_mul(nf, c2, t));
    3918          63 :       gerepileall(av2, 2, &x,&y);
    3919          63 :       gel(A,i) = x;
    3920          63 :       gel(A,i+1) = y;
    3921          63 :       gel(I,i+1) = Q_primitive_part(idealmul(nf,a,b), &c);
    3922          63 :       if (c) gel(A,i+1) = nfC_nf_mul(nf, gel(A,i+1), c);
    3923             :     }
    3924             :   }
    3925          28 :   gel(M,1) = A;
    3926          28 :   gel(M,2) = I; return gerepilecopy(av, M);
    3927             : }
    3928             : 
    3929             : /* Given bnf and a proj. module (or a t_POL -> rnfpseudobasis), and outputs a
    3930             :  * basis if it is free, an n+1-generating set if it is not */
    3931             : GEN
    3932          21 : rnfbasis(GEN bnf, GEN M)
    3933             : {
    3934          21 :   pari_sp av = avma;
    3935             :   long j, n;
    3936             :   GEN nf, A, I, cl, col, a;
    3937             : 
    3938          21 :   bnf = checkbnf(bnf); nf = bnf_get_nf(bnf);
    3939          21 :   M = get_module(nf, M, "rnfbasis");
    3940          21 :   I = gel(M,2); n = lg(I)-1;
    3941          98 :   j = 1; while (j < n && ideal_is1(gel(I,j))) j++;
    3942          21 :   if (j < n) { M = rnfsteinitz(nf,M); I = gel(M,2); }
    3943          21 :   A = gel(M,1);
    3944          21 :   col= gel(A,n); A = vecslice(A, 1, n-1);
    3945          21 :   cl = gel(I,n);
    3946          21 :   a = gen_if_principal(bnf, cl);
    3947          21 :   if (!a)
    3948             :   {
    3949           7 :     GEN v = idealtwoelt(nf, cl);
    3950           7 :     A = vec_append(A, gmul(gel(v,1), col));
    3951           7 :     a = gel(v,2);
    3952             :   }
    3953          21 :   A = vec_append(A, nfC_nf_mul(nf, col, a));
    3954          21 :   return gerepilecopy(av, A);
    3955             : }
    3956             : 
    3957             : /* Given a Z_K-module M (or a polynomial => rnfpseudobasis) outputs a
    3958             :  * Z_K-basis in HNF if it exists, zero if not */
    3959             : GEN
    3960           7 : rnfhnfbasis(GEN bnf, GEN M)
    3961             : {
    3962           7 :   pari_sp av = avma;
    3963             :   long j, l;
    3964             :   GEN nf, A, I, a;
    3965             : 
    3966           7 :   bnf = checkbnf(bnf); nf = bnf_get_nf(bnf);
    3967           7 :   if (typ(M) == t_POL) M = rnfpseudobasis(nf, M);
    3968             :   else
    3969             :   {
    3970           7 :     if (typ(M) != t_VEC) pari_err_TYPE("rnfhnfbasis", M);
    3971           7 :     if (lg(M) == 5) M = mkvec2(gel(M,1), gel(M,2));
    3972           7 :     M = nfhnf(nf, M); /* in case M is not in HNF */
    3973             :   }
    3974           7 :   A = shallowcopy(gel(M,1));
    3975           7 :   I = gel(M,2); l = lg(A);
    3976          42 :   for (j = 1; j < l; j++)
    3977             :   {
    3978          35 :     if (ideal_is1(gel(I,j))) continue;
    3979          14 :     a = gen_if_principal(bnf, gel(I,j));
    3980          14 :     if (!a) return gc_const(av, gen_0);
    3981          14 :     gel(A,j) = nfC_nf_mul(nf, gel(A,j), a);
    3982             :   }
    3983           7 :   return gerepilecopy(av,A);
    3984             : }
    3985             : 
    3986             : long
    3987           7 : rnfisfree(GEN bnf, GEN M)
    3988             : {
    3989           7 :   pari_sp av = avma;
    3990             :   GEN nf, P, I;
    3991             :   long l, j;
    3992             : 
    3993           7 :   bnf = checkbnf(bnf);
    3994           7 :   if (is_pm1( bnf_get_no(bnf) )) return 1;
    3995           0 :   nf = bnf_get_nf(bnf);
    3996           0 :   M = get_module(nf, M, "rnfisfree");
    3997           0 :   I = gel(M,2); l = lg(I); P = NULL;
    3998           0 :   for (j = 1; j < l; j++)
    3999           0 :     if (!ideal_is1(gel(I,j))) P = P? idealmul(nf, P, gel(I,j)): gel(I,j);
    4000           0 :   return gc_long(av, P? gequal0( isprincipal(bnf,P) ): 1);
    4001             : }
    4002             : 
    4003             : /**********************************************************************/
    4004             : /**                                                                  **/
    4005             : /**                   COMPOSITUM OF TWO NUMBER FIELDS                **/
    4006             : /**                                                                  **/
    4007             : /**********************************************************************/
    4008             : static GEN
    4009       26523 : compositum_fix(GEN nf, GEN A)
    4010             : {
    4011             :   int ok;
    4012       26523 :   if (nf)
    4013             :   {
    4014         952 :     A = Q_primpart(liftpol_shallow(A)); RgX_check_ZXX(A,"polcompositum");
    4015         952 :     ok = nfissquarefree(nf,A);
    4016             :   }
    4017             :   else
    4018             :   {
    4019       25571 :     A = Q_primpart(A); RgX_check_ZX(A,"polcompositum");
    4020       25566 :     ok = ZX_is_squarefree(A);
    4021             :   }
    4022       26524 :   if (!ok) pari_err_DOMAIN("polcompositum","issquarefree(arg)","=",gen_0,A);
    4023       26517 :   return A;
    4024             : }
    4025             : #define next_lambda(a) (a>0 ? -a : 1-a)
    4026             : 
    4027             : static long
    4028         497 : nfcompositum_lambda(GEN nf, GEN A, GEN B, long lambda)
    4029             : {
    4030         497 :   pari_sp av = avma;
    4031             :   forprime_t S;
    4032         497 :   GEN T = nf_get_pol(nf);
    4033         497 :   long vT = varn(T);
    4034             :   ulong p;
    4035         497 :   init_modular_big(&S);
    4036         497 :   p = u_forprime_next(&S);
    4037             :   while (1)
    4038          42 :   {
    4039             :     GEN Hp, Tp, a;
    4040         539 :     if (DEBUGLEVEL>4) err_printf("Trying lambda = %ld\n", lambda);
    4041         539 :     a = ZXX_to_FlxX(RgX_rescale(A, stoi(-lambda)), p, vT);
    4042         539 :     Tp = ZX_to_Flx(T, p);
    4043         539 :     Hp = FlxqX_composedsum(a, ZXX_to_FlxX(B, p, vT), Tp, p);
    4044         539 :     if (!FlxqX_is_squarefree(Hp, Tp, p))
    4045          42 :       { lambda = next_lambda(lambda); continue; }
    4046         497 :     if (DEBUGLEVEL>4) err_printf("Final lambda = %ld\n", lambda);
    4047         497 :     return gc_long(av, lambda);
    4048             :   }
    4049             : }
    4050             : 
    4051             : /* modular version */
    4052             : GEN
    4053       13372 : nfcompositum(GEN nf, GEN A, GEN B, long flag)
    4054             : {
    4055       13372 :   pari_sp av = avma;
    4056             :   int same;
    4057             :   long v, k;
    4058             :   GEN C, D, LPRS;
    4059             : 
    4060       13372 :   if (typ(A)!=t_POL) pari_err_TYPE("polcompositum",A);
    4061       13372 :   if (typ(B)!=t_POL) pari_err_TYPE("polcompositum",B);
    4062       13372 :   if (degpol(A)<=0 || degpol(B)<=0) pari_err_CONSTPOL("polcompositum");
    4063       13372 :   v = varn(A);
    4064       13372 :   if (varn(B) != v) pari_err_VAR("polcompositum", A,B);
    4065       13372 :   if (nf)
    4066             :   {
    4067         539 :     nf = checknf(nf);
    4068         532 :     if (varncmp(v,nf_get_varn(nf))>=0) pari_err_PRIORITY("polcompositum", nf, ">=",  v);
    4069             :   }
    4070       13330 :   same = (A == B || RgX_equal(A,B));
    4071       13330 :   A = compositum_fix(nf,A);
    4072       13328 :   B = same ? A: compositum_fix(nf,B);
    4073             : 
    4074       13327 :   D = LPRS = NULL; /* -Wall */
    4075       13327 :   k = same? -1: 1;
    4076       13327 :   if (nf)
    4077             :   {
    4078         497 :     long v0 = fetch_var();
    4079         497 :     GEN q, T = nf_get_pol(nf);
    4080         497 :     A = liftpol_shallow(A);
    4081         497 :     B = liftpol_shallow(B);
    4082         497 :     k = nfcompositum_lambda(nf, A, B, k);
    4083         497 :     if (flag&1)
    4084             :     {
    4085             :       GEN H0, H1;
    4086         189 :       GEN chgvar = deg1pol_shallow(stoi(k),pol_x(v0),v);
    4087         189 :       GEN B1 = poleval(QXQX_to_mod_shallow(B, T), chgvar);
    4088         189 :       C = RgX_resultant_all(QXQX_to_mod_shallow(A, T), B1, &q);
    4089         189 :       C = gsubst(C,v0,pol_x(v));
    4090         189 :       C = lift_if_rational(C);
    4091         189 :       H0 = gsubst(gel(q,2),v0,pol_x(v));
    4092         189 :       H1 = gsubst(gel(q,3),v0,pol_x(v));
    4093         189 :       if (typ(H0) != t_POL) H0 = scalarpol_shallow(H0,v);
    4094         189 :       if (typ(H1) != t_POL) H1 = scalarpol_shallow(H1,v);
    4095         189 :       H0 = lift_if_rational(H0);
    4096         189 :       H1 = lift_if_rational(H1);
    4097         189 :       LPRS = mkvec2(H0,H1);
    4098             :     }
    4099             :     else
    4100             :     {
    4101         308 :       C = nf_direct_compositum(nf, RgX_rescale(A,stoi(-k)), B);
    4102         308 :       setvarn(C, v); C = QXQX_to_mod_shallow(C, T);
    4103             :     }
    4104         497 :     C = RgX_normalize(C);
    4105             :   }
    4106             :   else
    4107             :   {
    4108       12830 :     B = leafcopy(B); setvarn(B,fetch_var_higher());
    4109        3129 :     C = (flag&1)? ZX_ZXY_resultant_all(A, B, &k, &LPRS)
    4110       12829 :                 : ZX_compositum(A, B, &k);
    4111       12829 :     setvarn(C, v);
    4112             :   }
    4113             :   /* C = Res_Y (A(Y), B(X + kY)) guaranteed squarefree */
    4114       13326 :   if (flag & 2)
    4115       10232 :     C = mkvec(C);
    4116             :   else
    4117             :   {
    4118        3094 :     if (same)
    4119             :     {
    4120         105 :       D = RgX_rescale(A, stoi(1 - k));
    4121         105 :       if (nf) D = RgX_normalize(QXQX_to_mod_shallow(D, nf_get_pol(nf)));
    4122         105 :       C = RgX_div(C, D);
    4123         105 :       if (degpol(C) <= 0)
    4124           0 :         C = mkvec(D);
    4125             :       else
    4126         105 :         C = shallowconcat(nf? gel(nffactor(nf,C),1): ZX_DDF(C), D);
    4127             :     }
    4128             :     else
    4129        2989 :       C = nf? gel(nffactor(nf,C),1): ZX_DDF(C);
    4130             :   }
    4131       13325 :   gen_sort_inplace(C, (void*)(nf?&cmp_RgX: &cmpii), &gen_cmp_RgX, NULL);
    4132       13325 :   if (flag&1)
    4133             :   { /* a,b,c root of A,B,C = compositum, c = b - k a */
    4134        3318 :     long i, l = lg(C);
    4135        3318 :     GEN a, b, mH0 = RgX_neg(gel(LPRS,1)), H1 = gel(LPRS,2);
    4136        3318 :     setvarn(mH0,v);
    4137        3318 :     setvarn(H1,v);
    4138        6713 :     for (i=1; i<l; i++)
    4139             :     {
    4140        3395 :       GEN D = gel(C,i);
    4141        3395 :       a = RgXQ_mul(mH0, nf? RgXQ_inv(H1,D): QXQ_inv(H1,D), D);
    4142        3395 :       b = gadd(pol_x(v), gmulsg(k,a));
    4143        3395 :       if (degpol(D) == 1) b = RgX_rem(b,D);
    4144        3395 :       gel(C,i) = mkvec4(D, mkpolmod(a,D), mkpolmod(b,D), stoi(-k));
    4145             :     }
    4146             :   }
    4147       13325 :   (void)delete_var();
    4148       13325 :   settyp(C, t_VEC);
    4149       13325 :   if (flag&2) C = gel(C,1);
    4150       13325 :   return gerepilecopy(av, C);
    4151             : }
    4152             : GEN
    4153       12833 : polcompositum0(GEN A, GEN B, long flag)
    4154       12833 : { return nfcompositum(NULL,A,B,flag); }
    4155             : 
    4156             : GEN
    4157          91 : compositum(GEN pol1,GEN pol2) { return polcompositum0(pol1,pol2,0); }
    4158             : GEN
    4159        2877 : compositum2(GEN pol1,GEN pol2) { return polcompositum0(pol1,pol2,1); }

Generated by: LCOV version 1.16