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 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 - base1.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.8.0 lcov report (development 19352-1b11b25) Lines: 1362 1465 93.0 %
Date: 2016-08-25 06:11:27 Functions: 111 126 88.1 %
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. It is distributed in the hope that it will be useful, but WITHOUT
       8             : ANY WARRANTY WHATSOEVER.
       9             : 
      10             : Check the License for details. You should have received a copy of it, along
      11             : with the package; see the file 'COPYING'. If not, write to the Free Software
      12             : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      13             : 
      14             : /**************************************************************/
      15             : /*                                                            */
      16             : /*                        NUMBER FIELDS                       */
      17             : /*                                                            */
      18             : /**************************************************************/
      19             : #include "pari.h"
      20             : #include "paripriv.h"
      21             : 
      22             : int new_galois_format = 0;
      23             : 
      24             : int
      25      211778 : checkrnf_i(GEN rnf)
      26      211778 : { return (typ(rnf)==t_VEC && lg(rnf)==13); }
      27             : 
      28             : void
      29      208670 : checkrnf(GEN rnf)
      30      208670 : { if (!checkrnf_i(rnf)) pari_err_TYPE("checkrnf",rnf); }
      31             : 
      32             : GEN
      33      689421 : checkbnf_i(GEN X)
      34             : {
      35      689421 :   if (typ(X) == t_VEC)
      36      688980 :     switch (lg(X))
      37             :     {
      38      687433 :       case 11: return X;
      39        1008 :       case 7:  return checkbnf_i(bnr_get_bnf(X));
      40             :     }
      41         980 :   return NULL;
      42             : }
      43             : 
      44             : GEN
      45    13210250 : checknf_i(GEN X)
      46             : {
      47    13210250 :   if (typ(X)==t_VEC)
      48    13209802 :     switch(lg(X))
      49             :     {
      50    13005076 :       case 10: return X;
      51      198440 :       case 11: return checknf_i(bnf_get_nf(X));
      52        5341 :       case 7:  return checknf_i(bnr_get_bnf(X));
      53         175 :       case 3: if (typ(gel(X,2)) == t_POLMOD) return checknf_i(gel(X,1));
      54             :     }
      55        1386 :   return NULL;
      56             : }
      57             : 
      58             : GEN
      59      687258 : checkbnf(GEN x)
      60             : {
      61      687258 :   GEN bnf = checkbnf_i(x);
      62      687258 :   if (!bnf) pari_err_TYPE("checkbnf [please apply bnfinit()]",x);
      63      687258 :   return bnf;
      64             : }
      65             : 
      66             : GEN
      67    12483387 : checknf(GEN x)
      68             : {
      69    12483387 :   GEN nf = checknf_i(x);
      70    12483387 :   if (!nf) pari_err_TYPE("checknf [please apply nfinit()]",x);
      71    12483373 :   return nf;
      72             : }
      73             : 
      74             : void
      75      198084 : checkbnr(GEN bnr)
      76             : {
      77      198084 :   if (typ(bnr)!=t_VEC || lg(bnr)!=7)
      78           0 :     pari_err_TYPE("checkbnr [please apply bnrinit()]",bnr);
      79      198084 :   (void)checkbnf(bnr_get_bnf(bnr));
      80      198084 : }
      81             : 
      82             : void
      83           0 : checkbnrgen(GEN bnr)
      84             : {
      85           0 :   checkbnr(bnr);
      86           0 :   if (lg(bnr_get_clgp(bnr))<=3)
      87           0 :     pari_err_TYPE("checkbnrgen [apply bnrinit(,,1), not bnrinit()]",bnr);
      88           0 : }
      89             : 
      90             : void
      91           0 : checksqmat(GEN x, long N)
      92             : {
      93           0 :   if (typ(x)!=t_MAT) pari_err_TYPE("checksqmat",x);
      94           0 :   if (lg(x) == 1 || lgcols(x) != N+1) pari_err_DIM("checksqmat");
      95           0 : }
      96             : 
      97             : GEN
      98      206400 : checkbid_i(GEN bid)
      99             : {
     100             :   GEN f;
     101      206400 :   if (typ(bid)!=t_VEC || lg(bid)!=6 || typ(gel(bid,3)) != t_MAT) return NULL;
     102      200198 :   f = bid_get_mod(bid);
     103      200198 :   if (typ(f)!=t_VEC || lg(f)!=3) return NULL;
     104      200198 :   return bid;
     105             : }
     106             : void
     107      200198 : checkbid(GEN bid)
     108             : {
     109      200198 :   if (!checkbid_i(bid)) pari_err_TYPE("checkbid",bid);
     110      200191 : }
     111             : void
     112       11403 : checkabgrp(GEN v)
     113             : {
     114       11403 :   if (typ(v) == t_VEC) switch(lg(v))
     115             :   {
     116       11312 :     case 4: if (typ(gel(v,3)) != t_VEC) break;
     117       11403 :     case 3: if (typ(gel(v,2)) != t_VEC) break;
     118       11375 :             if (typ(gel(v,1)) != t_INT) break;
     119       22750 :             return;/*OK*/
     120           0 :     default: break;
     121             :   }
     122          28 :   pari_err_TYPE("checkabgrp",v);
     123             : }
     124             : 
     125             : GEN
     126      359058 : checknfelt_mod(GEN nf, GEN x, const char *s)
     127             : {
     128      359058 :   GEN T = gel(x,1), a = gel(x,2), Tnf = nf_get_pol(nf);
     129      359058 :   if (!RgX_equal_var(T, Tnf)) pari_err_MODULUS(s, T, Tnf);
     130      358988 :   return a;
     131             : }
     132             : 
     133             : void
     134        3234 : check_ZKmodule(GEN x, const char *s)
     135             : {
     136        3234 :   if (typ(x) != t_VEC || lg(x) < 3) pari_err_TYPE(s,x);
     137        3234 :   if (typ(gel(x,1)) != t_MAT) pari_err_TYPE(s,gel(x,1));
     138        3234 :   if (typ(gel(x,2)) != t_VEC) pari_err_TYPE(s,gel(x,2));
     139        3234 :   if (lg(gel(x,2)) != lgcols(x)) pari_err_DIM(s);
     140        3234 : }
     141             : 
     142             : static long
     143       99883 : typv6(GEN x)
     144             : {
     145       99883 :   if (typ(gel(x,1)) == t_VEC && lg(gel(x,3)) == 3)
     146             :   {
     147        1806 :     long t = typ(gel(x,3));
     148        1806 :     return (t == t_MAT || t == t_VEC)? typ_BID: typ_NULL;
     149             :   }
     150       98077 :   if (typ(gel(x,2)) == t_COL && typ(gel(x,3)) == t_INT) return typ_PRID;
     151         196 :   return typ_NULL;
     152             : }
     153             : 
     154             : GEN
     155       13048 : get_bnf(GEN x, long *t)
     156             : {
     157       13048 :   switch(typ(x))
     158             :   {
     159          56 :     case t_POL: *t = typ_POL;  return NULL;
     160          56 :     case t_QUAD: *t = typ_Q  ; return NULL;
     161             :     case t_VEC:
     162       12432 :       switch(lg(x))
     163             :       {
     164        4382 :         case 5: *t = typ_QUA; return NULL;
     165         322 :         case 6: *t = typv6(x); return NULL;
     166          77 :         case 7:  *t = typ_BNR;
     167          77 :           x = bnr_get_bnf(x); if (typ(x)!=t_VEC || lg(x)!=11) break;
     168          77 :           return x;
     169             :         case 9:
     170          63 :           x = gel(x,2);
     171          63 :           if (typ(x) == t_VEC && lg(x) == 4) *t = typ_GAL;
     172          63 :           return NULL;
     173         217 :         case 10: *t = typ_NF; return NULL;
     174         189 :         case 11: *t = typ_BNF; return x;
     175          56 :         case 13: *t = typ_RNF; return NULL;
     176         266 :         case 17: *t = typ_ELL; return NULL;
     177             :       }
     178        6860 :       break;
     179             :     case t_COL:
     180         112 :       if (get_prid(x)) { *t = typ_MODPR; return NULL; }
     181          56 :       break;
     182             :   }
     183        7308 :   *t = typ_NULL; return NULL;
     184             : }
     185             : 
     186             : GEN
     187      110929 : get_nf(GEN x, long *t)
     188             : {
     189      110929 :   switch(typ(x))
     190             :   {
     191         133 :     case t_POL : *t = typ_POL; return NULL;
     192         133 :     case t_QUAD: *t = typ_Q  ; return NULL;
     193             :     case t_VEC:
     194      108514 :       switch(lg(x))
     195             :       {
     196             :         case 3:
     197         133 :           if (typ(gel(x,2)) != t_POLMOD) break;
     198         133 :           return get_nf(gel(x,1),t);
     199         133 :         case 5: *t = typ_QUA; return NULL;
     200       98889 :         case 6: *t = typv6(x); return NULL;
     201         140 :         case 7: *t = typ_BNR;
     202         140 :           x = bnr_get_bnf(x); if (typ(x)!=t_VEC || lg(x)!=11) break;
     203         140 :           x = bnf_get_nf(x);  if (typ(x)!=t_VEC || lg(x)!=10) break;
     204         140 :           return x;
     205             :         case 9:
     206         238 :           x = gel(x,2);
     207         238 :           if (typ(x) == t_VEC && lg(x) == 4) *t = typ_GAL;
     208         238 :           return NULL;
     209         686 :         case 10: *t = typ_NF; return x;
     210        4802 :         case 11: *t = typ_BNF;
     211        4802 :           x = bnf_get_nf(x); if (typ(x)!=t_VEC || lg(x)!=10) break;
     212        4802 :           return x;
     213         336 :         case 13: *t = typ_RNF; return NULL;
     214        3024 :         case 17: *t = typ_ELL; return NULL;
     215             :       }
     216         133 :       break;
     217             :     case t_COL:
     218         266 :       if (get_prid(x)) { *t = typ_MODPR; return NULL; }
     219         133 :       break;
     220             :   }
     221        2149 :   *t = typ_NULL; return NULL;
     222             : }
     223             : 
     224             : long
     225       38318 : nftyp(GEN x)
     226             : {
     227       38318 :   switch(typ(x))
     228             :   {
     229          14 :     case t_POL : return typ_POL;
     230           7 :     case t_QUAD: return typ_Q;
     231             :     case t_VEC:
     232       38290 :       switch(lg(x))
     233             :       {
     234         161 :         case 13: return typ_RNF;
     235             :         case 10:
     236       36470 :           if (typ(gel(x,1))!=t_POL) break;
     237       36463 :           return typ_NF;
     238             :         case 11:
     239          56 :           x = bnf_get_nf(x); if (typ(x)!=t_VEC || lg(x)!=10) break;
     240          56 :           return typ_BNF;
     241             :         case 7:
     242         896 :           x = bnr_get_bnf(x); if (typ(x)!=t_VEC || lg(x)!=11) break;
     243         889 :           x = bnf_get_nf(x);  if (typ(x)!=t_VEC || lg(x)!=10) break;
     244         889 :           return typ_BNR;
     245             :         case 6:
     246         672 :           return typv6(x);
     247             :         case 9:
     248           7 :           x = gel(x,2);
     249           7 :           if (typ(x) == t_VEC && lg(x) == 4) return typ_GAL;
     250          14 :         case 17: return typ_ELL;
     251             :       }
     252             :   }
     253          42 :   return typ_NULL;
     254             : }
     255             : 
     256             : /*************************************************************************/
     257             : /**                                                                     **/
     258             : /**                           GALOIS GROUP                              **/
     259             : /**                                                                     **/
     260             : /*************************************************************************/
     261             : 
     262             : GEN
     263        3157 : tschirnhaus(GEN x)
     264             : {
     265        3157 :   pari_sp av = avma, av2;
     266        3157 :   long a, v = varn(x);
     267        3157 :   GEN u, y = cgetg(5,t_POL);
     268             : 
     269        3157 :   if (typ(x)!=t_POL) pari_err_TYPE("tschirnhaus",x);
     270        3157 :   if (lg(x) < 4) pari_err_CONSTPOL("tschirnhaus");
     271        3157 :   if (v) { u = leafcopy(x); setvarn(u,0); x=u; }
     272        3157 :   y[1] = evalsigne(1)|evalvarn(0);
     273             :   do
     274             :   {
     275        3283 :     a = random_bits(2); if (a==0) a  = 1; gel(y,4) = stoi(a);
     276        3283 :     a = random_bits(3); if (a>=4) a -= 8; gel(y,3) = stoi(a);
     277        3283 :     a = random_bits(3); if (a>=4) a -= 8; gel(y,2) = stoi(a);
     278        3283 :     u = RgXQ_charpoly(y,x,v); av2 = avma;
     279             :   }
     280        3283 :   while (degpol(RgX_gcd(u,RgX_deriv(u)))); /* while u not separable */
     281        3157 :   if (DEBUGLEVEL>1)
     282           0 :     err_printf("Tschirnhaus transform. New pol: %Ps",u);
     283        3157 :   avma=av2; return gerepileupto(av,u);
     284             : }
     285             : 
     286             : /* Assume pol in Z[X], monic of degree n. Find L in Z such that
     287             :  * POL = L^(-n) pol(L x) is monic in Z[X]. Return POL and set *ptk = L.
     288             :  * No GC. */
     289             : GEN
     290       12285 : ZX_Z_normalize(GEN pol, GEN *ptk)
     291             : {
     292       12285 :   long i,j, sk, n = degpol(pol); /* > 0 */
     293             :   GEN k, fa, P, E, a, POL;
     294             : 
     295       12285 :   a = pol + 2; k = gel(a,n-1); /* a[i] = coeff of degree i */
     296       46074 :   for (i = n-2; i >= 0; i--)
     297             :   {
     298       40831 :     k = gcdii(k, gel(a,i));
     299       40831 :     if (is_pm1(k)) { if (ptk) *ptk = gen_1; return pol; }
     300             :   }
     301        5243 :   sk = signe(k);
     302        5243 :   if (!sk) { if (ptk) *ptk = gen_1; return pol; /* monomial! */ }
     303        4263 :   fa = absZ_factor_limit(k, 0); k = gen_1;
     304        4263 :   P = gel(fa,1);
     305        4263 :   E = gel(fa,2);
     306        4263 :   POL = leafcopy(pol); a = POL+2;
     307        9744 :   for (i = lg(P)-1; i > 0; i--)
     308             :   {
     309        5481 :     GEN p = gel(P,i), pv, pvj;
     310        5481 :     long vmin = itos(gel(E,i));
     311             :     /* find v_p(k) = min floor( v_p(a[i]) / (n-i)) */
     312       38206 :     for (j=n-1; j>=0; j--)
     313             :     {
     314             :       long v;
     315       32725 :       if (!signe(gel(a,j))) continue;
     316       20769 :       v = Z_pval(gel(a,j), p) / (n - j);
     317       20769 :       if (v < vmin) vmin = v;
     318             :     }
     319        5481 :     if (!vmin) continue;
     320        1099 :     pvj = pv = powiu(p,vmin); k = mulii(k, pv);
     321             :     /* a[j] /= p^(v*(n-j)) */
     322        7931 :     for (j=n-1; j>=0; j--)
     323             :     {
     324        6832 :       if (j < n-1) pvj = mulii(pvj, pv);
     325        6832 :       gel(a,j) = diviiexact(gel(a,j), pvj);
     326             :     }
     327             :   }
     328        4263 :   if (ptk) *ptk = k; return POL;
     329             : }
     330             : 
     331             : /* Assume pol != 0 in Z[X]. Find C in Q, L in Z such that POL = C pol(x/L) monic
     332             :  * in Z[X]. Return POL and set *pL = L. Wasteful (but correct) if pol is not
     333             :  * primitive: better if caller used Q_primpart already. No GC. */
     334             : GEN
     335       12292 : ZX_primitive_to_monic(GEN pol, GEN *pL)
     336             : {
     337       12292 :   long i,j, n = degpol(pol);
     338       12292 :   GEN lc = leading_coeff(pol), L, fa, P, E, a, POL;
     339             : 
     340       12292 :   if (is_pm1(lc))
     341             :   {
     342       12033 :     if (pL) *pL = gen_1;
     343       12033 :     return signe(lc) < 0? ZX_neg(pol): pol;
     344             :   }
     345         259 :   if (signe(lc) < 0)
     346          35 :     POL = ZX_neg(pol);
     347             :   else
     348         224 :     POL = leafcopy(pol);
     349         259 :   a = POL+2; lc = gel(a,n);
     350         259 :   fa = Z_factor_limit(lc,0); L = gen_1;
     351         259 :   P = gel(fa,1);
     352         259 :   E = gel(fa,2);
     353         651 :   for (i = lg(P)-1; i > 0; i--)
     354             :   {
     355         392 :     GEN p = gel(P,i), pk, pku;
     356         392 :     long v, j0, e = itos(gel(E,i)), k = e/n, d = k*n - e;
     357             : 
     358         392 :     if (d < 0) { k++; d += n; }
     359             :     /* k = ceil(e[i] / n); find d, k such that  p^d pol(x / p^k) monic */
     360        1519 :     for (j=n-1; j>0; j--)
     361             :     {
     362        1127 :       if (!signe(gel(a,j))) continue;
     363        1015 :       v = Z_pval(gel(a,j), p);
     364        1015 :       while (v + d < k * j) { k++; d += n; }
     365             :     }
     366         392 :     pk = powiu(p,k); j0 = d/k;
     367         392 :     L = mulii(L, pk);
     368             : 
     369         392 :     pku = powiu(p,d - k*j0);
     370             :     /* a[j] *= p^(d - kj) */
     371        1617 :     for (j=j0; j>=0; j--)
     372             :     {
     373        1225 :       if (j < j0) pku = mulii(pku, pk);
     374        1225 :       gel(a,j) = mulii(gel(a,j), pku);
     375             :     }
     376         392 :     j0++;
     377         392 :     pku = powiu(p,k*j0 - d);
     378             :     /* a[j] /= p^(kj - d) */
     379        1078 :     for (j=j0; j<=n; j++)
     380             :     {
     381         686 :       if (j > j0) pku = mulii(pku, pk);
     382         686 :       gel(a,j) = diviiexact(gel(a,j), pku);
     383             :     }
     384             :   }
     385         259 :   if (pL) *pL = L;
     386         259 :   return POL;
     387             : }
     388             : /* Assume pol != 0 in Z[X]. Find C,L in Q such that POL = C pol(x/L)
     389             :  * monic in Z[X]. Return POL and set *pL = L.
     390             :  * Wasteful (but correct) if pol is not primitive: better if caller used
     391             :  * Q_primpart already. No GC. */
     392             : GEN
     393       12033 : ZX_Q_normalize(GEN pol, GEN *pL)
     394             : {
     395       12033 :   GEN lc, POL = ZX_primitive_to_monic(pol, &lc);
     396       12033 :   POL = ZX_Z_normalize(POL, pL);
     397       12033 :   if (pL) *pL = gdiv(lc, *pL);
     398       12033 :   return POL;
     399             : }
     400             : /* pol != 0 in Z[x], returns a monic polynomial POL in Z[x] generating the
     401             :  * same field: there exist C in Q, L in Z such that POL(x) = C pol(x/L).
     402             :  * Set *L = NULL if L = 1, and to L otherwise. No garbage collecting. */
     403             : GEN
     404           0 : ZX_to_monic(GEN pol, GEN *L)
     405             : {
     406           0 :   long n = lg(pol)-1;
     407           0 :   GEN lc = gel(pol,n);
     408           0 :   if (is_pm1(lc)) { *L = gen_1; return signe(lc) > 0? pol: ZX_neg(pol); }
     409           0 :   return ZX_primitive_to_monic(Q_primpart(pol), L);
     410             : }
     411             : 
     412             : /* Evaluate pol in s using nfelt arithmetic and Horner rule */
     413             : GEN
     414       11417 : nfpoleval(GEN nf, GEN pol, GEN s)
     415             : {
     416       11417 :   pari_sp av=avma;
     417       11417 :   long i=lg(pol)-1;
     418             :   GEN res;
     419       11417 :   if (i==1) return gen_0;
     420       11417 :   res = nf_to_scalar_or_basis(nf, gel(pol,i));
     421       28609 :   for (i-- ; i>=2; i--)
     422       17192 :     res = nfadd(nf, nfmul(nf, s, res), gel(pol,i));
     423       11417 :   return gerepileupto(av, res);
     424             : }
     425             : 
     426             : static GEN
     427       19824 : QX_table_nfpoleval(GEN nf, GEN pol, GEN m)
     428             : {
     429       19824 :   pari_sp av = avma;
     430       19824 :   long i = lg(pol)-1;
     431             :   GEN res, den;
     432       19824 :   if (i==1) return gen_0;
     433       19824 :   pol = Q_remove_denom(pol, &den);
     434       19824 :   res = scalarcol_shallow(gel(pol,i), nf_get_degree(nf));
     435      106799 :   for (i-- ; i>=2; i--)
     436       86975 :     res = ZC_Z_add(ZM_ZC_mul(m, res), gel(pol,i));
     437       19824 :   if (den) res = RgC_Rg_div(res, den);
     438       19824 :   return gerepileupto(av, res);
     439             : }
     440             : 
     441             : GEN
     442        1456 : FpX_FpC_nfpoleval(GEN nf, GEN pol, GEN a, GEN p)
     443             : {
     444        1456 :   pari_sp av=avma;
     445        1456 :   long i=lg(pol)-1, n=nf_get_degree(nf);
     446             :   GEN res, Ma;
     447        1456 :   if (i==1) return zerocol(n);
     448        1456 :   Ma = FpM_red(zk_multable(nf, a), p);
     449        1456 :   res = scalarcol(gel(pol,i),n);
     450        3612 :   for (i-- ; i>=2; i--)
     451             :   {
     452        2156 :     res = FpM_FpC_mul(Ma, res, p);
     453        2156 :     gel(res,1) = Fp_add(gel(res,1), gel(pol,i), p);
     454             :   }
     455        1456 :   return gerepileupto(av, res);
     456             : }
     457             : 
     458             : /* compute s(x), not stack clean */
     459             : static GEN
     460        3738 : table_galoisapply(GEN nf, GEN m, GEN x)
     461             : {
     462        3738 :   x = nf_to_scalar_or_alg(nf, x);
     463        3738 :   if (typ(x) != t_POL) return scalarcol(x, nf_get_degree(nf));
     464        2807 :   return QX_table_nfpoleval(nf, x, m);
     465             : }
     466             : 
     467             : /* compute s(x), not stack clean */
     468             : static GEN
     469       10150 : ZC_galoisapply(GEN nf, GEN s, GEN x)
     470             : {
     471       10150 :   x = nf_to_scalar_or_alg(nf, x);
     472       10150 :   if (typ(x) != t_POL) return scalarcol(x, nf_get_degree(nf));
     473       10087 :   return QX_table_nfpoleval(nf, x, zk_multable(nf, s));
     474             : }
     475             : 
     476             : static GEN
     477        1456 : QX_galoisapplymod(GEN nf, GEN pol, GEN S, GEN p)
     478             : {
     479        1456 :   GEN den, P = Q_remove_denom(pol,&den);
     480             :   GEN pe, pe1, denpe, R;
     481        1456 :   if (den)
     482             :   {
     483          98 :     ulong e = Z_pval(den, p);
     484          98 :     pe = powiu(p, e); pe1 = mulii(pe, p);
     485          98 :     denpe = Fp_inv(diviiexact(den, pe), pe1);
     486             :   } else {
     487        1358 :     pe = gen_1; pe1 = p; denpe = gen_1;
     488             :   }
     489        1456 :   R = FpX_FpC_nfpoleval(nf, FpX_red(P, pe1), FpC_red(S, pe1), pe1);
     490        1456 :   return gdivexact(FpC_Fp_mul(R, denpe, pe1), pe);
     491             : }
     492             : 
     493             : static GEN
     494           7 : pr_galoisapply(GEN nf, GEN pr, GEN aut)
     495             : {
     496             :   GEN p, t, u;
     497           7 :   if (typ(pr_get_tau(pr)) == t_INT) return pr; /* inert */
     498           7 :   p = pr_get_p(pr);
     499           7 :   u = QX_galoisapplymod(nf, coltoliftalg(nf, pr_get_gen(pr)), aut, p);
     500           7 :   t = FpM_deplin(zk_multable(nf, u), p);
     501           7 :   t = zk_scalar_or_multable(nf, t);
     502           7 :   return mkvec5(p, u, gel(pr,3), gel(pr,4), t);
     503             : }
     504             : 
     505             : static GEN
     506           7 : vecgaloisapply(GEN nf, GEN aut, GEN v)
     507             : {
     508             :   long i, l;
     509           7 :   GEN V = cgetg_copy(v, &l);
     510           7 :   for (i = 1; i < l; i++) gel(V,i) = galoisapply(nf, aut, gel(v,i));
     511           7 :   return V;
     512             : }
     513             : 
     514             : /* x: famat or standard algebraic number, aut automorphism in ZC form
     515             :  * simplified from general galoisapply */
     516             : static GEN
     517          49 : elt_galoisapply(GEN nf, GEN aut, GEN x)
     518             : {
     519          49 :   pari_sp av = avma;
     520          49 :   switch(typ(x))
     521             :   {
     522           7 :     case t_INT:  return icopy(x);
     523           7 :     case t_FRAC: return gcopy(x);
     524           7 :     case t_POLMOD: x = gel(x,2); /* fall through */
     525             :     case t_POL: {
     526          14 :       GEN y = basistoalg(nf, ZC_galoisapply(nf, aut, x));
     527          14 :       return gerepileupto(av,y);
     528             :     }
     529             :     case t_COL:
     530           7 :       return gerepileupto(av, ZC_galoisapply(nf, aut, x));
     531             :     case t_MAT:
     532          14 :       switch(lg(x)) {
     533           7 :         case 1: return cgetg(1, t_MAT);
     534           7 :         case 3: retmkmat2(vecgaloisapply(nf,aut,gel(x,1)), ZC_copy(gel(x,2)));
     535             :       }
     536             :   }
     537           0 :   pari_err_TYPE("galoisapply",x);
     538           0 :   return NULL; /* not reached */
     539             : }
     540             : 
     541             : GEN
     542        5117 : galoisapply(GEN nf, GEN aut, GEN x)
     543             : {
     544        5117 :   pari_sp av = avma;
     545             :   long lx, j;
     546             :   GEN y;
     547             : 
     548        5117 :   nf = checknf(nf);
     549        5117 :   switch(typ(x))
     550             :   {
     551          70 :     case t_INT:  return icopy(x);
     552           7 :     case t_FRAC: return gcopy(x);
     553             : 
     554          35 :     case t_POLMOD: x = gel(x,2); /* fall through */
     555             :     case t_POL:
     556         448 :       aut = algtobasis(nf, aut);
     557         448 :       y = basistoalg(nf, ZC_galoisapply(nf, aut, x));
     558         448 :       return gerepileupto(av,y);
     559             : 
     560             :     case t_VEC:
     561          56 :       aut = algtobasis(nf, aut);
     562          56 :       switch(lg(x))
     563             :       {
     564           7 :         case 6: return gerepilecopy(av, pr_galoisapply(nf, x, aut));
     565          49 :         case 3: y = cgetg(3,t_VEC);
     566          49 :           gel(y,1) = galoisapply(nf, aut, gel(x,1));
     567          49 :           gel(y,2) = elt_galoisapply(nf, aut, gel(x,2));
     568          49 :           return gerepileupto(av, y);
     569             :       }
     570           0 :       break;
     571             : 
     572             :     case t_COL:
     573        3605 :       aut = algtobasis(nf, aut);
     574        3605 :       return gerepileupto(av, ZC_galoisapply(nf, aut, x));
     575             : 
     576             :     case t_MAT: /* ideal */
     577         931 :       lx = lg(x); if (lx==1) return cgetg(1,t_MAT);
     578         931 :       if (nbrows(x) != nf_get_degree(nf)) break;
     579         931 :       aut = zk_multable(nf, algtobasis(nf, aut));
     580         931 :       y = cgetg(lx,t_MAT);
     581         931 :       for (j=1; j<lx; j++) gel(y,j) = table_galoisapply(nf, aut, gel(x,j));
     582         931 :       return gerepileupto(av, idealhnf_shallow(nf,y));
     583             :   }
     584           0 :   pari_err_TYPE("galoisapply",x);
     585           0 :   return NULL; /* not reached */
     586             : }
     587             : 
     588             : GEN
     589        1939 : nfgaloismatrix(GEN nf, GEN s)
     590             : {
     591             :   GEN zk, M, m;
     592             :   long k, l;
     593        1939 :   nf = checknf(nf);
     594        1939 :   zk = nf_get_zk(nf);
     595        1939 :   if (typ(s) != t_COL) s = algtobasis(nf, s); /* left on stack for efficiency */
     596        1939 :   m = zk_multable(nf, s);
     597        1939 :   l = lg(s); M = cgetg(l, t_MAT);
     598        1939 :   gel(M, 1) = col_ei(l-1, 1); /* s(1) = 1 */
     599        8869 :   for (k = 2; k < l; k++)
     600        6930 :     gel(M, k) = QX_table_nfpoleval(nf, gel(zk, k), m);
     601        1939 :   return M;
     602             : }
     603             : 
     604             : static GEN
     605        3017 : idealquasifrob(GEN nf, GEN gal, GEN grp, GEN pr, GEN subg, GEN *S, GEN aut)
     606             : {
     607        3017 :   pari_sp av = avma;
     608        3017 :   long i, n = nf_get_degree(nf), f = pr_get_f(pr);
     609        3017 :   GEN pi = pr_get_gen(pr);
     610       15274 :   for (i=1; i<=n; i++)
     611             :   {
     612       15274 :     GEN g = gel(grp,i);
     613       15274 :     if ((!subg && perm_order(g)==f)
     614        9478 :       || (subg && perm_relorder(g, subg)==f))
     615             :     {
     616        5824 :       *S = aut ? gel(aut, i): poltobasis(nf, galoispermtopol(gal, g));
     617        5824 :       if (ZC_prdvd(nf, ZC_galoisapply(nf, *S, pi), pr)) return g;
     618        2807 :       avma = av;
     619             :     }
     620             :   }
     621           0 :   pari_err_BUG("idealquasifrob [Frobenius not found]");
     622           0 :   return NULL; /*NOT REACHED*/
     623             : }
     624             : 
     625             : GEN
     626          14 : nfgaloispermtobasis(GEN nf, GEN gal)
     627             : {
     628          14 :   GEN grp = gal_get_group(gal);
     629          14 :   long i, n = lg(grp)-1;
     630          14 :   GEN aut = cgetg(n+1, t_VEC);
     631         126 :   for(i=1; i<=n; i++)
     632         112 :     gel(aut, i) = poltobasis(nf, galoispermtopol(gal, gel(grp, i)));
     633          14 :   return aut;
     634             : }
     635             : 
     636             : static void
     637         182 : gal_check_pol(const char *f, GEN x, GEN y)
     638         182 : { if (!RgX_equal_var(x,y)) pari_err_MODULUS(f,x,y); }
     639             : 
     640             : GEN
     641        3024 : idealfrobenius_aut(GEN nf, GEN gal, GEN pr, GEN aut)
     642             : {
     643        3024 :   pari_sp av = avma;
     644        3024 :   GEN S=NULL, g=NULL; /*-Wall*/
     645             :   GEN T, p, a, b, modpr;
     646             :   long f, n, s;
     647        3024 :   f = pr_get_f(pr); n = nf_get_degree(nf);
     648        3024 :   if (f==1) { avma = av; return identity_perm(n); }
     649        2933 :   g = idealquasifrob(nf, gal, gal_get_group(gal), pr, NULL, &S, aut);
     650        2933 :   if (f==2) return gerepileupto(av, g);
     651        1400 :   modpr = zk_to_Fq_init(nf,&pr,&T,&p);
     652        1400 :   a = pol_x(nf_get_varn(nf));
     653        1400 :   b = nf_to_Fq(nf, QX_galoisapplymod(nf, modpr_genFq(modpr), S, p), modpr);
     654        3003 :   for (s = 1; s < f-1; s++)
     655             :   {
     656        2709 :     a = Fq_pow(a, p, T, p);
     657        2709 :     if (ZX_equal(a, b)) break;
     658             :   }
     659        1400 :   g = perm_pow(g, Fl_inv(s, f));
     660        1400 :   return gerepileupto(av, g);
     661             : }
     662             : 
     663             : GEN
     664          63 : idealfrobenius(GEN nf, GEN gal, GEN pr)
     665             : {
     666          63 :   nf = checknf(nf);
     667          63 :   checkgal(gal);
     668          63 :   checkprid(pr);
     669          63 :   gal_check_pol("idealfrobenius",nf_get_pol(nf),gal_get_pol(gal));
     670          63 :   if (pr_get_e(pr)>1) pari_err_DOMAIN("idealfrobenius","pr.e", ">", gen_1,pr);
     671          56 :   return idealfrobenius_aut(nf, gal, pr, NULL);
     672             : }
     673             : 
     674             : GEN
     675          14 : idealramfrobenius(GEN nf, GEN gal, GEN pr, GEN ram)
     676             : {
     677          14 :   pari_sp av = avma;
     678          14 :   GEN S=NULL, g=NULL; /*-Wall*/
     679             :   GEN T, p, a, b, modpr;
     680             :   GEN isog, deco;
     681             :   long f, n, s;
     682          14 :   f = pr_get_f(pr); n = nf_get_degree(nf);
     683          14 :   if (f==1) { avma = av; return identity_perm(n); }
     684           0 :   modpr = zk_to_Fq_init(nf,&pr,&T,&p);
     685           0 :   deco = group_elts(gel(ram,1), nf_get_degree(nf));
     686           0 :   isog = group_set(gel(ram,2),  nf_get_degree(nf));
     687           0 :   g = idealquasifrob(nf, gal, deco, pr, isog, &S, NULL);
     688           0 :   a = pol_x(nf_get_varn(nf));
     689           0 :   b = nf_to_Fq(nf, QX_galoisapplymod(nf, modpr_genFq(modpr), S, p), modpr);
     690           0 :   for (s=0; !ZX_equal(a, b); s++)
     691           0 :     a = Fq_pow(a, p, T, p);
     692           0 :   g = perm_pow(g, Fl_inv(s, f));
     693           0 :   return gerepileupto(av, g);
     694             : }
     695             : 
     696             : static GEN
     697          42 : idealinertiagroup(GEN nf, GEN gal, GEN pr)
     698             : {
     699          42 :   long i, n = nf_get_degree(nf);
     700          42 :   GEN p, T, modpr = zk_to_Fq_init(nf,&pr,&T,&p);
     701          42 :   GEN b = modpr_genFq(modpr);
     702          42 :   long e = pr_get_e(pr), coprime = cgcd(e, pr_get_f(pr)) == 1;
     703          42 :   GEN grp = gal_get_group(gal), pi = pr_get_gen(pr);
     704          42 :   pari_sp ltop = avma;
     705         322 :   for (i=1; i<=n; i++)
     706             :   {
     707         322 :     GEN iso = gel(grp,i);
     708         322 :     if (perm_order(iso) == e)
     709             :     {
     710          98 :       GEN S = poltobasis(nf, galoispermtopol(gal, iso));
     711          98 :       if (ZC_prdvd(nf, ZC_galoisapply(nf, S, pi), pr)
     712          42 :           && (coprime || gequalX(nf_to_Fq(nf, galoisapply(nf,S,b), modpr))))
     713          42 :           return iso;
     714          56 :       avma = ltop;
     715             :     }
     716             :   }
     717           0 :   pari_err_BUG("idealinertiagroup [no isotropic element]");
     718           0 :   return NULL;
     719             : }
     720             : 
     721             : static GEN
     722         105 : idealramgroupstame(GEN nf, GEN gal, GEN pr)
     723             : {
     724         105 :   pari_sp av = avma;
     725             :   GEN iso, frob, giso, isog, S, res;
     726         105 :   long e = pr_get_e(pr), f = pr_get_f(pr);
     727         105 :   if (e == 1)
     728             :   {
     729          63 :     if (f==1)
     730           0 :       return cgetg(1,t_VEC);
     731          63 :     frob = idealquasifrob(nf, gal, gal_get_group(gal), pr, NULL, &S, NULL);
     732          63 :     avma = av;
     733          63 :     res = cgetg(2, t_VEC);
     734          63 :     gel(res, 1) = cyclicgroup(frob, f);
     735          63 :     return res;
     736             :   }
     737          42 :   res = cgetg(3, t_VEC);
     738          42 :   av = avma;
     739          42 :   iso = idealinertiagroup(nf, gal, pr);
     740          42 :   avma = av;
     741          42 :   giso = cyclicgroup(iso, e);
     742          42 :   gel(res, 2) = giso;
     743          42 :   if (f==1)
     744             :   {
     745          21 :     gel(res, 1) = giso;
     746          21 :     return res;
     747             :   }
     748          21 :   av = avma;
     749          21 :   isog = group_set(giso, nf_get_degree(nf));
     750          21 :   frob = idealquasifrob(nf, gal, gal_get_group(gal), pr, isog, &S, NULL);
     751          21 :   avma = av;
     752          21 :   gel(res, 1) = dicyclicgroup(iso,frob,e,f);
     753          21 :   return res;
     754             : }
     755             : 
     756             : static GEN
     757          14 : idealramgroupindex(GEN nf, GEN gal, GEN pr)
     758             : {
     759          14 :   pari_sp av = avma;
     760             :   GEN p, T, g, idx, modpr;
     761             :   long i, e, f, n;
     762             :   ulong nt,rorder;
     763          14 :   GEN grp = vecvecsmall_sort(gal_get_group(gal));
     764          14 :   e = pr_get_e(pr); f = pr_get_f(pr); n = nf_get_degree(nf);
     765          14 :   modpr = zk_to_Fq_init(nf,&pr,&T,&p);
     766          14 :   (void) u_pvalrem(n,p,&nt);
     767          14 :   rorder = e*f*(n/nt);
     768          14 :   idx = const_vecsmall(n,-1);
     769          14 :   g = modpr_genFq(modpr);
     770         266 :   for (i=2; i<=n; i++)
     771             :   {
     772             :     GEN iso;
     773             :     long o;
     774         252 :     if (idx[i]>=0) continue;
     775         252 :     iso = gel(grp,i); o = perm_order(iso);
     776         252 :     if (rorder%o == 0)
     777             :     {
     778         154 :       GEN piso = iso;
     779         154 :       GEN S = poltobasis(nf, galoispermtopol(gal, iso));
     780         154 :       GEN pi = pr_get_gen(pr);
     781         154 :       GEN spi = ZC_galoisapply(nf, S, pi);
     782             :       long j;
     783         154 :       idx[i] = idealval(nf, gsub(spi,pi), pr);
     784         154 :       if (idx[i] >=1)
     785             :       {
     786          56 :         if (f>1)
     787             :         {
     788          49 :           GEN b = nf_to_Fq(nf, QX_galoisapplymod(nf, g, S, p), modpr);
     789          49 :           if (!gequalX(b)) idx[i] = 0;
     790             :         }
     791             :       }
     792          98 :       else idx[i] = -1;
     793         154 :       for(j=2;j<o;j++)
     794             :       {
     795           0 :         piso = perm_mul(piso,iso);
     796           0 :         if(cgcd(j,o)==1) idx[piso[1]] = idx[i];
     797             :       }
     798             :     }
     799             :   }
     800          14 :   return gerepileuptoleaf(av, idx);
     801             : }
     802             : 
     803             : GEN
     804         119 : idealramgroups(GEN nf, GEN gal, GEN pr)
     805             : {
     806         119 :   pari_sp av = avma;
     807             :   GEN tbl, idx, res, set, sub;
     808             :   long i, j, e, n, maxm, p;
     809             :   ulong et;
     810         119 :   nf = checknf(nf);
     811         119 :   checkgal(gal);
     812         119 :   checkprid(pr);
     813         119 :   gal_check_pol("idealramgroups",nf_get_pol(nf),gal_get_pol(gal));
     814         119 :   e = pr_get_e(pr); n = nf_get_degree(nf);
     815         119 :   p = itos(pr_get_p(pr));
     816         119 :   if (e%p) return idealramgroupstame(nf, gal, pr);
     817          14 :   (void) u_lvalrem(e,p,&et);
     818          14 :   idx = idealramgroupindex(nf, gal, pr);
     819          14 :   sub = group_subgroups(galois_group(gal));
     820          14 :   tbl = subgroups_tableset(sub, n);
     821          14 :   maxm = vecsmall_max(idx)+1;
     822          14 :   res = cgetg(maxm+1,t_VEC);
     823          14 :   set = zero_F2v(n); F2v_set(set,1);
     824          77 :   for(i=maxm; i>0; i--)
     825             :   {
     826        1183 :     for(j=1;j<=n;j++)
     827        1120 :       if (idx[j]==i-1)
     828          56 :         F2v_set(set,j);
     829          63 :     gel(res,i) = gel(sub, tableset_find_index(tbl, set));
     830             :   }
     831          14 :   return gerepilecopy(av, res);
     832             : }
     833             : 
     834             : /* x = relative polynomial nf = absolute nf, bnf = absolute bnf */
     835             : GEN
     836         112 : get_bnfpol(GEN x, GEN *bnf, GEN *nf)
     837             : {
     838         112 :   *bnf = checkbnf_i(x);
     839         112 :   *nf  = checknf_i(x);
     840         112 :   if (*nf) x = nf_get_pol(*nf);
     841         112 :   if (typ(x) != t_POL) pari_err_TYPE("get_bnfpol",x);
     842         112 :   return x;
     843             : }
     844             : 
     845             : GEN
     846       15137 : get_nfpol(GEN x, GEN *nf)
     847             : {
     848       15137 :   if (typ(x) == t_POL) { *nf = NULL; return x; }
     849        9698 :   *nf = checknf(x); return nf_get_pol(*nf);
     850             : }
     851             : 
     852             : /* is isomorphism / inclusion (a \subset b) compatible with what we know about
     853             :  * basic invariants ? (degree, signature, discriminant) */
     854             : static int
     855          49 : tests_OK(GEN a, GEN nfa, GEN b, GEN nfb, long fliso)
     856             : {
     857             :   GEN da, db, fa, P, E, U;
     858          49 :   long i, nP, m = degpol(a), n = degpol(b), q = m / n; /* relative degree */
     859             : 
     860          49 :   if (m <= 0) pari_err_IRREDPOL("nfisincl",a);
     861          49 :   if (n <= 0) pari_err_IRREDPOL("nfisincl",b);
     862          49 :   if (fliso) { if (n != m) return 0; } else { if (n % m) return 0; }
     863          49 :   if (m == 1) return 1;
     864             : 
     865          42 :   if (nfa && nfb) /* both nf structures available */
     866             :   {
     867           0 :     long r1a = nf_get_r1(nfa), r1b = nf_get_r1(nfb) ;
     868           0 :     if (fliso)
     869           0 :       return (r1a == r1b && equalii(nf_get_disc(nfa), nf_get_disc(nfb)));
     870             :     else
     871           0 :       return (r1b <= r1a * q &&
     872           0 :               dvdii(nf_get_disc(nfb), powiu(nf_get_disc(nfa), q)));
     873             :   }
     874          42 :   da = nfa? nf_get_disc(nfa): ZX_disc(a);
     875          42 :   if (!signe(da)) pari_err_IRREDPOL("nfisincl",a);
     876          35 :   db = nfb? nf_get_disc(nfb): ZX_disc(b);
     877          35 :   if (!signe(db)) pari_err_IRREDPOL("nfisincl",a);
     878          35 :   if (fliso) return issquare(gdiv(da,db));
     879             : 
     880          21 :   if (odd(q) && signe(da) != signe(db)) return 0;
     881          21 :   fa = absZ_factor_limit(da, 0);
     882          21 :   P = gel(fa,1);
     883          21 :   E = gel(fa,2); nP = lg(P) - 1;
     884          77 :   for (i=1; i<nP; i++)
     885          56 :     if (mod2(gel(E,i)) && !dvdii(db, powiu(gel(P,i),q))) return 0;
     886          21 :   U = gel(P,nP);
     887          21 :   if (mod2(gel(E,i)) && expi(U) < 150)
     888             :   { /* "unfactored" cofactor is small, finish */
     889           0 :     if (abscmpiu(U, maxprime()) > 0)
     890             :     {
     891           0 :       fa = Z_factor(U);
     892           0 :       P = gel(fa,1);
     893           0 :       E = gel(fa,2);
     894             :     }
     895             :     else
     896             :     {
     897           0 :       P = mkvec(U);
     898           0 :       E = mkvec(gen_1);
     899             :     }
     900           0 :     nP = lg(P) - 1;
     901           0 :     for (i=1; i<=nP; i++)
     902           0 :       if (mod2(gel(E,i)) && !dvdii(db, powiu(gel(P,i),q))) return 0;
     903             :   }
     904          21 :   return 1;
     905             : }
     906             : 
     907             : /* if fliso test for isomorphism, for inclusion otherwise. */
     908             : static GEN
     909          49 : nfiso0(GEN a, GEN b, long fliso)
     910             : {
     911          49 :   pari_sp av = avma;
     912             :   long i, vb, lx;
     913             :   GEN nfa, nfb, y, la, lb;
     914             :   int newvar;
     915             : 
     916          49 :   a = get_nfpol(a, &nfa);
     917          49 :   b = get_nfpol(b, &nfb);
     918          49 :   if (!nfa) { a = Q_primpart(a); RgX_check_ZX(a, "nsiso0"); }
     919          49 :   if (!nfb) { b = Q_primpart(b); RgX_check_ZX(b, "nsiso0"); }
     920          49 :   if (fliso && nfa && !nfb) { swap(a,b); nfb = nfa; nfa = NULL; }
     921          49 :   if (!tests_OK(a, nfa, b, nfb, fliso)) { avma = av; return gen_0; }
     922             : 
     923          42 :   if (nfb) lb = gen_1; else b = ZX_Q_normalize(b,&lb);
     924          42 :   if (nfa) la = gen_1; else a = ZX_Q_normalize(a,&la);
     925          42 :   vb = varn(b); newvar = (varncmp(vb,varn(a)) <= 0);
     926          42 :   if (newvar) { a = leafcopy(a); setvarn(a, fetch_var_higher()); }
     927          42 :   if (nfb)
     928          14 :     y = lift_intern(nfroots(nfb,a));
     929             :   else
     930             :   {
     931          28 :     y = gel(polfnf(a,b),1); lx = lg(y);
     932         154 :     for (i=1; i<lx; i++)
     933             :     {
     934         126 :       GEN t = gel(y,i);
     935         126 :       if (degpol(t) != 1) { setlg(y,i); break; }
     936         126 :       gel(y,i) = gneg_i(lift_intern(gel(t,2)));
     937             :     }
     938          28 :     settyp(y, t_VEC);
     939          28 :     gen_sort_inplace(y, (void*)&cmp_RgX, &cmp_nodata, NULL);
     940             :   }
     941          42 :   if (newvar) (void)delete_var();
     942          42 :   lx = lg(y); if (lx==1) { avma=av; return gen_0; }
     943         189 :   for (i=1; i<lx; i++)
     944             :   {
     945         147 :     GEN t = gel(y,i);
     946         147 :     if (typ(t) == t_POL) setvarn(t, vb); else t = scalarpol(t, vb);
     947         147 :     if (lb != gen_1) t = RgX_unscale(t, lb);
     948         147 :     if (la != gen_1) t = RgX_Rg_div(t, la);
     949         147 :     gel(y,i) = t;
     950             :   }
     951          42 :   return gerepilecopy(av,y);
     952             : }
     953             : 
     954             : GEN
     955          14 : nfisisom(GEN a, GEN b) { return nfiso0(a,b,1); }
     956             : 
     957             : GEN
     958          35 : nfisincl(GEN a, GEN b) { return nfiso0(a,b,0); }
     959             : 
     960             : /*************************************************************************/
     961             : /**                                                                     **/
     962             : /**                               INITALG                               **/
     963             : /**                                                                     **/
     964             : /*************************************************************************/
     965             : 
     966             : GEN
     967        9142 : get_roots(GEN x, long r1, long prec)
     968             : {
     969             :   long i, ru;
     970             :   GEN z;
     971        9142 :   if (typ(x) != t_POL)
     972             :   {
     973           0 :     z = leafcopy(x);
     974           0 :     ru = (lg(z)-1 + r1) >> 1;
     975             :   }
     976             :   else
     977             :   {
     978        9142 :     long n = degpol(x);
     979        9142 :     z = (r1 == n)? realroots(x, NULL, prec): QX_complex_roots(x,prec);
     980        9142 :     ru = (n+r1)>>1;
     981             :   }
     982        9142 :   for (i=r1+1; i<=ru; i++) gel(z,i) = gel(z, (i<<1)-r1);
     983        9142 :   z[0]=evaltyp(t_VEC)|evallg(ru+1); return z;
     984             : }
     985             : 
     986             : GEN
     987           0 : nf_get_allroots(GEN nf)
     988             : {
     989           0 :   return embed_roots(nf_get_roots(nf), nf_get_r1(nf));
     990             : }
     991             : 
     992             : /* For internal use. compute trace(x mod pol), sym=polsym(pol,deg(pol)-1) */
     993             : GEN
     994       59045 : quicktrace(GEN x, GEN sym)
     995             : {
     996       59045 :   GEN p1 = gen_0;
     997             :   long i;
     998             : 
     999       59045 :   if (typ(x) != t_POL) return gmul(x, gel(sym,1));
    1000       59045 :   if (signe(x))
    1001             :   {
    1002       59045 :     sym--;
    1003      834568 :     for (i=lg(x)-1; i>1; i--)
    1004      775523 :       p1 = gadd(p1, gmul(gel(x,i),gel(sym,i)));
    1005             :   }
    1006       59045 :   return p1;
    1007             : }
    1008             : 
    1009             : static GEN
    1010        5110 : get_Tr(GEN mul, GEN x, GEN basden)
    1011             : {
    1012        5110 :   GEN t, bas = gel(basden,1), den = gel(basden,2);
    1013        5110 :   long i, j, n = lg(bas)-1;
    1014        5110 :   GEN T = cgetg(n+1,t_MAT), TW = cgetg(n+1,t_COL), sym = polsym(x, n-1);
    1015             : 
    1016        5110 :   gel(TW,1) = utoipos(n);
    1017       19439 :   for (i=2; i<=n; i++)
    1018             :   {
    1019       14329 :     t = quicktrace(gel(bas,i), sym);
    1020       14329 :     if (den && den[i]) t = diviiexact(t,gel(den,i));
    1021       14329 :     gel(TW,i) = t; /* tr(w[i]) */
    1022             :   }
    1023        5110 :   gel(T,1) = TW;
    1024       19439 :   for (i=2; i<=n; i++)
    1025             :   {
    1026       14329 :     gel(T,i) = cgetg(n+1,t_COL); gcoeff(T,1,i) = gel(TW,i);
    1027      117740 :     for (j=2; j<=i; j++) /* Tr(W[i]W[j]) */
    1028      103411 :       gcoeff(T,i,j) = gcoeff(T,j,i) = ZV_dotproduct(gel(mul,j+(i-1)*n), TW);
    1029             :   }
    1030        5110 :   return T;
    1031             : }
    1032             : 
    1033             : /* return [bas[i]*denom(bas[i]), denom(bas[i])], denom 1 is given as NULL */
    1034             : static GEN
    1035       13118 : get_bas_den(GEN bas)
    1036             : {
    1037       13118 :   GEN b,d,den, dbas = leafcopy(bas);
    1038       13118 :   long i, l = lg(bas);
    1039       13118 :   int power = 1;
    1040       13118 :   den = cgetg(l,t_VEC);
    1041       67602 :   for (i=1; i<l; i++)
    1042             :   {
    1043       54484 :     b = Q_remove_denom(gel(bas,i), &d);
    1044       54484 :     gel(dbas,i) = b;
    1045       54484 :     gel(den,i) = d; if (d) power = 0;
    1046             :   }
    1047       13118 :   if (power) den = NULL; /* power basis */
    1048       13118 :   return mkvec2(dbas, den);
    1049             : }
    1050             : 
    1051             : /* Internal: nf partially filled. Require pol; fill zk, invzk, multable */
    1052             : void
    1053        5110 : nf_set_multable(GEN nf, GEN bas, GEN basden)
    1054             : {
    1055        5110 :   GEN T = nf_get_pol(nf), invbas, basM;
    1056        5110 :   long i,j, n = degpol(T);
    1057        5110 :   GEN w, den, mul = cgetg(n*n+1,t_MAT);
    1058             : 
    1059        5110 :   if (typ(bas) == t_MAT)
    1060           0 :   { basM = bas; bas = RgM_to_RgXV(basM, varn(T)); }
    1061             :   else
    1062        5110 :     basM = RgV_to_RgM(bas, n);
    1063        5110 :   gel(nf,7) = bas;
    1064        5110 :   gel(nf,8) = invbas = QM_inv(basM, gen_1);
    1065        5110 :   gel(nf,9) = mul;
    1066             : 
    1067        5110 :   if (!basden) basden = get_bas_den(nf_get_zk(nf)); /*integral basis*/
    1068        5110 :   w   = gel(basden,1);
    1069        5110 :   den = gel(basden,2);
    1070             :   /* i = 1 split for efficiency, assume w[1] = 1 */
    1071       24549 :   for (j=1; j<=n; j++)
    1072       19439 :     gel(mul,j) = gel(mul,1+(j-1)*n) = col_ei(n, j);
    1073       19439 :   for (i=2; i<=n; i++)
    1074      117740 :     for (j=i; j<=n; j++)
    1075             :     {
    1076      103411 :       pari_sp av = avma;
    1077      103411 :       GEN z = (i == j)? ZXQ_sqr(gel(w,i), T): ZXQ_mul(gel(w,i),gel(w,j), T);
    1078      103411 :       z = mulmat_pol(invbas, z); /* integral column */
    1079      103411 :       if (den)
    1080             :       {
    1081       71176 :         GEN d = mul_denom(gel(den,i), gel(den,j));
    1082       71176 :         if (d) z = ZC_Z_divexact(z, d);
    1083             :       }
    1084      103411 :       gel(mul,j+(i-1)*n) = gel(mul,i+(j-1)*n) = gerepileupto(av,z);
    1085             :     }
    1086        5110 : }
    1087             : 
    1088             : /* as get_Tr, mul_table not precomputed */
    1089             : static GEN
    1090        2737 : make_Tr(GEN x, GEN basden)
    1091             : {
    1092        2737 :   long i,j, n = degpol(x);
    1093             :   GEN c, t, d;
    1094        2737 :   GEN T   = cgetg(n+1,t_MAT);
    1095        2737 :   GEN sym = polsym(x, n-1);
    1096        2737 :   GEN w   = gel(basden,1); /* W[i] = w[i]/den[i] */
    1097        2737 :   GEN den = gel(basden,2);
    1098             :   /* assume W[1] = 1, case i = 1 split for efficiency */
    1099        2737 :   c = cgetg(n+1,t_COL); gel(T,1) = c;
    1100        2737 :   gel(c, 1) = utoipos(n);
    1101        8232 :   for (j=2; j<=n; j++)
    1102             :   {
    1103        5495 :     pari_sp av = avma;
    1104        5495 :     t = quicktrace(gel(w,j), sym);
    1105        5495 :     if (den)
    1106             :     {
    1107        3969 :       d = gel(den,j);
    1108        3969 :       if (d) t = diviiexact(t, d);
    1109             :     }
    1110        5495 :     gel(c,j) = gerepileuptoint(av, t);
    1111             :   }
    1112        8232 :   for (i=2; i<=n; i++)
    1113             :   {
    1114        5495 :     c = cgetg(n+1,t_COL); gel(T,i) = c;
    1115        5495 :     for (j=1; j<i ; j++) gel(c,j) = gcoeff(T,i,j);
    1116       36575 :     for (   ; j<=n; j++)
    1117             :     {
    1118       31080 :       pari_sp av = avma;
    1119       31080 :       t = (i == j)? ZXQ_sqr(gel(w,i), x): ZXQ_mul(gel(w,i),gel(w,j), x);
    1120       31080 :       t = quicktrace(t, sym);
    1121       31080 :       if (den)
    1122             :       {
    1123       28448 :         d = mul_denom(gel(den,i),gel(den,j));
    1124       28448 :         if (d) t = diviiexact(t, d);
    1125             :       }
    1126       31080 :       gel(c,j) = gerepileuptoint(av, t); /* Tr (W[i]W[j]) */
    1127             :     }
    1128             :   }
    1129        2737 :   return T;
    1130             : }
    1131             : 
    1132             : /* compute roots so that _absolute_ accuracy of M >= prec [also holds for G] */
    1133             : static void
    1134       10422 : get_roots_for_M(nffp_t *F)
    1135             : {
    1136             :   long n, eBD, PREC;
    1137             : 
    1138       10422 :   if (F->extraprec < 0)
    1139             :   { /* not initialized yet */
    1140             :     double er;
    1141       10422 :     n = degpol(F->x);
    1142       10422 :     eBD = 1 + gexpo(gel(F->basden,1));
    1143       10422 :     er  = F->ro? (1+gexpo(F->ro)): fujiwara_bound(F->x);
    1144       10422 :     if (er < 0) er = 0;
    1145       10422 :     F->extraprec = nbits2extraprec(n*er + eBD + log2(n));
    1146             :   }
    1147             : 
    1148       10422 :   PREC = F->prec + F->extraprec;
    1149             :   /* make sure that default accuracy is the same on 32/64bit */
    1150             : #ifndef LONG_IS_64BIT
    1151        1524 :   if (odd(PREC)) PREC += EXTRAPRECWORD;
    1152             : #endif
    1153       20844 :   if (F->ro && gprecision(gel(F->ro,1)) >= PREC) return;
    1154        9142 :   F->ro = get_roots(F->x, F->r1, PREC);
    1155             : }
    1156             : 
    1157             : /* [bas[i]/den[i]]= integer basis. roo = real part of the roots */
    1158             : static void
    1159       10422 : make_M(nffp_t *F, int trunc)
    1160             : {
    1161       10422 :   GEN bas = gel(F->basden,1), den = gel(F->basden,2), ro = F->ro;
    1162             :   GEN m, d, M;
    1163       10422 :   long i, j, l = lg(ro), n = lg(bas);
    1164       10422 :   M = cgetg(n,t_MAT);
    1165       10422 :   gel(M,1) = const_col(l-1, gen_1); /* bas[1] = 1 */
    1166       10422 :   for (j=2; j<n; j++) gel(M,j) = cgetg(l,t_COL);
    1167       39629 :   for (i=1; i<l; i++)
    1168             :   {
    1169       29207 :     GEN r = gel(ro,i), ri;
    1170       29207 :     ri = (gexpo(r) > 1)? ginv(r): NULL;
    1171       29207 :     for (j=2; j<n; j++) gcoeff(M,i,j) = RgX_cxeval(gel(bas,j), r, ri);
    1172             :   }
    1173       10422 :   if (den)
    1174       28469 :     for (j=2; j<n; j++)
    1175             :     {
    1176       24053 :       d = gel(den,j); if (!d) continue;
    1177       19530 :       m = gel(M,j);
    1178       19530 :       for (i=1; i<l; i++) gel(m,i) = gdiv(gel(m,i), d);
    1179             :     }
    1180             : 
    1181       10422 :   if (trunc && gprecision(M) > F->prec)
    1182             :   {
    1183        1889 :     M     = gprec_w(M, F->prec);
    1184        1889 :     F->ro = gprec_w(ro,F->prec);
    1185             :   }
    1186       10422 :   F->M = M;
    1187       10422 : }
    1188             : 
    1189             : /* return G real such that G~ * G = T_2 */
    1190             : static void
    1191       10422 : make_G(nffp_t *F)
    1192             : {
    1193       10422 :   GEN G, M = F->M;
    1194       10422 :   long i, j, k, r1 = F->r1, l = lg(M);
    1195             : 
    1196       10422 :   G = cgetg(l, t_MAT);
    1197       56784 :   for (j=1; j<l; j++)
    1198             :   {
    1199       46362 :     GEN g = cgetg(l, t_COL);
    1200       46362 :     GEN m = gel(M,j);
    1201       46362 :     gel(G,j) = g;
    1202       46362 :     for (k=i=1; i<=r1; i++) g[k++] = m[i];
    1203      266972 :     for (     ; k < l; i++)
    1204             :     {
    1205      220610 :       GEN r = gel(m,i);
    1206      220610 :       if (typ(r) == t_COMPLEX)
    1207             :       {
    1208      203455 :         gel(g,k++) = mpadd(gel(r,1), gel(r,2));
    1209      203455 :         gel(g,k++) = mpsub(gel(r,1), gel(r,2));
    1210             :       }
    1211             :       else
    1212             :       {
    1213       17155 :         gel(g,k++) = r;
    1214       17155 :         gel(g,k++) = r;
    1215             :       }
    1216             :     }
    1217             :   }
    1218       10422 :   F->G = G;
    1219       10422 : }
    1220             : 
    1221             : static void
    1222       10422 : make_M_G(nffp_t *F, int trunc)
    1223             : {
    1224       10422 :   get_roots_for_M(F);
    1225       10422 :   make_M(F, trunc);
    1226       10422 :   make_G(F);
    1227       10422 : }
    1228             : 
    1229             : void
    1230         784 : remake_GM(GEN nf, nffp_t *F, long prec)
    1231             : {
    1232         784 :   F->x  = nf_get_pol(nf);
    1233         784 :   F->ro = NULL;
    1234         784 :   F->r1 = nf_get_r1(nf);
    1235         784 :   F->basden = get_bas_den(nf_get_zk(nf));
    1236         784 :   F->extraprec = -1;
    1237         784 :   F->prec = prec; make_M_G(F, 1);
    1238         784 : }
    1239             : 
    1240             : static void
    1241        9638 : nffp_init(nffp_t *F, nfbasic_t *T, GEN ro, long prec)
    1242             : {
    1243        9638 :   F->x  = T->x;
    1244        9638 :   F->ro = ro;
    1245        9638 :   F->r1 = T->r1;
    1246        9638 :   if (!T->basden) T->basden = get_bas_den(T->bas);
    1247        9638 :   F->basden = T->basden;
    1248        9638 :   F->extraprec = -1;
    1249        9638 :   F->prec = prec;
    1250        9638 : }
    1251             : 
    1252             : static void
    1253        6243 : get_nf_fp_compo(nfbasic_t *T, nffp_t *F, GEN ro, int trunc, long prec)
    1254             : {
    1255        6243 :   nffp_init(F,T,ro,prec);
    1256        6243 :   make_M_G(F, trunc);
    1257        6243 : }
    1258             : 
    1259             : static GEN
    1260        5110 : get_sign(long r1, long n) { return mkvec2s(r1, (n-r1)>>1); }
    1261             : 
    1262             : GEN
    1263        5110 : nfbasic_to_nf(nfbasic_t *T, GEN ro, long prec)
    1264             : {
    1265        5110 :   GEN nf = cgetg(10,t_VEC);
    1266        5110 :   GEN x = T->x, absdK, Tr, D, TI, A, dA, MDI, mat = cgetg(9,t_VEC);
    1267        5110 :   long n = degpol(T->x);
    1268             :   nffp_t F;
    1269        5110 :   get_nf_fp_compo(T, &F, ro, 0, prec);
    1270             : 
    1271        5110 :   gel(nf,1) = T->x;
    1272        5110 :   gel(nf,2) = get_sign(T->r1, n);
    1273        5110 :   gel(nf,3) = T->dK;
    1274        5110 :   gel(nf,4) = T->index;
    1275        5110 :   gel(nf,6) = F.ro;
    1276        5110 :   gel(nf,5) = mat;
    1277             : 
    1278        5110 :   gel(mat,1) = F.M;
    1279        5110 :   gel(mat,2) = F.G;
    1280             : 
    1281        5110 :   nf_set_multable(nf, T->bas, F.basden);
    1282             : 
    1283        5110 :   Tr = get_Tr(gel(nf,9), x, F.basden);
    1284        5110 :   absdK = T->dK; if (signe(absdK) < 0) absdK = negi(absdK);
    1285        5110 :   TI = ZM_inv(Tr, absdK); /* dK T^-1 */
    1286        5110 :   A = Q_primitive_part(TI, &dA);
    1287        5110 :   gel(mat,6) = A; /* primitive part of codifferent, dA its content */
    1288        5110 :   dA = dA? diviiexact(absdK, dA): absdK;
    1289        5110 :   A = ZM_hnfmodid(A, dA);
    1290        5110 :   MDI = idealtwoelt(nf, A);
    1291        5110 :   gel(MDI,2) = zk_scalar_or_multable(nf, gel(MDI,2));
    1292        5110 :   gel(mat,7) = MDI;
    1293        5110 :   if (is_pm1(T->index)) /* principal ideal (x'), whose norm is |dK| */
    1294             :   {
    1295        3549 :     D = zk_scalar_or_multable(nf, ZX_deriv(x));
    1296        3549 :     if (typ(D) == t_MAT) D = ZM_hnfmod(D, absdK);
    1297             :   }
    1298             :   else
    1299        1561 :     D = RgM_Rg_mul(idealinv(nf, A), dA);
    1300        5110 :   gel(mat,3) = RM_round_maxrank(F.G);
    1301        5110 :   gel(mat,4) = Tr;
    1302        5110 :   gel(mat,5) = D;
    1303        5110 :   gel(mat,8) = T->dKP? shallowtrans(T->dKP): cgetg(1,t_VEC);
    1304        5110 :   return nf;
    1305             : }
    1306             : 
    1307             : static GEN
    1308          91 : primes_certify(GEN dK, GEN dKP)
    1309             : {
    1310          91 :   long i, l = lg(dKP);
    1311          91 :   GEN v, w, D = dK;
    1312          91 :   v = vectrunc_init(l);
    1313          91 :   w = vectrunc_init(l);
    1314         427 :   for (i = 1; i < l; i++)
    1315             :   {
    1316         336 :     GEN p = gel(dKP,i);
    1317         336 :     vectrunc_append(isprime(p)? w: v, p);
    1318         336 :     (void)Z_pvalrem(D, p, &D);
    1319             :   }
    1320          91 :   if (!is_pm1(D))
    1321             :   {
    1322           0 :     if (signe(D) < 0) D = negi(D);
    1323           0 :     vectrunc_append(isprime(D)? w: v, D);
    1324             :   }
    1325          91 :   return mkvec2(v,w);
    1326             : }
    1327             : GEN
    1328           7 : nfcertify(GEN nf)
    1329             : {
    1330           7 :   pari_sp av = avma;
    1331             :   GEN vw;
    1332           7 :   nf = checknf(nf);
    1333           7 :   vw = primes_certify(nf_get_disc(nf), nf_get_ramified_primes(nf));
    1334           7 :   return gerepilecopy(av, gel(vw,1));
    1335             : }
    1336             : 
    1337             : #if 0 /* used to check benches between HNF nf.zk and LLL-reduced nf.zk */
    1338             : static GEN
    1339             : hnffromLLL(GEN nf)
    1340             : {
    1341             :   GEN d, x;
    1342             :   x = RgV_to_RgM(nf_get_zk(nf), nf_get_degree(nf));
    1343             :   x = Q_remove_denom(x, &d);
    1344             :   if (!d) return x; /* power basis */
    1345             :   return RgM_solve(ZM_hnfmodid(x, d), x);
    1346             : }
    1347             : 
    1348             : static GEN
    1349             : nfbasechange(GEN u, GEN x)
    1350             : {
    1351             :   long i,lx;
    1352             :   GEN y;
    1353             :   switch(typ(x))
    1354             :   {
    1355             :     case t_COL: /* nfelt */
    1356             :       return RgM_RgC_mul(u, x);
    1357             : 
    1358             :     case t_MAT: /* ideal */
    1359             :       y = cgetg_copy(x, &lx);
    1360             :       for (i=1; i<lx; i++) gel(y,i) = RgM_RgC_mul(u, gel(x,i));
    1361             :       break;
    1362             : 
    1363             :     case t_VEC: /* pr */
    1364             :       checkprid(x); y = leafcopy(x);
    1365             :       gel(y,2) = RgM_RgC_mul(u, gel(y,2));
    1366             :       gel(y,5) = RgM_RgC_mul(u, gel(y,5));
    1367             :       break;
    1368             :     default: y = x;
    1369             :   }
    1370             :   return y;
    1371             : }
    1372             : 
    1373             : GEN
    1374             : nffromhnfbasis(GEN nf, GEN x)
    1375             : {
    1376             :   long tx = typ(x);
    1377             :   pari_sp av = avma;
    1378             :   GEN u;
    1379             :   if (!is_vec_t(tx)) return gcopy(x);
    1380             :   nf = checknf(nf);
    1381             :   u = hnffromLLL(nf);
    1382             :   return gerepilecopy(av, nfbasechange(u, x));
    1383             : }
    1384             : 
    1385             : GEN
    1386             : nftohnfbasis(GEN nf, GEN x)
    1387             : {
    1388             :   long tx = typ(x);
    1389             :   pari_sp av = avma;
    1390             :   GEN u;
    1391             :   if (!is_vec_t(tx)) return gcopy(x);
    1392             :   nf = checknf(nf);
    1393             :   u = ZM_inv(hnffromLLL(nf), gen_1);
    1394             :   return gerepilecopy(av, nfbasechange(u, x));
    1395             : }
    1396             : #endif
    1397             : 
    1398             : /* set *pro to roots of T->x */
    1399             : static GEN
    1400        3395 : get_red_G(nfbasic_t *T, GEN *pro)
    1401             : {
    1402        3395 :   GEN G, u, u0 = NULL;
    1403             :   pari_sp av;
    1404        3395 :   long i, prec, n = degpol(T->x);
    1405             :   nffp_t F;
    1406             : 
    1407        3395 :   prec = nbits2prec(n+32);
    1408        3395 :   nffp_init(&F, T, NULL, prec);
    1409        3395 :   av = avma;
    1410        3395 :   for (i=1; ; i++)
    1411             :   {
    1412        3395 :     F.prec = prec; make_M_G(&F, 0); G = F.G;
    1413        3395 :     if (u0) G = RgM_mul(G, u0);
    1414        3395 :     if (DEBUGLEVEL)
    1415           0 :       err_printf("get_red_G: starting LLL, prec = %ld (%ld + %ld)\n",
    1416           0 :                   prec + F.extraprec, prec, F.extraprec);
    1417        3395 :     if ((u = lllfp(G, 0.99, LLL_KEEP_FIRST|LLL_COMPATIBLE)))
    1418             :     {
    1419        3395 :       if (lg(u)-1 == n) break;
    1420             :       /* singular ==> loss of accuracy */
    1421           0 :       if (u0) u0 = gerepileupto(av, RgM_mul(u0,u));
    1422           0 :       else    u0 = gerepilecopy(av, u);
    1423             :     }
    1424           0 :     prec = precdbl(prec) + nbits2extraprec(gexpo(u0));
    1425           0 :     F.ro = NULL;
    1426           0 :     if (DEBUGLEVEL) pari_warn(warnprec,"get_red_G", prec);
    1427           0 :   }
    1428        3395 :   if (u0) u = RgM_mul(u0,u);
    1429        3395 :   *pro = F.ro; return u;
    1430             : }
    1431             : 
    1432             : /* Compute an LLL-reduced basis for the integer basis of nf(T).
    1433             :  * set *pro = roots of x if computed [NULL if not computed] */
    1434             : static void
    1435        6132 : set_LLL_basis(nfbasic_t *T, GEN *pro, double DELTA)
    1436             : {
    1437        6132 :   GEN B = T->bas;
    1438        6132 :   if (T->r1 == degpol(T->x)) {
    1439        2737 :     pari_sp av = avma;
    1440        2737 :     GEN u, basden = T->basden;
    1441        2737 :     if (!basden) basden = get_bas_den(B);
    1442        2737 :     u = ZM_lll(make_Tr(T->x,basden), DELTA,
    1443             :                LLL_GRAM|LLL_KEEP_FIRST|LLL_IM|LLL_COMPATIBLE);
    1444        2737 :     B = gerepileupto(av, RgV_RgM_mul(B, u));
    1445        2737 :     *pro = NULL;
    1446             :   }
    1447             :   else
    1448        3395 :     B = RgV_RgM_mul(B, get_red_G(T, pro));
    1449        6132 :   T->bas = B;
    1450        6132 :   T->basden = get_bas_den(B);
    1451        6132 : }
    1452             : 
    1453             : static int
    1454        3172 : cmp_abs_ZX(GEN x, GEN y) { return gen_cmp_RgX((void*)&abscmpii, x, y); }
    1455             : /* current best: ZX x of discriminant *dx, is ZX y better than x ?
    1456             :  * (if so update *dx) */
    1457             : static int
    1458        4621 : ZX_is_better(GEN y, GEN x, GEN *dx)
    1459             : {
    1460        4621 :   GEN d = ZX_disc(y);
    1461             :   int cmp;
    1462        4621 :   if (!*dx) *dx = ZX_disc(x);
    1463        4621 :   cmp = abscmpii(d, *dx);
    1464        4621 :   if (cmp < 0) { *dx = d; return 1; }
    1465        3781 :   if (cmp == 0) return cmp_abs_ZX(y, x) < 0;
    1466         609 :   return 0;
    1467             : }
    1468             : 
    1469             : static void polredbest_aux(nfbasic_t *T, GEN *pro, GEN *px, GEN *pdx, GEN *pa);
    1470             : /* Seek a simpler, polynomial pol defining the same number field as
    1471             :  * x (assumed to be monic at this point) */
    1472             : static GEN
    1473          84 : nfpolred(nfbasic_t *T, GEN *pro)
    1474             : {
    1475          84 :   GEN x = T->x, dx, b, rev;
    1476          84 :   long n = degpol(x), v = varn(x);
    1477             : 
    1478          84 :   if (n == 1) {
    1479           7 :     T->x = deg1pol_shallow(gen_1, gen_m1, v);
    1480           7 :     *pro = NULL; return pol_1(v);
    1481             :   }
    1482          77 :   polredbest_aux(T, pro, &x, &dx, &b);
    1483          77 :   if (x == T->x) return NULL; /* no improvement */
    1484          56 :   if (DEBUGLEVEL>1) err_printf("xbest = %Ps\n",x);
    1485             : 
    1486             :   /* update T */
    1487          56 :   rev = QXQ_reverse(b, T->x);
    1488          56 :   T->bas = QXV_QXQ_eval(T->bas, rev, x);
    1489          56 :   (void)Z_issquareall(diviiexact(dx,T->dK), &(T->index));
    1490          56 :   T->basden = get_bas_den(T->bas);
    1491          56 :   T->dx = dx;
    1492          56 :   T->x = x;
    1493          56 :   *pro = NULL; /* reset */
    1494          56 :   return rev;
    1495             : }
    1496             : 
    1497             : /* let bas a t_VEC of QX giving a Z-basis of O_K. Return the index of the
    1498             :  * basis. Assume bas[1] is 1 and that the leading coefficient of elements
    1499             :  * of bas are of the form 1/b for a t_INT b */
    1500             : GEN
    1501         525 : get_nfindex(GEN bas)
    1502             : {
    1503         525 :   pari_sp av = avma;
    1504         525 :   long n = lg(bas)-1, i;
    1505             :   GEN D, d, mat;
    1506             : 
    1507         525 :   D = gen_1; /* assume bas[1] = 1 */
    1508        1197 :   for (i = 2; i <= n; i++)
    1509             :   { /* in most cases [e.g after nfbasis] basis is upper triangular! */
    1510         924 :     GEN B = gel(bas,i), lc;
    1511         924 :     if (degpol(B) != i-1) break;
    1512         672 :     lc = gel(B, i+1);
    1513         672 :     switch (typ(lc))
    1514             :     {
    1515         399 :       case t_INT: continue;
    1516         273 :       case t_FRAC: lc = gel(lc,2); break;
    1517           0 :       default: pari_err_TYPE("get_nfindex",lc);
    1518             :     }
    1519         273 :     D = mulii(D, lc);
    1520             :   }
    1521         525 :   if (i <= n)
    1522             :   { /* not triangular after all */
    1523         252 :     bas = Q_remove_denom(bas, &d);
    1524         252 :     if (!d) { avma = av; return D; }
    1525         238 :     mat = RgV_to_RgM(bas, n);
    1526         238 :     d = diviiexact(powiu(d, n), ZM_det(mat));
    1527         238 :     D = mulii(D,absi(d));
    1528             :   }
    1529         511 :   return gerepileuptoint(av, D);
    1530             : }
    1531             : 
    1532             : /* Either nf type or ZX or [monic ZX, data], where data is either an integral
    1533             :  * basis (deprecated), or listP data (nfbasis input format) to specify
    1534             :  * a set of primes at with the basis order must be maximal.
    1535             :  * 1) nf type (or unrecognized): return t_VEC
    1536             :  * 2) ZX or [ZX, listP]: return t_POL
    1537             :  * 3) [ZX, order basis]: return 0 (deprecated)
    1538             :  * incorrect: return -1 */
    1539             : static long
    1540        6216 : nf_input_type(GEN x)
    1541             : {
    1542             :   GEN T, V;
    1543             :   long i, d, v;
    1544        6216 :   switch(typ(x))
    1545             :   {
    1546        5579 :     case t_POL: return t_POL;
    1547             :     case t_VEC:
    1548         637 :       if (lg(x) != 3) return t_VEC; /* nf or incorrect */
    1549         630 :       T = gel(x,1); V = gel(x,2);
    1550         630 :       if (typ(T) != t_POL) return -1;
    1551         630 :       switch(typ(V))
    1552             :       {
    1553          35 :         case t_INT: case t_MAT: return t_POL;
    1554             :         case t_VEC: case t_COL:
    1555         595 :           if (RgV_is_ZV(V)) return t_POL;
    1556         574 :           break;
    1557           0 :         default: return -1;
    1558             :       }
    1559         574 :       d = degpol(T); v = varn(T);
    1560         574 :       if (d<1 || !RgX_is_ZX(T) || !isint1(gel(T,d+2)) || lg(V)-1!=d) return -1;
    1561        3192 :       for (i = 1; i <= d; i++)
    1562             :       { /* check integer basis */
    1563        2639 :         GEN c = gel(V,i);
    1564        2639 :         switch(typ(c))
    1565             :         {
    1566          28 :           case t_INT: break;
    1567        2611 :           case t_POL: if (varn(c) == v && RgX_is_QX(c) && degpol(c) < d) break;
    1568             :           /* fall through */
    1569          14 :           default: return -1;
    1570             :         }
    1571             :       }
    1572         553 :       return 0;
    1573             :   }
    1574           0 :   return t_VEC; /* nf or incorrect */
    1575             : }
    1576             : 
    1577             : static void
    1578        5103 : nfbasic_add_disc(nfbasic_t *T)
    1579             : {
    1580        5103 :   if (!T->index) T->index = get_nfindex(T->bas);
    1581        5103 :   if (!T->dx) T->dx = ZX_disc(T->x);
    1582        5103 :   if (!T->dK) T->dK = diviiexact(T->dx, sqri(T->index));
    1583        5103 : }
    1584             : 
    1585             : static void
    1586        6216 : nfbasic_init(GEN x, long flag, nfbasic_t *T)
    1587             : {
    1588        6216 :   GEN bas, dK, dx, index, unscale = gen_1;
    1589             :   long r1;
    1590             : 
    1591        6216 :   T->dKP = NULL;
    1592        6216 :   switch (nf_input_type(x))
    1593             :   {
    1594             :     case t_POL:
    1595             :     {
    1596             :       nfmaxord_t S;
    1597        5635 :       nfmaxord(&S, x, flag);
    1598        5628 :       x = S.T;
    1599        5628 :       T->x0 = S.T0;
    1600        5628 :       T->dKP = S.dKP;
    1601        5628 :       dK = S.dK;
    1602        5628 :       index = S.index;
    1603        5628 :       bas = S.basis;
    1604        5628 :       dx = S.dT;
    1605        5628 :       unscale = S.unscale;
    1606        5628 :       r1 = ZX_sturm(x);
    1607        5628 :       break;
    1608             :     }
    1609             :     case t_VEC:
    1610             :     { /* nf, bnf, bnr */
    1611           7 :       GEN nf = checknf(x);
    1612           7 :       x     = nf_get_pol(nf);
    1613           7 :       dK    = nf_get_disc(nf);
    1614           7 :       index = nf_get_index(nf);
    1615           7 :       bas   = nf_get_zk(nf);
    1616           7 :       T->x0 = x;
    1617           7 :       dx = NULL;
    1618           7 :       r1 = nf_get_r1(nf);
    1619           7 :       break;
    1620             :     }
    1621             :     case 0: /* monic integral polynomial + integer basis */
    1622         553 :       bas = gel(x,2); x = gel(x,1);
    1623         553 :       T->x0 = x;
    1624         553 :       index = NULL;
    1625         553 :       dx = NULL;
    1626         553 :       dK = NULL;
    1627         553 :       r1 = ZX_sturm(x);
    1628         553 :       break;
    1629             :     default: /* -1 */
    1630          21 :       pari_err_TYPE("nfbasic_init", x);
    1631        6188 :       return;
    1632             :   }
    1633        6188 :   T->x     = x;
    1634        6188 :   T->unscale = unscale;
    1635        6188 :   T->r1    = r1;
    1636        6188 :   T->dx    = dx;
    1637        6188 :   T->dK    = dK;
    1638        6188 :   T->bas   = bas;
    1639        6188 :   T->basden= NULL;
    1640        6188 :   T->index = index;
    1641             : }
    1642             : 
    1643             : void
    1644        5124 : nfinit_step1(nfbasic_t *T, GEN x, long flag)
    1645             : {
    1646        5124 :   nfbasic_init(x, flag, T);
    1647        5103 :   if (!ZX_is_irred(T->x)) pari_err_IRREDPOL("nfinit",x);
    1648        5103 : }
    1649             : 
    1650             : GEN
    1651        5103 : nfinit_step2(nfbasic_t *T, long flag, long prec)
    1652             : {
    1653             :   GEN nf, unscale;
    1654             : 
    1655        5103 :   if (!(flag & nf_RED) && !equali1(leading_coeff(T->x0)))
    1656             :   {
    1657          49 :     pari_warn(warner,"non-monic polynomial. Result of the form [nf,c]");
    1658          49 :     flag |= nf_RED | nf_ORIG;
    1659             :   }
    1660        5103 :   unscale = T->unscale;
    1661        5103 :   if (!(flag & nf_RED) && !isint1(unscale))
    1662             :   { /* implies lc(x0) = 1 and L := 1/unscale is integral */
    1663         105 :     long d = degpol(T->x0);
    1664         105 :     GEN L = ginv(unscale); /* x = L^(-deg(x)) x0(L X) */
    1665         105 :     GEN f= powiu(L, (d*(d-1)) >> 1);
    1666         105 :     T->x = T->x0; /* restore original user-supplied x0, unscale data */
    1667         105 :     T->unscale = gen_1;
    1668         105 :     T->dx    = gmul(T->dx, sqri(f));
    1669         105 :     T->bas   = RgXV_unscale(T->bas, unscale);
    1670         105 :     T->index = gmul(T->index, f);
    1671             :   }
    1672        5103 :   nfbasic_add_disc(T); /* more expensive after set_LLL_basis */
    1673        5103 :   if (flag & nf_RED)
    1674             :   {
    1675             :     GEN ro, rev;
    1676             :     /* lie to polred: more efficient to update *after* modreverse, than to
    1677             :      * unscale in the polred subsystem */
    1678          84 :     T->unscale = gen_1;
    1679          84 :     rev = nfpolred(T, &ro);
    1680          84 :     nf = nfbasic_to_nf(T, ro, prec);
    1681          84 :     if (flag & nf_ORIG)
    1682             :     {
    1683          56 :       if (!rev) rev = pol_x(varn(T->x)); /* no improvement */
    1684          56 :       if (!isint1(unscale)) rev = RgX_Rg_div(rev, unscale);
    1685          56 :       nf = mkvec2(nf, mkpolmod(rev, T->x));
    1686             :     }
    1687          84 :     T->unscale = unscale; /* restore */
    1688             :   } else {
    1689        5019 :     GEN ro; set_LLL_basis(T, &ro, 0.99);
    1690        5019 :     nf = nfbasic_to_nf(T, ro, prec);
    1691             :   }
    1692        5103 :   return nf;
    1693             : }
    1694             : /* Initialize the number field defined by the polynomial x (in variable v)
    1695             :  * flag & nf_RED:     try a polred first.
    1696             :  * flag & nf_ORIG
    1697             :  *    do a polred and return [nfinit(x), Mod(a,red)], where
    1698             :  *    Mod(a,red) = Mod(v,x) (i.e return the base change). */
    1699             : GEN
    1700        3108 : nfinitall(GEN x, long flag, long prec)
    1701             : {
    1702        3108 :   const pari_sp av = avma;
    1703             :   nfbasic_t T;
    1704             :   GEN nf;
    1705             : 
    1706        3108 :   if (checkrnf_i(x)) return check_and_build_nfabs(x, prec);
    1707        3101 :   nfinit_step1(&T, x, flag);
    1708        3080 :   nf = nfinit_step2(&T, flag, prec);
    1709        3080 :   return gerepilecopy(av, nf);
    1710             : }
    1711             : 
    1712             : GEN
    1713           0 : nfinitred(GEN x, long prec)  { return nfinitall(x, nf_RED, prec); }
    1714             : GEN
    1715           0 : nfinitred2(GEN x, long prec) { return nfinitall(x, nf_RED|nf_ORIG, prec); }
    1716             : GEN
    1717        1183 : nfinit(GEN x, long prec)     { return nfinitall(x, 0, prec); }
    1718             : 
    1719             : GEN
    1720        1708 : nfinit0(GEN x, long flag,long prec)
    1721             : {
    1722        1708 :   switch(flag)
    1723             :   {
    1724             :     case 0:
    1725        1687 :     case 1: return nfinitall(x,0,prec);
    1726          14 :     case 2: case 4: return nfinitall(x,nf_RED,prec);
    1727           7 :     case 3: case 5: return nfinitall(x,nf_RED|nf_ORIG,prec);
    1728           0 :     default: pari_err_FLAG("nfinit");
    1729             :   }
    1730           0 :   return NULL; /* not reached */
    1731             : }
    1732             : 
    1733             : /* assume x a bnr/bnf/nf */
    1734             : long
    1735       69552 : nf_get_prec(GEN x)
    1736             : {
    1737       69552 :   GEN nf = checknf(x), ro = nf_get_roots(nf);
    1738       69552 :   return (typ(ro)==t_VEC)? precision(gel(ro,1)): DEFAULTPREC;
    1739             : }
    1740             : 
    1741             : /* assume nf is an nf */
    1742             : GEN
    1743         784 : nfnewprec_shallow(GEN nf, long prec)
    1744             : {
    1745         784 :   GEN NF = leafcopy(nf);
    1746             :   nffp_t F;
    1747         784 :   gel(NF,5) = leafcopy(gel(NF,5));
    1748         784 :   remake_GM(NF, &F, prec);
    1749         784 :   gel(NF,6) = F.ro;
    1750         784 :   gmael(NF,5,1) = F.M;
    1751         784 :   gmael(NF,5,2) = F.G;
    1752         784 :   return NF;
    1753             : }
    1754             : 
    1755             : GEN
    1756          63 : nfnewprec(GEN nf, long prec)
    1757             : {
    1758             :   GEN z;
    1759          63 :   switch(nftyp(nf))
    1760             :   {
    1761          49 :     default: pari_err_TYPE("nfnewprec", nf);
    1762           7 :     case typ_BNF: z = bnfnewprec(nf,prec); break;
    1763           7 :     case typ_BNR: z = bnrnewprec(nf,prec); break;
    1764             :     case typ_NF: {
    1765           0 :       pari_sp av = avma;
    1766           0 :       z = gerepilecopy(av, nfnewprec_shallow(checknf(nf), prec));
    1767           0 :       break;
    1768             :     }
    1769             :   }
    1770          14 :   return z;
    1771             : }
    1772             : 
    1773             : /********************************************************************/
    1774             : /**                                                                **/
    1775             : /**                           POLRED                               **/
    1776             : /**                                                                **/
    1777             : /********************************************************************/
    1778             : GEN
    1779           0 : embednorm_T2(GEN x, long r1)
    1780             : {
    1781           0 :   pari_sp av = avma;
    1782           0 :   GEN p = RgV_sumpart(x, r1);
    1783           0 :   GEN q = RgV_sumpart2(x,r1+1, lg(x)-1);
    1784           0 :   if (q != gen_0) p = gadd(p, gmul2n(q,1));
    1785           0 :   return avma == av? gcopy(p): gerepileupto(av, p);
    1786             : }
    1787             : 
    1788             : /* simplified version of gnorm for scalar, non-complex inputs, without GC */
    1789             : static GEN
    1790        6671 : real_norm(GEN x)
    1791             : {
    1792        6671 :   switch(typ(x))
    1793             :   {
    1794           0 :     case t_INT:  return sqri(x);
    1795        6671 :     case t_REAL: return sqrr(x);
    1796           0 :     case t_FRAC: return sqrfrac(x);
    1797             :   }
    1798           0 :   pari_err_TYPE("real_norm", x);
    1799           0 :   return NULL;
    1800             : }
    1801             : /* simplified version of gnorm, without GC */
    1802             : static GEN
    1803     2479211 : complex_norm(GEN x)
    1804             : {
    1805     2479211 :   return typ(x) == t_COMPLEX? cxnorm(x): real_norm(x);
    1806             : }
    1807             : /* return T2(x), argument r1 needed in case x has components whose type
    1808             :  * is unexpected, e.g. all of them t_INT for embed(gen_1) */
    1809             : GEN
    1810        1583 : embed_T2(GEN x, long r1)
    1811             : {
    1812        1583 :   pari_sp av = avma;
    1813        1583 :   long i, l = lg(x);
    1814        1583 :   GEN c, s = NULL, t = NULL;
    1815        1583 :   if (typ(gel(x,1)) == t_INT) return muliu(gel(x,1), 2*(l-1)-r1);
    1816        8254 :   for (i = 1; i <= r1; i++)
    1817             :   {
    1818        6671 :     c = real_norm(gel(x,i));
    1819        6671 :     s = s? gadd(s, c): c;
    1820             :   }
    1821        6338 :   for (; i < l; i++)
    1822             :   {
    1823        4755 :     c = complex_norm(gel(x,i));
    1824        4755 :     t = t? gadd(t, c): c;
    1825             :   }
    1826        1583 :   if (t) { t = gmul2n(t,1); s = s? gadd(s,t): t; }
    1827        1583 :   return gerepileupto(av, s);
    1828             : }
    1829             : /* return N(x) */
    1830             : GEN
    1831     1170048 : embed_norm(GEN x, long r1)
    1832             : {
    1833     1170048 :   pari_sp av = avma;
    1834     1170048 :   long i, l = lg(x);
    1835     1170048 :   GEN c, s = NULL, t = NULL;
    1836     1170048 :   if (typ(gel(x,1)) == t_INT) return powiu(gel(x,1), 2*(l-1)-r1);
    1837     2849269 :   for (i = 1; i <= r1; i++)
    1838             :   {
    1839     1682691 :     c = gel(x,i);
    1840     1682691 :     s = s? gmul(s, c): c;
    1841             :   }
    1842     3641034 :   for (; i < l; i++)
    1843             :   {
    1844     2474456 :     c = complex_norm(gel(x,i));
    1845     2474456 :     t = t? gmul(t, c): c;
    1846             :   }
    1847     1166578 :   if (t) s = s? gmul(s,t): t;
    1848     1166578 :   return gerepileupto(av, s);
    1849             : }
    1850             : 
    1851             : typedef struct {
    1852             :   long r1, v, prec;
    1853             :   GEN ZKembed; /* embeddings of fincke-pohst-reduced Zk basis */
    1854             :   GEN u; /* matrix giving fincke-pohst-reduced Zk basis */
    1855             :   GEN M; /* embeddings of initial (LLL-reduced) Zk basis */
    1856             :   GEN bound; /* T2 norm of the polynomial defining nf */
    1857             :   long expo_best_disc; /* expo(disc(x)), best generator so far */
    1858             : } CG_data;
    1859             : 
    1860             : /* characteristic pol of x (given by embeddings) */
    1861             : static GEN
    1862       24778 : get_pol(CG_data *d, GEN x)
    1863             : {
    1864             :   long e;
    1865       24778 :   GEN g = grndtoi(roots_to_pol_r1(x, d->v, d->r1), &e);
    1866       24778 :   return (e > -5)? NULL: g;
    1867             : }
    1868             : 
    1869             : /* characteristic pol of x (given as vector on (w_i)) */
    1870             : static GEN
    1871       10593 : get_polchar(CG_data *d, GEN x)
    1872       10593 : { return get_pol(d, RgM_RgC_mul(d->ZKembed,x)); }
    1873             : 
    1874             : /* Choose a canonical polynomial in the pair { z(X), (+/-)z(-X) }.
    1875             :  * z a ZX with lc(z) > 0. We want to keep that property, while
    1876             :  * ensuring that the leading coeff of the odd (resp. even) part of z is < 0
    1877             :  * if deg z is even (resp. odd).
    1878             :  * Either leave z alone (return 1) or set z <-- (-1)^deg(z) z(-X). In place. */
    1879             : static int
    1880       10733 : ZX_canon_neg(GEN z)
    1881             : {
    1882             :   long i,s;
    1883             : 
    1884      165778 :   for (i = lg(z)-2; i >= 2; i -= 2)
    1885             :   { /* examine the odd (resp. even) part of z if deg(z) even (resp. odd). */
    1886       77576 :     s = signe(gel(z,i));
    1887       77576 :     if (!s) continue;
    1888             :     /* non trivial */
    1889        5420 :     if (s < 0) break; /* the condition is already satisfied */
    1890             : 
    1891        1807 :     for (; i>=2; i-=2) gel(z,i) = negi(gel(z,i));
    1892        1807 :     return 1;
    1893             :   }
    1894        8926 :   return 0;
    1895             : }
    1896             : /* return a defining polynomial for Q(alpha), v = embeddings of alpha.
    1897             :  * Return NULL on failure: discriminant too large or non primitive */
    1898             : static GEN
    1899       20272 : try_polmin(CG_data *d, nfbasic_t *T, GEN v, long flag, GEN *ai)
    1900             : {
    1901       20272 :   const long best = flag & nf_ABSOLUTE;
    1902             :   long ed;
    1903       20272 :   pari_sp av = avma;
    1904             :   GEN g;
    1905       20272 :   if (best)
    1906             :   {
    1907       19397 :     ed = expo(embed_disc(v, d->r1, LOWDEFAULTPREC));
    1908       19397 :     avma = av; if (d->expo_best_disc < ed) return NULL;
    1909             :   }
    1910             :   else
    1911         875 :     ed = 0;
    1912       11683 :   g = get_pol(d, v);
    1913             :   /* accuracy too low, compute algebraically */
    1914       11683 :   if (!g) { avma = av; g = ZXQ_charpoly(*ai, T->x, varn(T->x)); }
    1915       11683 :   (void)ZX_gcd_all(g, ZX_deriv(g), &g);
    1916       11683 :   if (best && degpol(g) != degpol(T->x)) { avma = av; return NULL; }
    1917        4718 :   g = gerepilecopy(av, g);
    1918        4718 :   d->expo_best_disc = ed;
    1919        4718 :   if (flag & nf_ORIG)
    1920             :   {
    1921        1001 :     if (ZX_canon_neg(g)) *ai = RgX_neg(*ai);
    1922        1001 :     if (!isint1(T->unscale)) *ai = RgX_unscale(*ai, T->unscale);
    1923             :   }
    1924             :   else
    1925        3717 :     (void)ZX_canon_neg(g);
    1926        4718 :   if (DEBUGLEVEL>3) err_printf("polred: generator %Ps\n", g);
    1927        4718 :   return g;
    1928             : }
    1929             : 
    1930             : /* does x generate the correct field ? */
    1931             : static GEN
    1932       10593 : chk_gen(void *data, GEN x)
    1933             : {
    1934       10593 :   pari_sp av = avma, av1;
    1935       10593 :   GEN h, g = get_polchar((CG_data*)data,x);
    1936       10593 :   if (!g) pari_err_PREC("chk_gen");
    1937       10593 :   av1 = avma;
    1938       10593 :   h = ZX_gcd(g, ZX_deriv(g));
    1939       10593 :   if (degpol(h)) { avma = av; return NULL; }
    1940        6050 :   if (DEBUGLEVEL>3) err_printf("  generator: %Ps\n",g);
    1941        6050 :   avma = av1; return gerepileupto(av, g);
    1942             : }
    1943             : 
    1944             : static long
    1945        1456 : chk_gen_prec(long N, long bit)
    1946        1456 : { return nbits2prec(10 + (long)log2((double)N) + bit); }
    1947             : 
    1948             : /* Remove duplicate polynomials in P, updating A (same indices), in place.
    1949             :  * Among elements having the same characteristic pol, choose the smallest
    1950             :  * according to ZV_abscmp */
    1951             : static void
    1952         343 : remove_duplicates(GEN P, GEN A)
    1953             : {
    1954         343 :   long k, i, l = lg(P);
    1955         343 :   pari_sp av = avma;
    1956             :   GEN x, a;
    1957             : 
    1958         686 :   if (l < 2) return;
    1959         343 :   (void)sort_factor_pol(mkmat2(P, A), cmpii);
    1960         343 :   x = gel(P,1); a = gel(A,1);
    1961        6015 :   for  (k=1,i=2; i<l; i++)
    1962        5672 :     if (ZX_equal(gel(P,i), x))
    1963             :     {
    1964        3480 :       if (ZV_abscmp(gel(A,i), a) < 0) a = gel(A,i);
    1965             :     }
    1966             :     else
    1967             :     {
    1968        2192 :       gel(A,k) = a;
    1969        2192 :       gel(P,k) = x;
    1970        2192 :       k++;
    1971        2192 :       x = gel(P,i); a = gel(A,i);
    1972             :     }
    1973         343 :   l = k+1;
    1974         343 :   gel(A,k) = a; setlg(A,l);
    1975         343 :   gel(P,k) = x; setlg(P,l); avma = av;
    1976             : }
    1977             : 
    1978             : static long
    1979        1113 : polred_init(nfbasic_t *T, nffp_t *F, CG_data *d)
    1980             : {
    1981        1113 :   long e, prec, n = degpol(T->x);
    1982             :   double log2rho;
    1983             :   GEN ro;
    1984        1113 :   set_LLL_basis(T, &ro, 0.9999);
    1985             :   /* || polchar ||_oo < 2^e ~ 2 (n * rho)^n, rho = max modulus of root */
    1986        1113 :   log2rho = ro ? (double)gexpo(ro): fujiwara_bound(T->x);
    1987        1113 :   e = n * (long)(log2rho + log2((double)n)) + 1;
    1988        1113 :   if (e < 0) e = 0; /* can occur if n = 1 */
    1989        1113 :   prec = chk_gen_prec(n, e);
    1990        1113 :   get_nf_fp_compo(T, F, ro, 1, prec);
    1991        1113 :   d->v = varn(T->x);
    1992        1113 :   d->expo_best_disc = -1;
    1993        1113 :   d->ZKembed = NULL;
    1994        1113 :   d->M = NULL;
    1995        1113 :   d->u = NULL;
    1996        1113 :   d->r1= T->r1; return prec;
    1997             : }
    1998             : static GEN
    1999         350 : findmindisc(GEN y, GEN *pa)
    2000             : {
    2001         350 :   GEN a = *pa, x = gel(y,1), b = gel(a,1), dx = NULL;
    2002         350 :   long i, l = lg(y);
    2003         421 :   for (i = 2; i < l; i++)
    2004             :   {
    2005          71 :     GEN yi = gel(y,i);
    2006          71 :     if (ZX_is_better(yi,x,&dx)) { x = yi; b = gel(a,i); }
    2007             :   }
    2008         350 :   *pa = b; return x;
    2009             : }
    2010             : /* filter [y,b] from polred_aux: keep a single polynomial of degree n in y
    2011             :  * [ the best wrt discriminant ordering ], but keep all non-primitive
    2012             :  * polynomials */
    2013             : static void
    2014         770 : filter(GEN y, GEN b, long n)
    2015             : {
    2016             :   GEN x, a, dx;
    2017         770 :   long i, k = 1, l = lg(y);
    2018         770 :   a = x = dx = NULL;
    2019        5551 :   for (i = 1; i < l; i++)
    2020             :   {
    2021        4781 :     GEN yi = gel(y,i), ai = gel(b,i);
    2022        4781 :     if (degpol(yi) == n)
    2023             :     {
    2024        4613 :       pari_sp av = avma;
    2025        4613 :       if (dx && !ZX_is_better(yi,x,&dx)) { avma = av; continue; }
    2026        1085 :       if (!dx) dx = ZX_disc(yi);
    2027        1085 :       x = yi; a = ai; continue;
    2028             :     }
    2029         168 :     gel(y,k) = yi;
    2030         168 :     gel(b,k) = ai; k++;
    2031             :   }
    2032         770 :   if (dx)
    2033             :   {
    2034         770 :     gel(y,k) = x;
    2035         770 :     gel(b,k) = a; k++;
    2036             :   }
    2037         770 :   setlg(y, k);
    2038         770 :   setlg(b, k);
    2039         770 : }
    2040             : 
    2041             : static GEN
    2042         798 : polred_aux(nfbasic_t *T, GEN *pro, long flag)
    2043             : { /* only keep polynomials of max degree and best discriminant */
    2044         798 :   const long best = flag & nf_ABSOLUTE;
    2045         798 :   const long orig = flag & nf_ORIG;
    2046         798 :   GEN M, b, y, x = T->x;
    2047         798 :   long maxi, i, j, k, v = varn(x), n = lg(T->bas)-1;
    2048             :   nffp_t F;
    2049             :   CG_data d;
    2050             : 
    2051         798 :   if (n == 1)
    2052             :   {
    2053          28 :     if (!best)
    2054             :     {
    2055          14 :       GEN ch = deg1pol_shallow(gen_1, gen_m1, v);
    2056          14 :       return orig? mkmat2(mkcol(ch),mkcol(gen_1)): mkvec(ch);
    2057             :     }
    2058             :     else
    2059          14 :       return orig? trivial_fact(): cgetg(1,t_VEC);
    2060             :   }
    2061             : 
    2062         770 :   (void)polred_init(T, &F, &d);
    2063         770 :   *pro = F.ro;
    2064         770 :   M = F.M;
    2065         770 :   if (best)
    2066             :   {
    2067         707 :     if (!T->dx) T->dx = ZX_disc(T->x);
    2068         707 :     d.expo_best_disc = expi(T->dx);
    2069             :   }
    2070             : 
    2071             :   /* n + 2 sum_{1 <= i <= n} n-i = n + n(n-1) = n*n */
    2072         770 :   y = cgetg(n*n + 1, t_VEC);
    2073         770 :   b = cgetg(n*n + 1, t_COL);
    2074         770 :   k = 1;
    2075         770 :   if (!best)
    2076             :   {
    2077          63 :     GEN ch = deg1pol_shallow(gen_1, gen_m1, v);
    2078          63 :     gel(y,1) = ch; gel(b,1) = gen_1; k++;
    2079             :   }
    2080        4270 :   for (i = 2; i <= n; i++)
    2081             :   {
    2082             :     GEN ch, ai;
    2083        3500 :     ai = gel(T->bas,i);
    2084        3500 :     ch = try_polmin(&d, T, gel(M,i), flag, &ai);
    2085        3500 :     if (ch) { gel(y,k) = ch; gel(b,k) = ai; k++; }
    2086             :   }
    2087         770 :   maxi = minss(n, 3);
    2088        2884 :   for (i = 1; i <= maxi; i++)
    2089       10500 :     for (j = i+1; j <= n; j++)
    2090             :     {
    2091             :       GEN ch, ai, v;
    2092        8386 :       ai = gadd(gel(T->bas,i), gel(T->bas,j));
    2093        8386 :       v = RgV_add(gel(M,i), gel(M,j));
    2094             :       /* defining polynomial for Q(w_i+w_j) */
    2095        8386 :       ch = try_polmin(&d, T, v, flag, &ai);
    2096        8386 :       if (ch) { gel(y,k) = ch; gel(b,k) = ai; k++; }
    2097             : 
    2098        8386 :       ai = gsub(gel(T->bas,i), gel(T->bas,j));
    2099        8386 :       v = RgV_sub(gel(M,i), gel(M,j));
    2100             :       /* defining polynomial for Q(w_i-w_j) */
    2101        8386 :       ch = try_polmin(&d, T, v, flag, &ai);
    2102        8386 :       if (ch) { gel(y,k) = ch; gel(b,k) = ai; k++; }
    2103             :     }
    2104         770 :   setlg(y, k);
    2105         770 :   setlg(b, k); filter(y, b, n);
    2106         770 :   if (!orig) return gen_sort_uniq(y, (void*)cmpii, &gen_cmp_RgX);
    2107         147 :   (void)sort_factor_pol(mkmat2(y, b), cmpii);
    2108         147 :   settyp(y, t_COL); return mkmat2(b, y);
    2109             : }
    2110             : 
    2111             : static GEN
    2112          84 : Polred(GEN x, long flag, GEN fa)
    2113             : {
    2114          84 :   pari_sp av = avma;
    2115             :   GEN ro;
    2116          84 :   nfbasic_t T; nfbasic_init(fa? mkvec2(x,fa): x, flag & nf_PARTIALFACT, &T);
    2117          77 :   return gerepilecopy(av, polred_aux(&T, &ro, flag));
    2118             : }
    2119             : 
    2120             : /* finds "best" polynomial in polred_aux list, defaulting to T->x if none of
    2121             :  * them is primitive. *px is the ZX, characteristic polynomial of Mod(*pb,T->x),
    2122             :  * *pdx its discriminant. Set *pro = polroots(T->x) [ NOT *px ]. */
    2123             : static void
    2124         721 : polredbest_aux(nfbasic_t *T, GEN *pro, GEN *px, GEN *pdx, GEN *pb)
    2125             : {
    2126         721 :   GEN y, x = T->x; /* default value */
    2127             :   long i, l;
    2128         721 :   y = polred_aux(T, pro, pb? nf_ORIG|nf_ABSOLUTE: nf_ABSOLUTE);
    2129         721 :   *pdx = T->dx;
    2130         721 :   if (pb)
    2131             :   {
    2132         133 :     GEN a, b = deg1pol_shallow(T->unscale, gen_0, varn(x));
    2133         133 :     a = gel(y,1); l = lg(a);
    2134         133 :     y = gel(y,2);
    2135         259 :     for (i=1; i<l; i++)
    2136             :     {
    2137         126 :       GEN yi = gel(y,i);
    2138         126 :       pari_sp av = avma;
    2139         126 :       if (ZX_is_better(yi,x,pdx)) { x = yi; b = gel(a,i); } else avma = av;
    2140             :     }
    2141         133 :     *pb = b;
    2142             :   }
    2143             :   else
    2144             :   {
    2145         588 :     l = lg(y);
    2146        1169 :     for (i=1; i<l; i++)
    2147             :     {
    2148         581 :       GEN yi = gel(y,i);
    2149         581 :       pari_sp av = avma;
    2150         581 :       if (ZX_is_better(yi,x,pdx)) x = yi; else avma = av;
    2151             :     }
    2152             :   }
    2153         721 :   if (!*pdx) *pdx = ZX_disc(x);
    2154         721 :   *px = x;
    2155         721 : }
    2156             : GEN
    2157         616 : polredbest(GEN T0, long flag)
    2158             : {
    2159         616 :   pari_sp av = avma;
    2160             :   GEN T, dT, ro, a;
    2161             :   nfbasic_t S;
    2162         616 :   if (flag < 0 || flag > 1) pari_err_FLAG("polredbest");
    2163         616 :   T = T0; nfbasic_init(T, nf_PARTIALFACT, &S);
    2164         616 :   polredbest_aux(&S, &ro, &T, &dT, flag? &a: NULL);
    2165         616 :   if (flag)
    2166             :   { /* charpoly(Mod(a,T0)) = T */
    2167             :     GEN b;
    2168          28 :     if (T0 == T)
    2169           0 :       b = pol_x(varn(T)); /* no improvement */
    2170             :     else
    2171          28 :       b = QXQ_reverse(a, T0); /* charpoly(Mod(b,T)) = S.x */
    2172          28 :     b = (degpol(T) == 1)? gmodulo(b, T): mkpolmod(b,T);
    2173          28 :     T = mkvec2(T, b);
    2174             :   }
    2175         616 :   return gerepilecopy(av, T);
    2176             : }
    2177             : /* DEPRECATED: backward compatibility */
    2178             : GEN
    2179          70 : polred0(GEN x, long flag, GEN fa)
    2180             : {
    2181          70 :   long fl = 0;
    2182          70 :   if (flag & 1) fl |= nf_PARTIALFACT;
    2183          70 :   if (flag & 2) fl |= nf_ORIG;
    2184          70 :   return Polred(x, fl, fa);
    2185             : }
    2186             : 
    2187             : GEN
    2188          21 : polredord(GEN x)
    2189             : {
    2190          21 :   pari_sp av = avma;
    2191             :   GEN v, lt;
    2192             :   long i, n, vx;
    2193             : 
    2194          21 :   if (typ(x) != t_POL) pari_err_TYPE("polredord",x);
    2195          21 :   x = Q_primpart(x); RgX_check_ZX(x,"polredord");
    2196          21 :   n = degpol(x); if (n <= 0) pari_err_CONSTPOL("polredord");
    2197          21 :   if (n == 1) return gerepilecopy(av, mkvec(x));
    2198          14 :   lt = leading_coeff(x); vx = varn(x);
    2199          14 :   if (is_pm1(lt))
    2200             :   {
    2201           7 :     if (signe(lt) < 0) x = ZX_neg(x);
    2202           7 :     v = pol_x_powers(n, vx);
    2203             :   }
    2204             :   else
    2205             :   { GEN L;
    2206             :     /* basis for Dedekind order */
    2207           7 :     v = cgetg(n+1, t_VEC);
    2208           7 :     gel(v,1) = scalarpol_shallow(lt, vx);
    2209          14 :     for (i = 2; i <= n; i++)
    2210           7 :       gel(v,i) = RgX_Rg_add(RgX_mulXn(gel(v,i-1), 1), gel(x,n+3-i));
    2211           7 :     gel(v,1) = pol_1(vx);
    2212           7 :     x = ZX_Q_normalize(x, &L);
    2213           7 :     v = gsubst(v, vx, monomial(ginv(L),1,vx));
    2214          14 :     for (i=2; i <= n; i++)
    2215           7 :       if (Q_denom(gel(v,i)) == gen_1) gel(v,i) = monomial(gen_1, i-1, vx);
    2216             :   }
    2217          14 :   return gerepileupto(av, polred(mkvec2(x, v)));
    2218             : }
    2219             : 
    2220             : GEN
    2221          14 : polred(GEN x) { return Polred(x, 0, NULL); }
    2222             : GEN
    2223           0 : smallpolred(GEN x) { return Polred(x, nf_PARTIALFACT, NULL); }
    2224             : GEN
    2225           0 : factoredpolred(GEN x, GEN fa) { return Polred(x, 0, fa); }
    2226             : GEN
    2227           0 : polred2(GEN x) { return Polred(x, nf_ORIG, NULL); }
    2228             : GEN
    2229           0 : smallpolred2(GEN x) { return Polred(x, nf_PARTIALFACT|nf_ORIG, NULL); }
    2230             : GEN
    2231           0 : factoredpolred2(GEN x, GEN fa) { return Polred(x, nf_PARTIALFACT, fa); }
    2232             : 
    2233             : /********************************************************************/
    2234             : /**                                                                **/
    2235             : /**                           POLREDABS                            **/
    2236             : /**                                                                **/
    2237             : /********************************************************************/
    2238             : /* set V[k] := matrix of multiplication by nk.zk[k] */
    2239             : static GEN
    2240        1302 : set_mulid(GEN V, GEN M, GEN Mi, long r1, long r2, long N, long k)
    2241             : {
    2242        1302 :   GEN v, Mk = cgetg(N+1, t_MAT);
    2243             :   long i, e;
    2244        1302 :   for (i = 1; i < k; i++) gel(Mk,i) = gmael(V, i, k);
    2245       12320 :   for (     ; i <=N; i++)
    2246             :   {
    2247       11018 :     v = vecmul(gel(M,k), gel(M,i));
    2248       11018 :     v = RgM_RgC_mul(Mi, split_realimag(v, r1, r2));
    2249       11018 :     gel(Mk,i) = grndtoi(v, &e);
    2250       11018 :     if (e > -5) return NULL;
    2251             :   }
    2252        1302 :   gel(V,k) = Mk; return Mk;
    2253             : }
    2254             : 
    2255             : static GEN
    2256        1427 : ZM_image_shallow(GEN M, long *pr)
    2257             : {
    2258             :   long j, k, r;
    2259        1427 :   GEN y, d = ZM_pivots(M, &k);
    2260        1427 :   r = lg(M)-1 - k;
    2261        1427 :   y = cgetg(r+1,t_MAT);
    2262       10550 :   for (j=k=1; j<=r; k++)
    2263        9123 :     if (d[k]) gel(y,j++) = gel(M,k);
    2264        1427 :   *pr = r; return y;
    2265             : }
    2266             : 
    2267             : /* U = base change matrix, R = Cholesky form of the quadratic form [matrix
    2268             :  * Q from algo 2.7.6] */
    2269             : static GEN
    2270         351 : chk_gen_init(FP_chk_fun *chk, GEN R, GEN U)
    2271             : {
    2272         351 :   CG_data *d = (CG_data*)chk->data;
    2273             :   GEN P, V, D, inv, bound, S, M;
    2274         351 :   long N = lg(U)-1, r1 = d->r1, r2 = (N-r1)>>1;
    2275         351 :   long i, j, prec, firstprim = 0, skipfirst = 0;
    2276             :   pari_sp av;
    2277             : 
    2278         351 :   d->u = U;
    2279         351 :   d->ZKembed = M = RgM_mul(d->M, U);
    2280             : 
    2281         351 :   av = avma; bound = d->bound;
    2282         351 :   D = cgetg(N+1, t_VECSMALL);
    2283        2831 :   for (i = 1; i <= N; i++)
    2284             :   {
    2285        2488 :     pari_sp av2 = avma;
    2286        2488 :     P = get_pol(d, gel(M,i));
    2287        2488 :     if (!P) pari_err_PREC("chk_gen_init");
    2288        2480 :     (void)ZX_gcd_all(P, ZX_deriv(P), &P);
    2289        2480 :     P = gerepilecopy(av2, P);
    2290        2480 :     D[i] = degpol(P);
    2291        2480 :     if (D[i] == N)
    2292             :     { /* primitive element */
    2293        1030 :       GEN B = embed_T2(gel(M,i), r1);
    2294        1030 :       if (!firstprim) firstprim = i; /* index of first primitive element */
    2295        1030 :       if (DEBUGLEVEL>2) err_printf("chk_gen_init: generator %Ps\n",P);
    2296        1030 :       if (gcmp(B,bound) < 0) bound = gerepileuptoleaf(av2, B);
    2297             :     }
    2298             :     else
    2299             :     {
    2300        1450 :       if (DEBUGLEVEL>2) err_printf("chk_gen_init: subfield %Ps\n",P);
    2301        1450 :       if (firstprim)
    2302             :       { /* cycle basis vectors so that primitive elements come last */
    2303         159 :         GEN u = d->u, e = M;
    2304         159 :         GEN te = gel(e,i), tu = gel(u,i), tR = gel(R,i);
    2305         159 :         long tS = D[i];
    2306         447 :         for (j = i; j > firstprim; j--)
    2307             :         {
    2308         288 :           u[j] = u[j-1];
    2309         288 :           e[j] = e[j-1];
    2310         288 :           R[j] = R[j-1];
    2311         288 :           D[j] = D[j-1];
    2312             :         }
    2313         159 :         gel(u,firstprim) = tu;
    2314         159 :         gel(e,firstprim) = te;
    2315         159 :         gel(R,firstprim) = tR;
    2316         159 :         D[firstprim] = tS; firstprim++;
    2317             :       }
    2318             :     }
    2319             :   }
    2320         343 :   if (!firstprim)
    2321             :   { /* try (a little) to find primitive elements to improve bound */
    2322          21 :     GEN x = cgetg(N+1, t_VECSMALL);
    2323          21 :     if (DEBUGLEVEL>1)
    2324           0 :       err_printf("chk_gen_init: difficult field, trying random elements\n");
    2325         231 :     for (i = 0; i < 10; i++)
    2326             :     {
    2327             :       GEN e, B;
    2328         210 :       for (j = 1; j <= N; j++) x[j] = (long)random_Fl(7) - 3;
    2329         210 :       e = RgM_zc_mul(M, x);
    2330         210 :       B = embed_T2(e, r1);
    2331         210 :       if (gcmp(B,bound) >= 0) continue;
    2332          14 :       P = get_pol(d, e); if (!P) pari_err_PREC( "chk_gen_init");
    2333          14 :       if (!ZX_is_squarefree(P)) continue;
    2334          14 :       if (DEBUGLEVEL>2) err_printf("chk_gen_init: generator %Ps\n",P);
    2335          14 :       bound = B ;
    2336             :     }
    2337             :   }
    2338             : 
    2339         343 :   if (firstprim != 1)
    2340             :   {
    2341         343 :     inv = ginv( split_realimag(M, r1, r2) ); /*TODO: use QR?*/
    2342         343 :     V = gel(inv,1);
    2343         343 :     for (i = 2; i <= r1+r2; i++) V = gadd(V, gel(inv,i));
    2344             :     /* V corresponds to 1_Z */
    2345         343 :     V = grndtoi(V, &j);
    2346         343 :     if (j > -5) pari_err_BUG("precision too low in chk_gen_init");
    2347         343 :     S = mkmat(V); /* 1 */
    2348             : 
    2349         343 :     V = cgetg(N+1, t_VEC);
    2350        1456 :     for (i = 1; i <= N; i++,skipfirst++)
    2351             :     { /* S = Q-basis of subfield generated by nf.zk[1..i-1] */
    2352             :       GEN Mx, M2;
    2353        1456 :       long j, k, h, rkM, dP = D[i];
    2354             : 
    2355        1456 :       if (dP == N) break; /* primitive */
    2356        1302 :       Mx = set_mulid(V, M, inv, r1, r2, N, i);
    2357        1302 :       if (!Mx) break; /* prec. problem. Stop */
    2358        1302 :       if (dP == 1) continue;
    2359        1008 :       rkM = lg(S)-1;
    2360        1008 :       M2 = cgetg(N+1, t_MAT); /* we will add to S the elts of M2 */
    2361        1008 :       gel(M2,1) = col_ei(N, i); /* nf.zk[i] */
    2362        1008 :       k = 2;
    2363        3428 :       for (h = 1; h < dP; h++)
    2364             :       {
    2365             :         long r; /* add to M2 the elts of S * nf.zk[i]  */
    2366        1427 :         for (j = 1; j <= rkM; j++) gel(M2,k++) = ZM_ZC_mul(Mx, gel(S,j));
    2367        1427 :         setlg(M2, k); k = 1;
    2368        1427 :         S = ZM_image_shallow(shallowconcat(S,M2), &r);
    2369        2148 :         if (r == rkM) break;
    2370         895 :         if (r > rkM)
    2371             :         {
    2372         895 :           rkM = r;
    2373         895 :           if (rkM == N) break;
    2374             :         }
    2375             :       }
    2376        1008 :       if (rkM == N) break;
    2377             :       /* Q(w[1],...,w[i-1]) is a strict subfield of nf */
    2378             :     }
    2379             :   }
    2380             :   /* x_1,...,x_skipfirst generate a strict subfield [unless N=skipfirst=1] */
    2381         343 :   chk->skipfirst = skipfirst;
    2382         343 :   if (DEBUGLEVEL>2) err_printf("chk_gen_init: skipfirst = %ld\n",skipfirst);
    2383             : 
    2384             :   /* should be DEF + gexpo( max_k C^n_k (bound/k)^(k/2) ) */
    2385         343 :   bound = gerepileuptoleaf(av, bound);
    2386         343 :   prec = chk_gen_prec(N, (gexpo(bound)*N)/2);
    2387         343 :   if (DEBUGLEVEL)
    2388           0 :     err_printf("chk_gen_init: new prec = %ld (initially %ld)\n", prec, d->prec);
    2389         343 :   if (prec > d->prec) pari_err_BUG("polredabs (precision problem)");
    2390         343 :   if (prec < d->prec) d->ZKembed = gprec_w(M, prec);
    2391         343 :   return bound;
    2392             : }
    2393             : 
    2394             : /* z "small" minimal polynomial of Mod(a,x), deg z = deg x */
    2395             : static GEN
    2396        2478 : store(GEN x, GEN z, GEN a, nfbasic_t *T, long flag, GEN u)
    2397             : {
    2398             :   GEN y, b;
    2399             : 
    2400        2478 :   if (u) a = RgV_RgC_mul(T->bas, ZM_ZC_mul(u, a));
    2401        2478 :   if (flag & (nf_ORIG|nf_ADDZK))
    2402             :   {
    2403         245 :     b = QXQ_reverse(a, x);
    2404         245 :     if (!isint1(T->unscale)) b = gdiv(b, T->unscale); /* not RgX_Rg_div */
    2405             :   }
    2406             :   else
    2407        2233 :     b = NULL;
    2408             : 
    2409        2478 :   if (flag & nf_RAW)
    2410          28 :     y = mkvec2(z, a);
    2411        2450 :   else if (flag & nf_ORIG) /* store phi(b mod z). */
    2412         245 :     y = mkvec2(z, mkpolmod(b,z));
    2413             :   else
    2414        2205 :     y = z;
    2415        2478 :   if (flag & nf_ADDZK)
    2416             :   { /* append integral basis for number field Q[X]/(z) to result */
    2417           0 :     long n = degpol(x);
    2418           0 :     GEN t = RgV_RgM_mul(RgXQ_powers(b, n-1, z), RgV_to_RgM(T->bas,n));
    2419           0 :     y = mkvec2(y, t);
    2420             :   }
    2421        2478 :   return y;
    2422             : }
    2423             : static GEN
    2424         343 : polredabs_aux(nfbasic_t *T, GEN *u)
    2425             : {
    2426             :   long prec;
    2427             :   GEN v;
    2428         343 :   FP_chk_fun chk = { &chk_gen, &chk_gen_init, NULL, NULL, 0 };
    2429             :   nffp_t F;
    2430         343 :   CG_data d; chk.data = (void*)&d;
    2431             : 
    2432         343 :   prec = polred_init(T, &F, &d);
    2433         343 :   d.bound = embed_T2(F.ro, d.r1);
    2434         343 :   if (realprec(d.bound) > prec) d.bound = rtor(d.bound, prec);
    2435             :   for (;;)
    2436             :   {
    2437         363 :     GEN R = R_from_QR(F.G, prec);
    2438         363 :     if (R)
    2439             :     {
    2440         351 :       d.prec = prec;
    2441         351 :       d.M    = F.M;
    2442         351 :       v = fincke_pohst(mkvec(R),NULL,-1, 0, &chk);
    2443         351 :       if (v) break;
    2444             :     }
    2445          20 :     prec = precdbl(prec);
    2446          20 :     get_nf_fp_compo(T, &F, NULL, 1, prec);
    2447          20 :     if (DEBUGLEVEL) pari_warn(warnprec,"polredabs0",prec);
    2448          20 :   }
    2449         343 :   *u = d.u; return v;
    2450             : }
    2451             : 
    2452             : GEN
    2453         357 : polredabs0(GEN x, long flag)
    2454             : {
    2455         357 :   pari_sp av = avma;
    2456             :   long i, l, vx;
    2457             :   GEN y, a, u;
    2458             :   nfbasic_t T;
    2459             : 
    2460         357 :   nfbasic_init(x, nf_PARTIALFACT, &T);
    2461         357 :   x = T.x; vx = varn(x);
    2462             : 
    2463         357 :   if (degpol(x) == 1)
    2464             :   {
    2465          14 :     u = NULL;
    2466          14 :     y = mkvec( pol_x(vx) );
    2467          14 :     a = mkvec( deg1pol_shallow(gen_1, negi(gel(x,2)), vx) );
    2468          14 :     l = 2;
    2469             :   }
    2470             :   else
    2471             :   {
    2472             :     GEN v;
    2473         343 :     if (!(flag & nf_PARTIALFACT) && T.dKP)
    2474             :     {
    2475          84 :       GEN vw = primes_certify(T.dK, T.dKP);
    2476          84 :       v = gel(vw,1); l = lg(v);
    2477          84 :       if (l != 1)
    2478             :       { /* fix integral basis */
    2479           7 :         GEN w = gel(vw,2);
    2480          14 :         for (i = 1; i < l; i++)
    2481           7 :           w = ZV_union_shallow(w, gel(Z_factor(gel(v,i)),1));
    2482           7 :         nfbasic_init(mkvec2(x,w), 0, &T);
    2483             :       }
    2484             :     }
    2485         343 :     v = polredabs_aux(&T, &u);
    2486         343 :     y = gel(v,1);
    2487         343 :     a = gel(v,2); l = lg(a);
    2488        6358 :     for (i=1; i<l; i++)
    2489        6015 :       if (ZX_canon_neg(gel(y,i))) gel(a,i) = ZC_neg(gel(a,i));
    2490         343 :     remove_duplicates(y,a);
    2491         343 :     l = lg(a);
    2492         343 :     if (l == 1)
    2493           0 :       pari_err_BUG("polredabs (missing vector)");
    2494             :   }
    2495         357 :   if (DEBUGLEVEL) err_printf("Found %ld minimal polynomials.\n",l-1);
    2496         357 :   if (flag & nf_ALL) {
    2497           7 :     for (i=1; i<l; i++) gel(y,i) = store(x, gel(y,i), gel(a,i), &T, flag, u);
    2498             :   } else {
    2499         350 :     GEN z = findmindisc(y, &a);
    2500         350 :     y = store(x, z, a, &T, flag, u);
    2501             :   }
    2502         357 :   return gerepilecopy(av, y);
    2503             : }
    2504             : 
    2505             : GEN
    2506           0 : polredabsall(GEN x, long flun) { return polredabs0(x, flun | nf_ALL); }
    2507             : GEN
    2508           0 : polredabs(GEN x) { return polredabs0(x,0); }
    2509             : GEN
    2510           0 : polredabs2(GEN x) { return polredabs0(x,nf_ORIG); }
    2511             : 
    2512             : /* relative polredabs/best. Returns relative polynomial by default (flag = 0)
    2513             :  * flag & nf_ORIG: + element (base change)
    2514             :  * flag & nf_ABSOLUTE: absolute polynomial */
    2515             : static GEN
    2516          63 : rnfpolred_i(GEN nf, GEN relpol, long flag, long best)
    2517             : {
    2518          63 :   const char *f = best? "rnfpolredbest": "rnfpolredabs";
    2519          63 :   const long abs = ((flag & nf_ORIG) && (flag & nf_ABSOLUTE));
    2520             :   pari_timer ti;
    2521          63 :   GEN listP = NULL, red, bas, A, P, pol, T, rnfeq;
    2522          63 :   long ty = typ(relpol);
    2523          63 :   pari_sp av = avma;
    2524             : 
    2525          63 :   if (ty == t_VEC) {
    2526          14 :     if (lg(relpol) != 3) pari_err_TYPE(f,relpol);
    2527          14 :     listP = gel(relpol,2);
    2528          14 :     relpol = gel(relpol,1);
    2529             :   }
    2530          63 :   if (typ(relpol) != t_POL) pari_err_TYPE(f,relpol);
    2531          63 :   nf = checknf(nf);
    2532          63 :   if (DEBUGLEVEL>1) timer_start(&ti);
    2533          63 :   T = nf_get_pol(nf);
    2534          63 :   relpol = RgX_nffix(f, T, relpol, 0);
    2535          63 :   if (best || (flag & nf_PARTIALFACT))
    2536             :   {
    2537          42 :     if (abs)
    2538             :     {
    2539           7 :       rnfeq = nf_rnfeq(nf, relpol);
    2540           7 :       pol = gel(rnfeq,1);
    2541             :     }
    2542             :     else
    2543             :     {
    2544             :       long sa;
    2545          35 :       pol = rnfequationall(nf, relpol, &sa, NULL);
    2546          35 :       rnfeq = mkvec5(gen_0,gen_0,stoi(sa),T,liftpol_shallow(relpol));
    2547             :     }
    2548          42 :     bas = listP? mkvec2(pol, listP): pol;
    2549          84 :     if (best)
    2550             :     {
    2551          35 :       if (abs) red = polredbest(bas, 1);
    2552             :       else
    2553             :       {
    2554             :         GEN ro, x, dx, a;
    2555             :         nfbasic_t T;
    2556          28 :         nfbasic_init(bas, nf_PARTIALFACT, &T);
    2557          28 :         polredbest_aux(&T, &ro, &x, &dx, &a);
    2558          28 :         red = mkvec2(x, a);
    2559             :       }
    2560             :     }
    2561             :     else
    2562           7 :       red = polredabs0(bas, (abs? nf_ORIG: nf_RAW)|nf_PARTIALFACT);
    2563             :   }
    2564             :   else
    2565             :   {
    2566          21 :     GEN rnf = rnfinit(nf, relpol), M = rnf_basM(rnf);
    2567          21 :     rnfeq = rnf_get_map(rnf);
    2568          21 :     pol = rnf_get_polabs(rnf);
    2569          21 :     bas = mkvec2(pol, RgM_to_RgXV(M, varn(pol)));
    2570          21 :     if (DEBUGLEVEL>1) timer_printf(&ti, "absolute basis");
    2571          21 :     red = polredabs0(bas, nf_RAW);
    2572             :   }
    2573          63 :   P = gel(red,1);
    2574          63 :   A = gel(red,2);
    2575          63 :   if (DEBUGLEVEL>1) err_printf("reduced absolute generator: %Ps\n",P);
    2576          63 :   if (flag & nf_ABSOLUTE)
    2577             :   {
    2578          14 :     if (flag & nf_ORIG)
    2579             :     {
    2580           7 :       GEN a = gel(rnfeq,2); /* Mod(a,pol) root of T */
    2581           7 :       GEN k = gel(rnfeq,3); /* Mod(variable(relpol),relpol) + k*a root of pol */
    2582           7 :       a = RgX_RgXQ_eval(a, lift_intern(A), P); /* Mod(a, P) root of T */
    2583           7 :       P = mkvec3(P, mkpolmod(a,P), gsub(A, gmul(k,a)));
    2584             :     }
    2585          14 :     return gerepilecopy(av, P);
    2586             :   }
    2587          49 :   A = eltabstorel_lift(rnfeq, A);
    2588          49 :   P = RgXQ_charpoly(A, relpol, varn(relpol));
    2589          49 :   P = lift_if_rational(P);
    2590          49 :   if (flag & nf_ORIG) P = mkvec2(P, mkpolmod(RgXQ_reverse(A,relpol),P));
    2591          49 :   return gerepilecopy(av, P);
    2592             : }
    2593             : GEN
    2594          28 : rnfpolredabs(GEN nf, GEN relpol, long flag)
    2595          28 : { return rnfpolred_i(nf,relpol,flag, 0); }
    2596             : GEN
    2597          35 : rnfpolredbest(GEN nf, GEN relpol, long flag)
    2598             : {
    2599          35 :   if (flag < 0 || flag > 3) pari_err_FLAG("rnfpolredbest");
    2600          35 :   return rnfpolred_i(nf,relpol,flag, 1);
    2601             : }

Generated by: LCOV version 1.11