Code coverage tests

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

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

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

LCOV - code coverage report
Current view: top level - basemath - factcyclo.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.18.0 lcov report (development 29818-b3e15d99d2) Lines: 916 1079 84.9 %
Date: 2024-12-27 09:09:37 Functions: 77 85 90.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 2000, 2012  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             : /* written by Takashi Fukuda
      15             :  *  2019.10.27 : Flx_factcyclo_gen, FpX_factcyclo_gen
      16             :  *  2019.10.28 : Flx_factcyclo_lift, FpX_factcyclo_lift
      17             :  *  2019.11.3  : Flx_factcyclo_newton, FpX_factcyclo_newton
      18             :  *  2019.11.12 : gausspol for prime
      19             :  *  2019.11.13 : gausspol for prime power
      20             :  *  2019.11.14 : ZpX_roots_nonsep with ZX_Zp_root
      21             :  *  2019.11.15 : test ZpX_roots_nonsep with polrootspadic
      22             :  *  2019.11.16 : accept variable number
      23             :  *  2019.11.17 : gen_ascent
      24             :  *  2019.11.20 : ZpX_roots_nonsep with FpX_roots
      25             :  *  2021.7.19  : Flx_factcyclo_newton_general
      26             :  *  2021.7.22  : Flx_conductor_lift */
      27             : 
      28             : #include "pari.h"
      29             : #include "paripriv.h"
      30             : 
      31             : #define DEBUGLEVEL DEBUGLEVEL_factcyclo
      32             : 
      33             : #define GENERAL            1
      34             : #define NEWTON_POWER       2
      35             : #define NEWTON_GENERAL     4
      36             : #define NEWTON_GENERAL_NEW 8
      37             : #define ASCENT            16
      38             : 
      39             : #define Flx_polcyclo(n, p) ZX_to_Flx(polcyclo(n, 0), p)
      40             : #define FpX_polcyclo(n, p) FpX_red(polcyclo(n, 0), p)
      41             : 
      42             : /* 0 <= z[i] <= ULONG_MAX */
      43             : static GEN
      44           0 : ZX_to_nx(GEN z)
      45             : {
      46           0 :   long i, r = lg(z);
      47           0 :   GEN x = cgetg(r, t_VECSMALL);
      48           0 :   x[1] = ((ulong) z[1])&VARNBITS;
      49           0 :   for (i = 2; i < r; i++) x[i] = itou(gel(z, i));
      50           0 :   return x;
      51             : }
      52             : 
      53             : static long
      54       92826 : QX_den_pval(GEN x, GEN p)
      55             : {
      56       92826 :   long i, vmax = 0, l = lg(x);
      57      334882 :   for (i = 2; i < l; i++)
      58             :   {
      59      242056 :     GEN z = gel(x, i);
      60             :     long v;
      61      242056 :     if (typ(z)==t_FRAC && (v = Z_pval(gel(z, 2), p)) > vmax) vmax = v;
      62             :   }
      63       92826 :   return vmax;
      64             : }
      65             : 
      66             : static long
      67       15807 : QXV_den_pval(GEN vT, GEN kT, GEN p)
      68             : {
      69       15807 :   long k, vmax = 0, l = lg(kT);
      70       75173 :   for (k = 1; k < l; k++)
      71             :   {
      72       59366 :     long v = QX_den_pval(gel(vT, kT[k]), p);
      73       59366 :     if (v > vmax) vmax = v;
      74             :   }
      75       15807 :   return vmax;
      76             : }
      77             : 
      78             : /* n=el^e, p^d=1 (mod n), d is in [1,el-1], phi(n)=d*f.
      79             :  *  E[i] : 1 <= i <= n-1
      80             :  *  E[g^i*p^j mod n] = i+1  (0 <= i <= f-1, 0 <= j <= d-1)
      81             :  *  We use E[i] (1 <= i <= d). Namely i < el. */
      82             : static GEN
      83       33460 : set_E(long pmodn, long n, long d, long f, long g)
      84             : {
      85             :   long i, j;
      86       33460 :   GEN E = const_vecsmall(n-1, 0);
      87       33460 :   pari_sp av = avma;
      88       33460 :   GEN C = Fl_powers(g, f-1, n);
      89      121856 :   for (i = 1; i <= f; i++)
      90             :   {
      91       88396 :     ulong x = C[i];
      92     1239140 :     for (j = 1; j <= d; j++) { x = Fl_mul(x, pmodn, n); E[x] = i; }
      93             :   }
      94       33460 :   return gc_const(av, E);
      95             : }
      96             : 
      97             : /* x1, x2 of the same degree; gcd(p1,p2) = 1, m = p1*p2, m2 = m >> 1*/
      98             : static GEN
      99           0 : ZX_chinese_center(GEN x1, GEN p1, GEN x2, GEN p2, GEN m, GEN m2)
     100             : {
     101           0 :   long i, l = lg(x1);
     102           0 :   GEN x = cgetg(l, t_POL);
     103             :   GEN y1, y2, q1, q2;
     104           0 :   (void)bezout(p1, p2, &q1, &q2);
     105           0 :   y1 = Fp_mul(p2, q2, m);
     106           0 :   y2 = Fp_mul(p1, q1, m);
     107           0 :   for (i = 2; i < l; i++)
     108             :   {
     109           0 :     GEN y = Fp_add(mulii(gel(x1, i), y1), mulii(gel(x2, i), y2), m);
     110           0 :     if (cmpii(y, m2) > 0) y = subii(y, m);
     111           0 :     gel(x, i) = y;
     112             :   }
     113           0 :   x[1] = x1[1]; return x;
     114             : }
     115             : 
     116             : /* find n_el primes el such that el=1 (mod n) and el does not divide d(T) */
     117             : static GEN
     118       98534 : list_el_n(ulong el0, ulong n, GEN d1, long n_el)
     119             : {
     120       98534 :   GEN v = cgetg(n_el + 1, t_VECSMALL);
     121             :   forprime_t T;
     122             :   long i;
     123       98534 :   u_forprime_arith_init(&T, el0+n, ULONG_MAX, 1, n);
     124      247044 :   for (i = 1; i <= n_el; i++)
     125             :   {
     126             :     ulong el;
     127      148510 :     do el = u_forprime_next(&T); while (dvdiu(d1, el));
     128      148510 :     v[i] = el;
     129             :   }
     130       98534 :   return v;
     131             : }
     132             : 
     133             : /* return min el s.t. 2^63<el and el=1 (mod n). */
     134             : static ulong
     135       49267 : start_el_n(ulong n)
     136             : {
     137       49267 :   ulong MAXHLONG = 1UL<<(BITS_IN_LONG-1), el = (MAXHLONG/n)*n + 1;
     138       49267 :   if ((el&1)==0) el += n; /* if el is even, then n is odd */
     139       49267 :   return el + (n << 1);
     140             : }
     141             : 
     142             : /* start probably catches d0*T_k(x). So small second is enough. */
     143             : static ulong
     144       49267 : get_n_el(GEN d0, ulong *psec)
     145             : {
     146       49267 :   ulong start = ((lgefint(d0)-2)*BITS_IN_LONG)/(BITS_IN_LONG-1)+1, second = 1;
     147       49267 :   if (start>10) second++;
     148       49267 :   if (start>100)  { start++; second++; }
     149       49267 :   if (start>500)  { start++; second++; }
     150       49267 :   if (start>1000) { start++; second++; }
     151       49267 :   *psec = second; return start;
     152             : }
     153             : 
     154             : static long
     155       77072 : FpX_degsub(GEN P, GEN Q, GEN p)
     156             : {
     157       77072 :   pari_sp av = avma;
     158       77072 :   long d = degpol(FpX_sub(P, Q, p));
     159       77072 :   return gc_long(av, d);
     160             : }
     161             : 
     162             : /* n=odd prime power, F=Q(zeta_n), G=G(F/Q)=(Z/nZ)^*, H=<p>, K <--> H,
     163             :  * t_k=Tr_{F/K}(zeta_n^k), T=minimal pol. of t_1 over Q.
     164             :  * g is a given generator of G(K/Q).
     165             :  * There exists a unique G(x) in Q[x] s.t. t_g=G(t_1).
     166             :  * return G(x) mod el assuming that el does not divide d(T), in which case
     167             :  * T(x) is separable over F_el and so Vandermonde mod el is regular. */
     168             : static GEN
     169      100456 : gausspol_el(GEN H, ulong n, ulong d, ulong f, ulong g, ulong el)
     170             : {
     171      100456 :   ulong j, k, z_n = rootsof1_Fl(n, el);
     172      100456 :   GEN vz_n, L = cgetg(1+f, t_VECSMALL), x = cgetg(1+f, t_VECSMALL), X;
     173             : 
     174      100456 :   vz_n = Fl_powers(z_n, n-1, el)+1;
     175      366316 :   for (k = 0; k < f; k++)
     176             :   {
     177      265860 :     ulong gk = Fl_powu(g, k, n), t = 0;
     178     3725628 :     for (j = 1; j <= d; j++)
     179     3459768 :       t = Fl_add(t, vz_n[Fl_mul(H[j], gk, n)], el);
     180      265860 :     L[1+k] = t;
     181      265860 :     x[1+(k+f-1)%f] = t;
     182             :   }
     183      100456 :   X = Flv_invVandermonde(L, 1, el);
     184      100456 :   return Flv_to_Flx(Flm_Flc_mul(X, x, el), 0);
     185             : }
     186             : 
     187             : static GEN
     188       66920 : get_G(GEN H, GEN d0, GEN d1, GEN N, long k, ulong *pel, GEN *pM)
     189             : {
     190       66920 :   long n = N[1], d = N[2], f = N[3], g = N[4], i;
     191       66920 :   GEN POL = cgetg(1+k, t_VEC), EL, G, M, x;
     192             :   pari_timer ti;
     193             : 
     194       66920 :   if (DEBUGLEVEL >= 6) timer_start(&ti);
     195       66920 :   EL = list_el_n(*pel, n, d1, k);
     196      167376 :   for (i = 1; i <= k; i++)
     197             :   {
     198      100456 :     ulong el = uel(EL,i);
     199      100456 :     x = gausspol_el(H, n, d, f, g, el);
     200      100456 :     gel(POL, i) = Flx_Fl_mul(x, umodiu(d0, el), el);
     201             :   }
     202       66920 :   if (DEBUGLEVEL >= 6) timer_printf(&ti, "get_G : make data k=%ld",k);
     203       66920 :   G = nxV_chinese_center(POL, EL, &M);
     204       66920 :   if (DEBUGLEVEL >= 6) timer_printf(&ti, "get_G : nxV_chinese_center k=%ld",k);
     205       66920 :   *pel = EL[k]; *pM = M; return G;
     206             : }
     207             : 
     208             : static long
     209           0 : Q_size(GEN z)
     210             : {
     211           0 :   if (typ(z)==t_INT) return lgefint(z) - 2;
     212           0 :   return maxss(lgefint(gel(z,1)), lgefint(gel(z,2))) - 2;
     213             : }
     214             : /* return max log_a(|x[i]|), a=2^(BITS_IN_LONG-1) */
     215             : static long
     216           0 : ZX_size(GEN x)
     217             : {
     218           0 :   long i, l = lg(x), max = 0;
     219           0 :   for (i = 2; i < l; i++)
     220             :   {
     221           0 :     long y = lgefint(gel(x,i)) - 2;
     222           0 :     if (y > max) max = y;
     223             :   }
     224           0 :   return max;
     225             : }
     226             : 
     227             : /* d0 is a multiple of (O_K:Z[t_1]). i.e. d0*T_k(x) is in Z[x].
     228             :  * d1 has the same prime factors as d(T); d0 d1 = d(T)^2 */
     229             : static GEN
     230       49267 : get_d0_d1(GEN T, GEN P)
     231             : {
     232       49267 :   long i, l = lg(P);
     233       49267 :   GEN x, y, dT = ZX_disc(T);
     234       49267 :   x = y = dT; setsigne(dT, 1);
     235      114451 :   for (i = 1; i < l; i++)
     236       65184 :     if (odd(Z_lvalrem(dT, P[i], &dT)))
     237             :     {
     238       50739 :       x = diviuexact(x, P[i]);
     239       50739 :       y = muliu(y, P[i]);
     240             :     }
     241       49267 :   return mkvec2(sqrti(x), sqrti(y));  /* x and y are square */
     242             : }
     243             : 
     244             : static GEN
     245       33460 : gausspol(GEN T, GEN H, GEN N, ulong d, ulong f, ulong g)
     246             : {
     247       33460 :   long n = N[1], el0 = N[2];
     248       33460 :   GEN F, G1, M1, d0, d1, Data, d0d1 = get_d0_d1(T, mkvecsmall(el0));
     249             :   ulong el, n_el, start, second;
     250             :   pari_timer ti;
     251             : 
     252       33460 :   d0 = gel(d0d1,1); /* d0*F is in Z[X] */
     253       33460 :   d1 = gel(d0d1,2); /* d1 has same prime factors as disc(T) */
     254       33460 :   Data = mkvecsmall4(n, d, f, g);
     255       33460 :   start = get_n_el(d0, &second);
     256       33460 :   el = start_el_n(n);
     257             : 
     258       33460 :   if (DEBUGLEVEL >= 6) timer_start(&ti);
     259       33460 :   if (DEBUGLEVEL == 2) err_printf("gausspol:start=(%ld,%ld)\n",start,second);
     260       33460 :   G1 = get_G(H, d0, d1, Data, start, &el, &M1);
     261       33460 :   for (n_el=second; n_el; n_el++)
     262             :   {
     263             :     GEN m, G2, M2;
     264       33460 :     G2 = get_G(H, d0, d1, Data, n_el, &el, &M2);
     265       33460 :     if (FpX_degsub(G1, G2, M2) < 0) break;  /* G1 = G2 (mod M2) */
     266           0 :     if (DEBUGLEVEL == 2)
     267           0 :       err_printf("G1:%ld, G2:%ld\n",ZX_size(G1), ZX_size(G2));
     268           0 :     if (DEBUGLEVEL >= 6) timer_start(&ti);
     269           0 :     m = mulii(M1, M2);
     270           0 :     G2 = ZX_chinese_center(G1, M1, G2, M2, m, shifti(m,-1));
     271           0 :     if (DEBUGLEVEL >= 6) timer_printf(&ti, "ZX_chinese_center");
     272           0 :     G1 = G2; M1 = m;
     273             :   }
     274       33460 :   F = RgX_Rg_div(G1, d0);
     275       33460 :   if (DEBUGLEVEL == 2)
     276           0 :     err_printf("G1:%ld, d0:%ld, M1:%ld, F:%ld\n",
     277             :                ZX_size(G1), Q_size(d0), Q_size(M1), ZX_size(F));
     278       33460 :   if (DEBUGLEVEL >= 6) timer_printf(&ti, "gausspol");
     279       33460 :   return F;
     280             : }
     281             : 
     282             : /* Data = [H, GH, i_t, d0d1, kT, [n, d, f, n_T, mitk]]
     283             :  * v_t_el[k]=t_k mod el, 1<= k <= n-1 */
     284             : static GEN
     285       48054 : mk_v_t_el(GEN vT, GEN Data, ulong el)
     286             : {
     287       48054 :   pari_sp av = avma;
     288       48054 :   GEN H = gel(Data, 1), GH = gel(Data,2), i_t = gel(Data, 3), N=gel(Data, 6);
     289       48054 :   ulong n = N[1],  d = N[2], mitk = N[5], f = N[3], i, k;
     290       48054 :   ulong z_n = rootsof1_Fl(n, el);
     291       48054 :   GEN vz_n = Fl_powers(z_n, n-1, el)+1;
     292       48054 :   GEN v_t_el = const_vecsmall(n-1, 0);
     293             : 
     294      348257 :   for (k = 1; k <= mitk; k++)
     295             :   {
     296      300203 :     if (k > 1 && !isintzero(gel(vT, k))) continue; /* k=1 is always handled */
     297     2222451 :     for (i=1; i<=f; i++)
     298             :     {
     299     1922248 :       ulong j, t = 0, x = Fl_mul(k, GH[i], n);
     300     1922248 :       long y = i_t[x]; /* x!=0, y!=0 */
     301     1922248 :       if (v_t_el[y]) continue;
     302     5435404 :       for (j = 1; j <= d; j++) t = Fl_add(t, vz_n[Fl_mul(x, H[j], n)], el);
     303      262980 :       v_t_el[y] = t;
     304             :     }
     305             :   }
     306       48054 :   return gerepileuptoleaf(av, v_t_el);
     307             : }
     308             : 
     309             : /* G=[[G_1,...,G_d],M,el]
     310             :  * Data = [H, GH, i_t, d0d1, kT, [n, d, f, n_T, mitk]] */
     311             : static GEN
     312       31614 : get_vG(GEN vT, GEN Data, long n_el, ulong *pel, GEN *pM)
     313             : {
     314       31614 :   GEN GH = gel(Data, 2), i_t = gel(Data, 3);
     315       31614 :   GEN d0 = gmael(Data, 4, 1), d1 = gmael(Data, 4, 2);
     316       31614 :   GEN kT = gel(Data, 5), N = gel(Data, 6);
     317       31614 :   long n = N[1], f = N[3], n_T = N[4], mitk = N[5];
     318       31614 :   GEN G = const_vec(mitk, gen_0), vPOL = cgetg(1+mitk, t_VEC);
     319             :   GEN EL, M, X, v_t_el;
     320       31614 :   GEN L = cgetg(1+f, t_VECSMALL), x = cgetg(1+f, t_VECSMALL);
     321             :   long i, j, k;
     322             : 
     323      216870 :   for (k=1; k<=mitk; k++) gel(vPOL, k) = cgetg(1+n_el, t_VEC);
     324       31614 :   EL = list_el_n(*pel, n, d1, n_el);
     325       79668 :   for (i=1; i<=n_el; i++)
     326             :   {
     327       48054 :     ulong el = uel(EL,i), d0model = umodiu(d0, el);
     328       48054 :     v_t_el = mk_v_t_el(vT, Data, el);
     329      214716 :     for (j = 1; j <= f; j++) L[j] = v_t_el[i_t[GH[j]]];
     330       48054 :     X = Flv_invVandermonde(L, 1, el);
     331      229086 :     for (k = 1; k <= n_T; k++)
     332             :     {
     333             :       GEN y;
     334      181032 :       long itk = kT[k];
     335      181032 :       if (!isintzero(gel(vT, itk))) continue;
     336      700581 :       for (j = 1; j <= f; j++) x[j] = v_t_el[i_t[Fl_mul(itk, GH[j], n)]];
     337      133705 :       y = Flv_to_Flx(Flm_Flc_mul(X, x, el), 0);
     338      133705 :       gmael(vPOL, itk, i) = Flx_Fl_mul(y, d0model, el);
     339             :     }
     340             :   }
     341      150346 :   for (k = 1; k <= n_T; k++)
     342             :   {
     343      118732 :     long itk = kT[k];
     344      118732 :     if (!isintzero(gel(vT, itk))) continue;
     345       87224 :     gel(G, itk) = nxV_chinese_center(gel(vPOL, itk), EL, &M);
     346             :   }
     347       31614 :   *pel = EL[n_el]; *pM = M; return G;
     348             : }
     349             : 
     350             : /* F=Q(zeta_n), H=<p> in (Z/nZ)^*, K<-->H, t_k=Tr_{F/K}(zeta_n^k).
     351             :  * i_t[i]=k ==> iH=kH, i.e. t_i=t_k. We use t_k instead of t_i:
     352             :  * the number of k << the number of i. */
     353             : static GEN
     354       15807 : get_i_t(long n, long p)
     355             : {
     356             :   long a;
     357       15807 :   GEN v_t = const_vecsmall(n-1, 0);
     358       15807 :   GEN i_t = cgetg(n, t_VECSMALL);  /* access i_t[a] with 1 <= a <= n-1 */
     359      118319 :   for (a = 1; a < n; a++)
     360             :   {
     361             :     long b;
     362      854693 :     while (a < n && v_t[a]) a++;
     363      118319 :     if (a==n) break;
     364      102512 :     b = a;
     365      838886 :     do { v_t[b] = 1; i_t[b] = a; b = Fl_mul(b, p, n); } while (b != a);
     366             :   }
     367       15807 :   return i_t;
     368             : }
     369             : 
     370             : /* get T_k(x) 1<= k <= d. d0*T_k(x) is in Z[x].
     371             :  * T_0(x)=T_n(x)=f.
     372             :  * Data = [H, GH, i_t, d0d1, kT, [n, d, f, n_T, mitk]] */
     373             : static GEN
     374       15807 : get_vT(GEN Data, int NEW)
     375             : {
     376       15807 :   pari_sp av = avma;
     377       15807 :   GEN d0 = gmael(Data, 4, 1), kT = gel(Data, 5), N = gel(Data, 6);
     378       15807 :   ulong k, n = N[1], n_T = N[4], mitk = N[5];
     379       15807 :   GEN G1, M1, vT = const_vec(mitk, gen_0); /* vT[k]!=NULL ==> vT[k]=T_k */
     380       15807 :   ulong n_k = 0, el, n_el, start, second;
     381             :   pari_timer ti;
     382             : 
     383       15807 :   if (DEBUGLEVEL >= 6) timer_start(&ti);
     384       15807 :   if (!NEW) { gel(vT, 1) = pol_x(0); n_k++; }
     385       15807 :   start = get_n_el(d0, &second);
     386       15807 :   el = start_el_n(n);
     387       15807 :   if (DEBUGLEVEL == 2) err_printf("get_vT: start=(%ld,%ld)\n",start,second);
     388       15807 :   G1 = get_vG(vT, Data, start, &el, &M1);
     389       15807 :   for (n_el = second;; n_el++)
     390           0 :   {
     391             :     GEN G2, M2, m, m2;
     392       15807 :     G2 = get_vG(vT, Data, n_el, &el, &M2);
     393       15807 :     m = mulii(M1, M2); m2 = shifti(m,-1);
     394       75173 :     for (k = 1; k <= n_T; k++)
     395             :     {
     396       59366 :       long j = kT[k];
     397       59366 :       if (!isintzero(gel(vT,j))) continue;
     398       43612 :       if (FpX_degsub(gel(G1,j), gel(G2,j), M2) < 0) /* G1=G2 (mod M2) */
     399             :       {
     400       43612 :         gel(vT,j) = RgX_Rg_div(gel(G1,j), d0);
     401       43612 :         n_k++;
     402       43612 :         if (DEBUGLEVEL == 2)
     403           0 :           err_printf("G1:%ld, d0:%ld, M1:%ld, vT[%ld]:%ld words\n",
     404           0 :             ZX_size(gel(G1,j)), Q_size(d0), Q_size(M1), j, ZX_size(gel(vT,j)));
     405             :       }
     406             :       else
     407             :       {
     408           0 :         if (DEBUGLEVEL == 2)
     409           0 :           err_printf("G1:%ld, G2:%ld\n", ZX_size(gel(G1,j)),ZX_size(gel(G2,j)));
     410           0 :         gel(G1, j) = ZX_chinese_center(gel(G1,j),M1, gel(G2,j),M2, m,m2);
     411             :       }
     412             :     }
     413       15807 :     if (n_k == n_T) break;
     414           0 :     M1 = m;
     415             :   }
     416       15807 :   if (DEBUGLEVEL >= 6) timer_printf(&ti, "get_vT");
     417       15807 :   return gerepilecopy(av, vT);
     418             : }
     419             : 
     420             : /* return sorted kT={i_t[k] | 1<=k<=d}
     421             :  * {T_k(x) | k in kT} are all the different T_k(x) (1<=k<=d) */
     422             : static GEN
     423       15754 : get_kT(GEN i_t, long d)
     424       15754 : { return vecsmall_uniq(vecsmall_shorten(i_t, d)); }
     425             : 
     426             : static GEN
     427          53 : get_kT_all(GEN GH, GEN i_t, long n, long d, long m)
     428             : {
     429          53 :   long i, j, k = 0;
     430          53 :   GEN x = const_vecsmall(d*m, 0);
     431         106 :   for (i = 1; i <= m; i++)
     432         755 :     for (j = 1; j <= d; j++) x[++k] = i_t[Fl_mul(GH[i], j, n)];
     433          53 :   return vecsmall_uniq(x);
     434             : }
     435             : 
     436             : static GEN
     437          53 : kT_from_kt_new(GEN gGH, GEN kt, GEN i_t, long n)
     438             : {
     439          53 :   GEN EL = gel(gGH, 1);
     440          53 :   long i, k = 0, lEL = lg(EL), lkt = lg(kt);
     441          53 :   GEN x = cgetg(lEL+lkt, t_VECSMALL);
     442             : 
     443         151 :   for (i = 1; i < lEL; i++) x[++k] = i_t[EL[i]];
     444         424 :   for (i = 2; i < lkt; i++) if (n%kt[i]==0) x[++k] = kt[i];
     445          53 :   setlg(x, k+1); return vecsmall_uniq(x);
     446             : }
     447             : 
     448             : static GEN
     449          53 : get_kTdiv(GEN kT, long n)
     450             : {
     451          53 :   long i, k = 0, l = lg(kT);
     452          53 :   GEN div = cgetg(l, t_VECSMALL);
     453         202 :   for (i = 1; i < l; i++) if (n%kT[i]==0) div[++k] = kT[i];
     454          53 :   setlg(div, k+1);
     455          53 :   return div;
     456             : }
     457             : 
     458             : /* T is separable over Zp but not separable over Fp.
     459             :  * receive all roots mod p^s and return all roots mod p^(s+1) */
     460             : static GEN
     461         833 : ZpX_roots_nonsep(GEN T, GEN R0, GEN p, GEN ps, GEN ps1)
     462             : {
     463         833 :   long i, j, n = 0, lr = lg(R0);
     464         833 :   GEN v = cgetg(lr, t_VEC), R;
     465        4375 :   for (i = 1; i < lr; i++)
     466             :   {
     467        3542 :     GEN z, f = ZX_unscale_div(ZX_translate(T, gel(R0, i)), ps);
     468        3542 :     (void)ZX_pvalrem(f, p, &f);
     469        3542 :     gel(v, i) = z = FpX_roots(f, p);
     470        3542 :     n += lg(z)-1;
     471             :   }
     472         833 :   R = cgetg(n+1, t_VEC); n = 0;
     473        4375 :   for (i = 1; i < lr; i++)
     474             :   {
     475        3542 :     GEN z = gel(v, i);
     476        3542 :     long lz = lg(z);
     477        8190 :     for (j=1; j<lz; j++)
     478        4648 :       gel(R, ++n) = Fp_add(gel(R0, i), mulii(gel(z, j), ps), ps1);
     479             :   }
     480         833 :   return ZV_sort_uniq_shallow(R);
     481             : }
     482             : static GEN
     483       49267 : ZpX_roots_all(GEN T, GEN p, long f, long *ptrs)
     484             : {
     485       49267 :   pari_sp av = avma;
     486             :   pari_timer ti;
     487             :   GEN v, ps, ps1;
     488             :   long s;
     489             : 
     490       49267 :   if (DEBUGLEVEL >= 6) timer_start(&ti);
     491       49267 :   v = FpX_roots(T, p); /* FpX_roots returns sorted roots */
     492       49267 :   if (DEBUGLEVEL >= 6) timer_printf(&ti, "FpX_roots, deg=%ld", degpol(T));
     493       49267 :   ps = NULL; ps1 = p;
     494       50100 :   for (s = 1; lg(v) != f+1; s++)
     495             :   {
     496         833 :     ps = ps1; ps1 = mulii(ps1, p); /* p^s, p^(s+1) */
     497         833 :     v = ZpX_roots_nonsep(T, v, p, ps, ps1);
     498         833 :     if (gc_needed(av, 1)) gerepileall(av, 3, &v, &ps, &ps1);
     499             :   }
     500       49267 :   *ptrs = s; return v;
     501             : }
     502             : /* x : roots of T in Zp. r < n.
     503             :  * receive vec of x mod p^r and return vec of x mod p^n.
     504             :  * under the assumtion lg(v)-1==degpol(T), x is uniquely determined by
     505             :  * x mod p^r. Namely, x mod p^n is unique. */
     506             : static GEN
     507        2513 : ZX_Zp_liftroots(GEN T, GEN v, GEN p, long r, long n)
     508             : {
     509        2513 :   long i, l = lg(v);
     510        2513 :   GEN R = cgetg(l, t_VEC);
     511        2513 :   GEN pr = powiu(p, r), pn = powiu(p, n);
     512             :   pari_timer ti;
     513             : 
     514        2513 :   if (DEBUGLEVEL >= 6) timer_start(&ti);
     515        9709 :   for (i=1; i<l; i++)
     516             :   {
     517        7196 :     GEN x = gel(v, i), y, z;
     518        7196 :     GEN f = ZX_unscale_div(ZX_translate(T, x), pr);
     519        7196 :     (void)ZX_pvalrem(f, p, &f);
     520        7196 :     y = FpX_roots(f, p);
     521        7196 :     z = (n==r+1) ? y : ZX_Zp_root(f, gel(y, 1), p, n-r);
     522        7196 :     if (lg(y)!=2 || lg(z)!=2)
     523           0 :       pari_err_BUG("ZX_Zp_liftroots, roots are not separable");
     524        7196 :     gel(R, i) = Fp_add(x, mulii(gel(z, 1), pr), pn);
     525             :   }
     526        2513 :   if (DEBUGLEVEL >= 6) timer_printf(&ti, "ZX_Zp_liftroots");
     527        2513 :   return R;
     528             : }
     529             : 
     530             : static GEN
     531       33460 : set_R(GEN T, GEN F, GEN Rs, GEN p, long nf, long r, long s, long u)
     532             : {
     533             :   long i;
     534       33460 :   GEN x, pr = powiu(p, r), prs = powiu(p, r+s), R = cgetg(1+nf, t_VEC), Rrs;
     535       33460 :   Rrs = r ? ZX_Zp_liftroots(T, Rs, p, s, r+s) : Rs;
     536       33460 :   x = gel(Rrs, 1);
     537      121856 :   for (i = 1; i <= nf; i++)
     538             :   {
     539       88396 :     x = FpX_eval(F, x, prs);
     540       88396 :     if (r) x = gel(Rrs, ZV_search(Rs, diviiexact(x, pr)));
     541       88396 :     gel(R, i) = x;  /* R[i]=t_1^(g^i), t_1=Rrs[1], mod p^(r+s) */
     542             :   }
     543       33460 :   if (r+s < u) R = ZX_Zp_liftroots(T, R, p, r+s, u);
     544       32116 :   else if (r+s > u) R = FpV_red(R, powiu(p, u));
     545       33460 :   return R;  /* mod p^u, accuracy for pol_newton */
     546             : }
     547             : 
     548             : /* Preparation for factoring polcyclo(el^e) mod p
     549             :  * f_0(x) : irred factor of polcyclo(el^e0) mod p
     550             :  * f_1(x)=f_0(x^(el^e1)) : irred factor of polcyclo(el^e) mod p
     551             :  *
     552             :  * p^d0 = 1 (mod el^e0), p^d = 1 (mod el^e)
     553             :  *
     554             :  * case el=2, 2^s || (p-1), s>=2
     555             :  * d=1 (1 <= e <= s), d=2^(e-s) (s < e)
     556             :  * e0=e, e1=0 if e <= s
     557             :  * e0=s, e1=e-s if s < e
     558             :  * d0=1
     559             :  *
     560             :  * case el=2, 2^s || (p+1), s>=2
     561             :  * d=1 (e == 1), d=2 (2 <= e <= s), d=2^(e-s) (s < e)
     562             :  * e0=e, e1=0 if e <= s+1
     563             :  * e0=s+1, e1=e-s-1 if s+1 < e
     564             :  * d0=1 if e==1,  d0=2 if e>1
     565             :  *
     566             :  * case el>2, el^s || (p^d0-1)
     567             :  * d=d0 (1 <= e <= s), d=d0*el^(e-s) (s < e)
     568             :  * e0=e, e1=0 if e <= s
     569             :  * e0=s, e1=e-s if s < e
     570             :  * d0 is min d s.t. p^d=1 (mod el)
     571             :  *
     572             :  * We do not need d. So d is not returned. */
     573             : static GEN
     574       34222 : set_e0_e1(ulong el, ulong e, GEN p)
     575             : {
     576       34222 :   ulong s, d0, e0, e1, f0, n, phin, g, up = itou_or_0(p);
     577             : 
     578       34222 :   if (el == 2)
     579             :   {
     580           0 :     ulong pmod4 = up ? up&3 : mod4(p);
     581           0 :     if (pmod4 == 3)  /* p+1 = 0 (mod 4) */
     582             :     {
     583           0 :       s = up ? vals(up+1) : vali(addiu(p, 1));
     584           0 :       if (e <= s+1) { e0 = e; e1 = 0;}
     585           0 :       else { e0 = s+1; e1= e-s-1;}
     586           0 :       d0 = e == 1? 1: 2;
     587             :     }
     588             :     else  /* p-1 = 0 (mod 4) */
     589             :     {
     590           0 :       s = up ? vals(up-1) : vali(subiu(p, 1));
     591           0 :       if (e <= s) { e0 = e; e1 = 0; }
     592           0 :       else { e0 = s; e1 = e-s; }
     593           0 :       d0 = 1;
     594             :     }
     595           0 :     phin = 1L<<(e0-1);
     596             :   }
     597             :   else  /* el is odd */
     598             :   {
     599       34222 :     ulong pmodel = up ? up%el : umodiu(p, el);
     600       34222 :     d0 = Fl_order(pmodel, el-1, el);
     601       34222 :     s = Z_lval(subiu(powiu(p, d0), 1), el);
     602       34222 :     if (e <= s) { e0 = e; e1 = 0; } else { e0 = s; e1 = e-s; }
     603       34222 :     phin = (el-1)*upowuu(el, e0-1);
     604             :   }
     605       34222 :   n = upowuu(el, e0); f0 = phin/d0;
     606       34222 :   g = (el==2) ? 1 : pgener_Zl(el);
     607       34222 :   return mkvecsmalln(7, n, e0, e1, phin, g, d0, f0);
     608             : }
     609             : 
     610             : /* return 1 if newton is fast, return 0 if gen is fast */
     611             : static int
     612       78511 : use_newton(long d, long f)
     613             : {
     614       78511 :   if (2*d <= f) return 0;
     615       73603 :   else if (f <= d) return 1;
     616        5935 :   else if (d <= 50) return 0;
     617           0 :   else if (f <= 60) return 1;
     618           0 :   else if (d <= 90) return 0;
     619           0 :   else if (f <= 150) return 1;
     620           0 :   else if (d <= 150) return 0;
     621           0 :   else if (f <= 200) return 1;
     622           0 :   else if (200*d <= f*f) return 0;
     623           0 :   else return 1;
     624             : }
     625             : 
     626             : /* return 1 if newton_general is fast, return 0 otherwise. Assume f > 40 */
     627             : static int
     628          14 : use_newton_general(long d, long f, long maxdeg)
     629             : {
     630          14 :   if (maxdeg < 20) return 0;
     631          14 :   else if (f <= 50) return 1;
     632           7 :   else if (maxdeg < 30) return 0;
     633           7 :   else if (f <= 60) return 1;
     634           7 :   else if (maxdeg < 40) return 0;
     635           7 :   else if (f <= 70) return 1;
     636           7 :   else if (maxdeg < 50) return 0;
     637           7 :   else if (f <= 80) return 1;
     638           7 :   else if (d < 200) return 0;
     639           0 :   else if (f <= 100) return 1;
     640           0 :   else if (d < 300) return 0;
     641           0 :   else if (f <= 120) return 1;
     642           0 :   else if (6*maxdeg < f*f) return 0;
     643           0 :   else return 1;
     644             : }
     645             : 
     646             : static int
     647           7 : use_general(long d, long maxdeg)
     648             : {
     649           7 :   if (d <= 50) return 1;
     650           7 :   else if (maxdeg <= 3*d) return 0;
     651           7 :   else if (d <= 200) return 1;
     652           0 :   else if (maxdeg <= 10*d) return 0;
     653           0 :   else if (d <= 500) return 1;
     654           0 :   else if (maxdeg <= 20*d) return 0;
     655           0 :   else if (d <= 1000) return 1;
     656           0 :   else return 0;
     657             : }
     658             : 
     659             : static void
     660          70 : update_dfm(long *pd, long *pf, long *pm, long di, long fi)
     661             : {
     662          70 :   long c = ugcd(*pd,di), d1 = *pd * di, f1 = *pf * fi;
     663          70 :   *pd = d1 / c; *pf = c * f1; *pm += d1 * d1 * f1;
     664          70 :   if (DEBUGLEVEL == 4) err_printf("(%ld,%ld), ",d1,f1);
     665          70 : }
     666             : /* assume ord(p mod f) > 1 */
     667             : static ulong
     668       94605 : set_action(GEN fn, GEN p, long d, long f)
     669             : {
     670       94605 :   GEN EL = gel(fn, 1), E = gel(fn, 2);
     671       94605 :   long i, d0, f0, m0, m1, maxdeg, max, l = lg(EL);
     672       94605 :   ulong action = 0, up = itou_or_0(p);
     673       94605 :   GEN D = cgetg(l, t_VECSMALL), F = cgetg(l, t_VECSMALL);
     674             : 
     675       94605 :   d += 10*(lgefint(p)-3);
     676       94605 :   if (l == 2)
     677             :   { /* n is a prime power */
     678       47670 :     action |= (EL[1]==2 || !use_newton(d, f))? GENERAL: NEWTON_POWER;
     679       47670 :     return action;
     680             :   }
     681       46935 :   if (f <= 2) action |= NEWTON_GENERAL;
     682       36540 :   else if (d <= 10) action |= GENERAL;
     683        5835 :   else if (f <= 10) action |= NEWTON_GENERAL;
     684         476 :   else if (d <= 20) action |= GENERAL;
     685          73 :   else if (f <= 20) action |= NEWTON_GENERAL_NEW;
     686          27 :   else if (d <= 30) action |= GENERAL;
     687          21 :   else if (f <= 30) action |= NEWTON_GENERAL_NEW;
     688          21 :   else if (d <= 40) action |= GENERAL;
     689          21 :   else if (f <= 40) action |= NEWTON_GENERAL_NEW;
     690       46935 :   if (action) return action;
     691             :   /* can assume that d > 40 and f > 40 */
     692             : 
     693          21 :   maxdeg = max = 1;
     694          91 :   for (i = 1; i < l; i++)
     695             :   {
     696          70 :     long x, el = EL[i], e = E[i];
     697          70 :     long q = upowuu(el, e-1), ni = q * el, phini = ni - q;
     698          70 :     long di = Fl_order(umodiu(p, ni), phini, ni);
     699          70 :     D[i] = di; F[i] = phini / di;
     700          70 :     x = ugcd(max, di); max = max * (di / x); /* = lcm(d1,..di) */
     701          70 :     if (x > 1) maxdeg = max*x;
     702          70 :     if (DEBUGLEVEL == 4) err_printf("(%ld,%ld), ", D[i], F[i]);
     703             :   }
     704          21 :   if (maxdeg == 1) return action;
     705          14 :   if (up != 2)
     706             :   {
     707          14 :     if (use_newton_general(d, f, maxdeg))
     708             :     { /* does not decompose n */
     709           7 :       action |= (20 < d)? NEWTON_GENERAL_NEW: NEWTON_GENERAL;
     710           7 :       return action;
     711             :     }
     712           7 :     if (use_general(d, maxdeg)) action |= GENERAL;
     713             :   }
     714           7 :   if (l < 4) return action; /* n has two factors */
     715             : 
     716           7 :   d0 = f0 = 1; m0 = 0;
     717          42 :   for (i = 1; i < l; i++) update_dfm(&d0, &f0, &m0, D[i], F[i]);
     718           7 :   if (DEBUGLEVEL == 4) err_printf("(d0,f0)=(%ld,%ld)\n",d0,f0);
     719           7 :   d0 = f0 = 1; m1 = 0;
     720          42 :   for (i = l-1; i >= 1; i--) update_dfm(&d0, &f0, &m1, D[i], D[i]);
     721           7 :   if (DEBUGLEVEL == 4) err_printf("(d0,f0)=(%ld,%ld)\n",d0,f0);
     722           7 :   if (DEBUGLEVEL == 4) err_printf("(m0,m1)=(%lu,%lu) %ld\n",m0,m1,m0<=m1);
     723           7 :   if (m0 <= m1) action |= ASCENT;
     724           7 :   return action;
     725             : }
     726             : 
     727             : static GEN
     728       10758 : FpX_Newton_perm(long d, GEN R, GEN v, GEN pu, GEN p)
     729             : {
     730       10758 :   GEN S = cgetg(d+2, t_VEC);
     731             :   long k;
     732       95189 :   gel(S,1) = utoi(d); for (k = 1; k <= d; k++) gel(S, k+1) = gel(R, v[k]);
     733       10758 :   return FpX_red(FpX_fromNewton(RgV_to_RgX(S, 0), pu), p);
     734             : }
     735             : static GEN
     736       81847 : Flx_Newton_perm(long d, GEN R, GEN v, ulong pu, ulong p)
     737             : {
     738       81847 :   GEN S = cgetg(d+2, t_VEC);
     739             :   long k;
     740     1177903 :   S[1] = d; for (k = 1; k <= d; k++) gel(S, k+1) = gel(R, v[k]);
     741       81847 :   return Flx_red(Flx_fromNewton(Flv_to_Flx(S, 0), pu), p);
     742             : }
     743             : 
     744             : /*  Data = [H, GH, i_t, d0, kT, [n, d, f, n_T, mitk]]
     745             :     N2 = [p, pr, pu, pru] */
     746             : static GEN
     747        6866 : FpX_pol_newton_general(GEN Data, GEN N2, GEN vT, GEN x)
     748             : {
     749        6866 :   GEN i_t = gel(Data, 3), kT = gel(Data, 5), N = gel(Data, 6);
     750        6866 :   long k, d = N[2], n_T = N[4], mitk = N[5];
     751        6866 :   GEN p = gel(N2,1), pr = gel(N2,2), pu = gel(N2,3), pru = gel(N2,4);
     752        6866 :   GEN R = cgetg(1+mitk, t_VEC);
     753             : 
     754       32579 :   for (k = 1; k <= n_T; k++)
     755       25713 :     gel(R, kT[k]) = diviiexact(FpX_eval(gel(vT, kT[k]), x, pru), pr);
     756        6866 :   return FpX_Newton_perm(d, R, i_t, pu, p);
     757             : }
     758             : 
     759             : /* n is any integer prime to p, but must be equal to the conductor
     760             :  * of the splitting field of p in Q(zeta_n).
     761             :  * GH=G/H={g_1, ... ,g_f}
     762             :  * Data = [GHgen, GH, fn, p, [n, d, f, m]] */
     763             : static GEN
     764        2414 : FpX_factcyclo_newton_general(GEN Data)
     765             : {
     766        2414 :   GEN GH = gel(Data, 2), fn = gel(Data, 3), p = gel(Data, 4);
     767        2414 :   long n = mael(Data, 5, 1), d = mael(Data, 5, 2), f = mael(Data, 5, 3);
     768        2414 :   long m = mael(Data, 5, 4), pmodn = umodiu(p, n);
     769        2414 :   long i, k, n_T, mitk, r, s = 0, u = 1;
     770             :   GEN vT, kT, H, i_t, T, d0d1, Data2, Data3, R, Rs, pr, pu, pru;
     771             :   pari_timer ti;
     772             : 
     773        2414 :   if (m != 1) m = f;
     774        2414 :   for (pu = p; cmpiu(pu,d) <= 0; u++) pu = mulii(pu, p);  /* d<pu, pu=p^n */
     775             : 
     776        2414 :   H = Fl_powers(pmodn, d-1, n); /* H=<p> */
     777        2414 :   i_t = get_i_t(n, pmodn); /* i_t[1+i]=k ==> t_i=t_k */
     778        2414 :   kT = get_kT(i_t, d); n_T = lg(kT)-1; mitk = kT[n_T];
     779        2414 :   if (DEBUGLEVEL == 2) err_printf("kT=%Ps %ld elements\n",kT,n_T);
     780        2414 :   if (DEBUGLEVEL >= 6) timer_start(&ti);
     781        2414 :   T = galoissubcyclo(utoi(n), utoi(pmodn), 0, 0);
     782        2414 :   if (DEBUGLEVEL >= 6) timer_printf(&ti, "galoissubcyclo");
     783        2414 :   d0d1 = get_d0_d1(T, gel(fn,1)); /* d0*T_k(x) is in Z[x] */
     784        2414 :   Data2 = mkvecn(6, H, GH, i_t, d0d1, kT, mkvecsmalln(5, n, d, f, n_T, mitk));
     785        2414 :   vT = get_vT(Data2, 0);
     786        2414 :   if (DEBUGLEVEL == 4) err_printf("vT=%Ps\n",vT);
     787        2414 :   r = QXV_den_pval(vT, kT, p);
     788        2414 :   Rs = ZpX_roots_all(T, p, f, &s);
     789        2414 :   if (DEBUGLEVEL >= 2) err_printf("(u,s,r)=(%ld,%ld,%ld)\n",u,s,r);
     790        2414 :   if (r+u < s) pari_err_BUG("FpX_factcyclo_newton_general (T is not separable mod p^(r+u))");
     791             :   /* R and vT are mod p^(r+u) */
     792        2414 :   R = (r+u==s) ? Rs : ZX_Zp_liftroots(T, Rs, p, s, r+u);
     793        2414 :   pr = powiu(p, r); pru = powiu(p, r+u); /* Usually, r=0, s=1, pr=1, pru=p */
     794       11320 :   for (k = 1; k<=n_T; k++)
     795             :   {
     796        8906 :     long itk = kT[k];
     797        8906 :     GEN z = r? RgX_Rg_mul(gel(vT, itk), pr): gel(vT, itk);
     798        8906 :     gel(vT, itk) = RgX_to_FpX(z, pru);
     799             :   }
     800        2414 :   Data3 = mkvec4(p, pr, pu, pru);
     801        2414 :   if (DEBUGLEVEL >= 6) timer_start(&ti);
     802        9280 :   for (i=1; i<=m; i++)
     803        6866 :     gel(R,i) = FpX_pol_newton_general(Data2, Data3, vT, gel(R,i));
     804        2414 :   if (DEBUGLEVEL >= 6) timer_printf(&ti, "FpX_pol_newton_general");
     805        2414 :   return R;
     806             : }
     807             : 
     808             : /* Data = [vT, gGH, Rs, Rrs, i_t, kt, p, pu, pr, prs,
     809             :           [n, r, s, n_t,mitk], div] */
     810             : static void
     811       10937 : Fp_next_gen3(long x, long i, GEN v_t_p, GEN t, GEN Data)
     812             : {
     813       10937 :   GEN vT = gel(Data, 1), gGH = gel(Data, 2), Rs = gel(Data, 3);
     814       10937 :   GEN Rrs = gel(Data, 4), i_t = gel(Data, 5);
     815       10937 :   GEN pu = gel(Data, 8), pr = gel(Data, 9), prs = gel(Data, 10);
     816       10937 :   GEN EL = gel(gGH, 1), E = gel(gGH, 2), div = gel(Data, 12);
     817       10937 :   long n = mael(Data, 11, 1), r = mael(Data, 11, 2), mitk = mael(Data, 11, 5);
     818       10937 :   long j, k, l = lg(EL), ld = lg(div);
     819       10937 :   if (i >= l) return;
     820       14099 :   for (j = 0; j < E[i]; j++)
     821             :   {
     822       10544 :     if (j > 0)
     823             :     {
     824        6989 :       long itx = i_t[x];
     825        6989 :       t = FpX_eval(gel(vT, i_t[EL[i]]), t, prs); /* mod p^(r+s) */
     826        6989 :       if (r) t = gel(Rrs, ZV_search(Rs, diviiexact(t, pr))); /* mod p^(r+s) */
     827        6989 :       if (itx <= mitk) gel(v_t_p, itx) = Fp_red(t, pu); /* mod p^u */
     828       16722 :       for (k = 1; k<ld; k++)
     829             :       {
     830        9733 :         ulong y = Fl_mul(x, div[k], n);
     831        9733 :         long ity = i_t[y];
     832             :         GEN v;
     833        9733 :         if (ity > mitk || !isintzero(gel(v_t_p, ity))) continue;
     834         653 :         v = FpX_eval(gel(vT, i_t[div[k]]), t, prs); /* mod p^(r+s) */
     835         653 :         if (r) v = diviiexact(v, pr); /* mod p^s */
     836         653 :         gel(v_t_p, ity) = Fp_red(v, pu);
     837             :       }
     838             :     }
     839       10544 :     Fp_next_gen3(x, i+1, v_t_p, t, Data);
     840       10544 :     x = Fl_mul(x, EL[i], n);
     841             :   }
     842             : }
     843             : 
     844             : /* Data = [vT, gGH, Rs, Rrs, i_t, kt, p, pu, pr, prs,
     845             :           [n, r, s, n_t, mitk], div] */
     846             : static GEN
     847         393 : Fp_mk_v_t_p3(GEN Data, long i)
     848             : { /* v_t_p[k] != gen_0 => v_t_p[k] = t_k mod p^u */
     849         393 :   GEN Rs = gel(Data, 3), Rrs = gel(Data, 4);
     850         393 :   GEN pu = gel(Data, 8), pr = gel(Data, 9), prs = gel(Data, 10);
     851         393 :   GEN vT = gel(Data, 1), i_t = gel(Data, 5), div = gel(Data, 12);
     852         393 :   long k, r = mael(Data, 11, 2), mitk = mael(Data, 11, 5), ld = lg(div);
     853         393 :   GEN v_t_p = const_vec(mitk, gen_0);
     854             : 
     855         393 :   gel(v_t_p, 1) = Fp_red(gel(Rs, i), pu); /* mod p^u, guaranteed u<=s */
     856         393 :   Fp_next_gen3(1, 1, v_t_p, gel(Rrs, i), Data);
     857         758 :   for (k = 1; k<ld; k++)
     858             :   {
     859         365 :     ulong itk = i_t[div[k]];
     860         365 :     GEN x = FpX_eval(gel(vT, itk), gel(Rrs, i), prs);
     861         365 :     if (r) x = diviiexact(x, pr); /* mod p^s */
     862         365 :     gel(v_t_p, itk) = Fp_red(x, pu);
     863             :   }
     864         393 :   return v_t_p;
     865             : }
     866             : 
     867             : /* Data = [vT, gGH, Rs, Rrs, i_t, kt, p, pu, pr, prs,
     868             :           [n, r, s, n_t,mitk], div] */
     869             : static void
     870       21024 : Fl_next_gen3(long x, long i, GEN v_t_p, ulong t, GEN Data)
     871             : {
     872       21024 :   GEN vT = gel(Data, 1), gGH = gel(Data, 2), Rs = gel(Data, 3);
     873       21024 :   GEN Rrs = gel(Data, 4), i_t = gel(Data, 5);
     874       21024 :   long pu = mael(Data, 8, 2), pr = mael(Data, 9, 2), prs = mael(Data, 10, 2);
     875       21024 :   GEN EL = gel(gGH, 1), E = gel(gGH, 2), div = gel(Data, 12);
     876       21024 :   long n = mael(Data, 11, 1), r = mael(Data, 11, 2), mitk = mael(Data, 11, 5);
     877       21024 :   long j, k, l = lg(EL), ld = lg(div);
     878       21024 :   if (i >= l) return;
     879       27936 :   for (j = 0; j < E[i]; j++)
     880             :   {
     881       20736 :     if (j > 0)
     882             :     {
     883       13536 :       long itx = i_t[x];
     884       13536 :       t = Flx_eval(gel(vT, i_t[EL[i]]), t, prs); /* mod p^(r+s) */
     885       13536 :       if (r) t = Rrs[zv_search(Rs, t/pr)]; /* mod p^(r+s) */
     886       13536 :       if (itx <= mitk) v_t_p[itx] = t%pu; /* mod p^u */
     887       54144 :       for (k = 1; k < ld; k++)
     888             :       {
     889       40608 :         ulong y = Fl_mul(x, div[k], n), v;
     890       40608 :         long ity = i_t[y];
     891       40608 :         if (ity > mitk || v_t_p[ity]) continue;
     892        2592 :         v = Flx_eval(gel(vT, i_t[div[k]]), t, prs); /* mod p^(r+s) */
     893        2592 :         if (r) v /= pr; /* mod p^s */
     894        2592 :         v_t_p[ity] = v%pu;
     895             :       }
     896             :     }
     897       20736 :     Fl_next_gen3(x, i+1, v_t_p, t, Data);
     898       20736 :     x = Fl_mul(x, EL[i], n);
     899             :   }
     900             : }
     901             : 
     902             : /* Data = [vT, gGH, Rs, Rrs, i_t, kt, p, pu, pr, prs,
     903             :           [n, r, s, n_t, mitk], div] */
     904             : static GEN
     905         288 : Fl_mk_v_t_p3(GEN Data, long i)
     906             : { /* v_t_p[k] != 0 => v_t_p[k] = t_k mod p^u */
     907         288 :   GEN Rs = gel(Data, 3), Rrs = gel(Data, 4);
     908         288 :   ulong pu = mael(Data, 8, 2), pr = mael(Data, 9, 2), prs = mael(Data, 10, 2);
     909         288 :   GEN vT = gel(Data, 1), i_t = gel(Data, 5), div = gel(Data, 12);
     910         288 :   long k, r = mael(Data, 11, 2), mitk = mael(Data, 11, 5), ld = lg(div);
     911         288 :   GEN v_t_p = const_vecsmall(mitk, 0);
     912             : 
     913         288 :   v_t_p[1] = Rs[i] % pu; /* mod p^u, guaranteed u<=s */
     914         288 :   Fl_next_gen3(1, 1, v_t_p, Rrs[i], Data);
     915        1152 :   for (k = 1; k < ld; k++)
     916             :   {
     917         864 :     ulong itk = i_t[div[k]], x = Flx_eval(gel(vT, itk), Rrs[i], prs);
     918         864 :     if (r) x /= pr; /* mod p^s */
     919         864 :     v_t_p[itk] = x % pu;
     920             :   }
     921         288 :   return v_t_p;
     922             : }
     923             : 
     924             : /* Data = [GHgen, GH, fn, p, [n, d, f, m]] */
     925             : static GEN
     926          53 : newton_general_new_pre3(GEN Data)
     927             : {
     928          53 :   GEN gGH = gel(Data, 1), GH = gel(Data, 2), fn = gel(Data, 3);
     929          53 :   GEN p = gel(Data, 4);
     930          53 :   long n = mael(Data, 5, 1), d = mael(Data, 5, 2), f = mael(Data, 5, 3);
     931          53 :   long pmodn = umodiu(p, n);
     932          53 :   long k, n_t, n_T, mitk, miTk, r, s = 0, u = 1;
     933             :   GEN vT, kt, kT, H, i_t, T, d0d1, Data2, Rs, Rrs, kTdiv;
     934             :   GEN pr, pu, prs;
     935             :   pari_timer ti;
     936             : 
     937          60 :   for (pu = p; cmpiu(pu,d)<=0; u++) pu = mulii(pu, p);  /* d<pu, pu=p^u */
     938             : 
     939          53 :   H = Fl_powers(pmodn, d-1, n); /* H=<p> */
     940          53 :   i_t = get_i_t(n, pmodn); /* i_t[1+i]=k ==> t_i=t_k */
     941          53 :   kt = get_kT_all(GH, i_t, n, d, 1); n_t = lg(kt)-1; mitk = kt[n_t];
     942          53 :   kT = kT_from_kt_new(gGH, kt, i_t, n); n_T = lg(kT)-1; miTk = kT[n_T];
     943          53 :   kTdiv = get_kTdiv(kT, n);
     944          53 :   if (DEBUGLEVEL == 2)
     945           0 :     err_printf("kt=%Ps %ld elements\nkT=%Ps %ld elements\n",kt,n_t,kT,n_T);
     946          53 :   if (DEBUGLEVEL == 2)
     947           0 :     err_printf("kTdiv=%Ps\n",kTdiv);
     948             : 
     949          53 :   if (DEBUGLEVEL >= 6) timer_start(&ti);
     950          53 :   T = galoissubcyclo(utoi(n), utoi(pmodn), 0, 0);
     951          53 :   if (DEBUGLEVEL >= 6) timer_printf(&ti, "galoissubcyclo");
     952          53 :   d0d1 = get_d0_d1(T, gel(fn,1)); /* d0*T_k(x) is in Z[x] */
     953          53 :   Data2 = mkvecn(6, H, GH, i_t, d0d1, kT, mkvecsmalln(5, n, d, f, n_T, miTk));
     954          53 :   vT = get_vT(Data2, 1);
     955          53 :   if (DEBUGLEVEL == 4) err_printf("vT=%Ps\n",vT);
     956          53 :   r = QXV_den_pval(vT, kT, p);
     957          53 :   Rs = ZpX_roots_all(T, p, f, &s);
     958          53 :   if (DEBUGLEVEL >= 2) err_printf("(u,s,r)=(%ld,%ld,%ld)\n",u,s,r);
     959          53 :   if (s < u)
     960             :   {
     961           0 :     Rs = ZV_sort_shallow(ZX_Zp_liftroots(T, Rs, p, s, u));
     962           0 :     s = u;
     963             :   }
     964             :   /* Rs : mod p^s, Rrs : mod p^(r+s), vT : mod p^(r+s) */
     965          53 :   Rrs = r ? ZX_Zp_liftroots(T, Rs, p, s, r+s) : Rs;
     966          53 :   pr = powiu(p, r); prs = powiu(p, r+s); /* Usually, r=0, s=1, pr=1, pru=p */
     967          53 :   if (lgefint(prs)>3)  /* ULONG_MAX < p^(r+s), usually occur */
     968             :   {
     969         166 :     for (k = 1; k <= n_T; k++)
     970             :     {
     971         119 :       long itk = kT[k];
     972         119 :       GEN z = r? RgX_Rg_mul(gel(vT, itk), pr): gel(vT, itk);
     973         119 :       gel(vT, itk) = RgX_to_FpX(z, prs);
     974             :     }
     975             :   }
     976             :   else  /* p^(r+s) < ULONG_MAX, frequently occur */
     977             :   {
     978           6 :     ulong upr = itou(pr), uprs = itou(prs);
     979          36 :     for (k = 1; k <= n_T; k++)
     980             :     {
     981          30 :       long itk = kT[k];
     982          30 :       GEN z = r? RgX_muls(gel(vT, itk), upr): gel(vT, itk);
     983          30 :       gel(vT, itk) = RgX_to_Flx(z, uprs);
     984             :     }
     985           6 :     Rs = ZV_to_nv(Rs); Rrs = ZV_to_nv(Rrs);
     986             :   }
     987          53 :   return mkvecn(12, vT, gGH, Rs, Rrs, i_t, kt, p, pu, pr, prs,
     988             :                 mkvecsmalln(6, n, r, s, n_t, mitk, d), kTdiv);
     989             : }
     990             : 
     991             : /* Data=[vT, gGH, Rs, Rrs, i_t, kt, p, pu, pr, prs,
     992             :  *      [n, r, s, n_t, mitk, d], div] */
     993             : static GEN
     994         345 : FpX_pol_newton_general_new3(GEN Data, long k)
     995             : {
     996         345 :   GEN i_t = gel(Data, 5), p = gel(Data, 7), pu = gel(Data, 8);
     997         345 :   long d = mael(Data, 11, 6);
     998         345 :   GEN v_t_p = Fp_mk_v_t_p3(Data, k);
     999         345 :   if (DEBUGLEVEL == 3) err_printf("v_t_p=%Ps\n",v_t_p);
    1000         345 :   return FpX_Newton_perm(d, v_t_p, i_t, pu, p);
    1001             : }
    1002             : 
    1003             : /* Data = [GHgen, GH, fn, p, [n, d, f, m]] */
    1004             : static GEN
    1005          46 : FpX_factcyclo_newton_general_new3(GEN Data)
    1006             : {
    1007          46 :   long i, f = mael(Data, 5, 3), m = mael(Data, 5, 4);
    1008             :   GEN Data2, pols;
    1009             :   pari_timer ti;
    1010             : 
    1011          46 :   if (m != 1) m = f;
    1012          46 :   pols = cgetg(1+m, t_VEC);
    1013          46 :   Data2 = newton_general_new_pre3(Data);
    1014             :   /* Data2 = [vT, gGH, Rs, Rrs, i_t, kt, p, pu, pr, prs,
    1015             :               [n, r, s, n_t, mitk, d], div] */
    1016          46 :   if (DEBUGLEVEL >= 6) timer_start(&ti);
    1017         391 :   for (i = 1; i <= m; i++)
    1018         345 :     gel(pols, i) = FpX_pol_newton_general_new3(Data2, i);
    1019          46 :   if (DEBUGLEVEL >= 6) timer_printf(&ti, "FpX_pol_newton_general_new3");
    1020          46 :   return pols;
    1021             : }
    1022             : 
    1023             : /* return normalized z(-x) */
    1024             : static GEN
    1025        4483 : FpX_1st_lift_2(GEN z, GEN p)
    1026             : {
    1027        4483 :   long i, r = lg(z);
    1028        4483 :   GEN x = cgetg(r, t_POL);
    1029        4483 :   x[1] = evalsigne(1) | evalvarn(0);
    1030        4483 :   if (odd(r))
    1031        9962 :     for (i = 2; i < r; i++) gel(x,i) = odd(i)? Fp_neg(gel(z,i), p): gel(z,i);
    1032             :   else
    1033       16909 :     for (i = 2; i < r; i++) gel(x,i) = odd(i)? gel(z,i): Fp_neg(gel(z,i), p);
    1034        4483 :   return x;
    1035             : }
    1036             : 
    1037             : static GEN
    1038        3190 : FpX_1st_lift(GEN z, GEN p, ulong e, ulong el, GEN vP)
    1039             : {
    1040        3190 :    GEN z2, z3, P = gel(vP, e);
    1041        3190 :    if (!gel(vP, e)) P = gel(vP, e) = FpX_polcyclo(e, p);
    1042        3190 :    z2 = RgX_inflate(z, el);
    1043        3190 :    z3 = FpX_normalize(FpX_gcd(P, z2, p), p);
    1044        3190 :    return FpX_div(z2, z3, p);
    1045             : }
    1046             : 
    1047             : static GEN
    1048       11807 : FpX_lift(GEN z, GEN p, ulong e, ulong el, ulong r, ulong s, GEN vP)
    1049             : {
    1050       11807 :   if (s == 0)
    1051             :   {
    1052        7673 :     z = (el==2) ? FpX_1st_lift_2(z, p) : FpX_1st_lift(z, p, e, el, vP);
    1053        7673 :     if (r >= 2) z = RgX_inflate(z, upowuu(el, r-1));
    1054             :   }
    1055             :   else
    1056        4134 :     z = RgX_inflate(z, upowuu(el, r-s));
    1057       11807 :   return z;
    1058             : }
    1059             : 
    1060             : /* e is the conductor of the splitting field of p in Q(zeta_n) */
    1061             : static GEN
    1062       10501 : FpX_conductor_lift(GEN z, GEN p, GEN fn, ulong e, GEN vP)
    1063             : {
    1064       10501 :   GEN EL = gel(fn, 1), En = gel(fn, 2);
    1065       10501 :   long i, r = lg(EL), new_e = e;
    1066             : 
    1067       32077 :   for (i = 1; i < r; i++)
    1068             :   {
    1069       21576 :     long el = EL[i], en = En[i], ee = u_lval(e, el);
    1070       21576 :     if (ee < en)
    1071             :     {
    1072       11807 :       z = FpX_lift(z, p, new_e, el, en, ee, vP);
    1073       11807 :       new_e *= upowuu(el, en-ee);
    1074             :     }
    1075             :   }
    1076       10501 :   return z;
    1077             : }
    1078             : 
    1079             : /* R0 is mod p^u, d < p^u */
    1080             : static GEN
    1081        3547 : FpX_pol_newton(long j, GEN R0, GEN E, GEN D3, long d, long f, GEN p)
    1082             : {
    1083        3547 :   long i, u = D3[3];
    1084        3547 :   GEN R = cgetg(1+f, t_VEC);
    1085       15377 :   for (i = 1; i <= f; i++) gel(R, i) = gel(R0, 1+(i+j)%f);
    1086        3547 :   return FpX_Newton_perm(d, R, E, powiu(p, u), p);
    1087             : }
    1088             : 
    1089             : /* Data = [T, F, Rs, [d, nf, g, r, s, u]], nf>1 */
    1090             : static GEN
    1091        1896 : FpX_factcyclo_newton_pre(GEN Data, GEN N, GEN p, ulong m)
    1092             : {
    1093        1896 :   GEN T = gel(Data, 1), F = gel(Data, 2), Rs = gel(Data, 3), D4 = gel(Data, 4);
    1094        1896 :   long d = D4[1], nf = D4[2], g = D4[3], r = D4[4], s = D4[5], u = D4[6];
    1095             :   GEN pols, E, R, Data3;
    1096        1896 :   ulong i, n = N[1], pmodn = umodiu(p, n);
    1097             :   pari_timer ti;
    1098             : 
    1099        1896 :   if (m!=1) m = nf;
    1100        1896 :   pols = cgetg(1+m, t_VEC);
    1101        1896 :   E = set_E(pmodn, n, d, nf, g);
    1102        1896 :   R = set_R(T, F, Rs, p, nf, r, s, u);
    1103        1896 :   Data3 = mkvecsmall3(r, s, u);
    1104        1896 :   if (DEBUGLEVEL >= 6) timer_start(&ti);
    1105        5443 :   for (i = 1; i <= m; i++) gel(pols, i) = FpX_pol_newton(i, R,E,Data3, d,nf,p);
    1106        1896 :   if (DEBUGLEVEL >= 6) timer_printf(&ti, "FpX_pol_newton");
    1107        1896 :   return pols;
    1108             : }
    1109             : 
    1110             : /* gcd(n1,n2)=1, e = gcd(d1,d2).
    1111             :  * phi(n1) = d1*nf1, phi(n2) = d2*nf2.
    1112             :  * d = lcm(d1,d2) = d1*d2/e, nf = phi(n1)*phi(n2)/d = nf1*nf2*e. */
    1113             : static GEN
    1114           7 : FpX_factcyclo_lift(long n1, GEN v1, long n2, GEN v2, GEN p, long m)
    1115             : {
    1116           7 :   pari_sp av = avma;
    1117           7 :   long d1 = degpol(gel(v1, 1)), lv1 = lg(v1), nf1 = eulerphiu(n1)/d1;
    1118           7 :   long d2 = degpol(gel(v2, 1)), lv2 = lg(v2), nf2 = eulerphiu(n2)/d2;
    1119           7 :   long e = ugcd(d1, d2), nf = nf1*nf2*e, need_factor = (e!=1);
    1120           7 :   long i, j, k = 0;
    1121           7 :   GEN z = NULL, v;
    1122             :   pari_timer ti;
    1123             : 
    1124           7 :   if (DEBUGLEVEL >= 6) timer_start(&ti);
    1125           7 :   if (m != 1) m = nf;
    1126           7 :   v = cgetg(1+m, t_VEC);
    1127           7 :   if (m == 1)
    1128             :   {
    1129           0 :     GEN x1 = gel(v1, 1), x2 = gel(v2, 1);
    1130           0 :     z = FpX_gcd(RgX_inflate(x1, n2), RgX_inflate(x2, n1), p);
    1131           0 :     z = FpX_normalize(z, p);  /* FpX_gcd sometimes returns non-monic */
    1132           0 :     gel(v, 1) = (!need_factor)? z : gmael(FpX_factor(z, p), 1, 1);
    1133             :   }
    1134             :   else
    1135             :   {
    1136          91 :     for (i = 1; i < lv1; i++)
    1137         420 :       for (j = 1; j < lv2; j++)
    1138             :       {
    1139         336 :         GEN x1 = gel(v1, i), x2 = gel(v2, j);
    1140         336 :         z = FpX_gcd(RgX_inflate(x1, n2), RgX_inflate(x2, n1), p);
    1141         336 :         z = FpX_normalize(z, p);  /* needed */
    1142         336 :         if (!need_factor) gel(v, ++k) = z;
    1143             :         else
    1144             :         {
    1145           0 :           GEN z1 = gel(FpX_factor(z, p), 1);
    1146           0 :           long i, l = lg(z1);
    1147           0 :           for (i = 1; i < l; i++) gel(v, ++k) = gel(z1, i);
    1148             :         }
    1149             :       }
    1150             :   }
    1151           7 :   if (DEBUGLEVEL >= 6)
    1152           0 :     timer_printf(&ti, "FpX_factcyclo_lift (%ld,%ld)*(%ld,%ld)-->(%ld,%ld)-->(%ld,%ld)",
    1153           0 :         d1, nf1, d2, nf2, degpol(z), nf1*nf2, d1*d2/e, nf);
    1154           7 :   return gerepilecopy(av, v);
    1155             : }
    1156             : 
    1157             : /* n is any integer prime to p; d>1 and f>1 */
    1158             : static GEN
    1159        1349 : FpX_factcyclo_gen(GEN GH, ulong n, GEN p, long m)
    1160             : {
    1161        1349 :   GEN fn = factoru(n), fa = zm_to_ZM(fn);
    1162             :   GEN A, T, X, pd_n, v, pols;
    1163        1349 :   long i, j, pmodn = umodiu(p, n), phin = eulerphiu_fact(fn);
    1164        1349 :   long d = Fl_order(pmodn, phin, n), f = phin/d;
    1165             :   pari_timer ti;
    1166             : 
    1167        1349 :   if (m != 1) m = f;
    1168        1349 :   if (m != 1 && GH==NULL) /* FpX_factcyclo_fact is used */
    1169             :   {
    1170         381 :     GEN H = znstar_generate(n, mkvecsmall(pmodn));
    1171         381 :     GH = znstar_cosets(n, phin, H); /* representatives of G/H */
    1172             :   }
    1173             : 
    1174        1349 :   pols = cgetg(1+m, t_VEC);
    1175        1349 :   v = cgetg(1+d, t_VEC);
    1176        1349 :   pd_n = diviuexact(subis(powiu(p, d), 1), n); /* (p^d-1)/n */
    1177        1349 :   T = init_Fq(p, d, 1);
    1178        1349 :   A = pol_x(1);  /* A is a generator of F_q, q=p^d */
    1179        1349 :   if (d == 1) A = FpX_rem(A, T, p);
    1180        1349 :   random_FpX(degpol(T), varn(T), p); /* skip 1st one */
    1181        1349 :   if (DEBUGLEVEL >= 6) timer_start(&ti);
    1182        1791 :   do X = FpXQ_pow(random_FpX(degpol(T), varn(T), p), pd_n, T, p);
    1183        1791 :   while(lg(X)<3 || equaliu(FpXQ_order(X, fa, T, p), n)==0); /* find zeta_n */
    1184        1349 :   if (DEBUGLEVEL >= 6) timer_printf(&ti, "find X");
    1185             : 
    1186        1349 :   if (m == 1)
    1187             :   {
    1188        2854 :     for (j = 1; j <= d; j++)
    1189             :     {
    1190        2183 :       gel(v, j) = pol_x(0);
    1191        2183 :       gmael(v, j, 2) = FpX_neg(X, p);
    1192        2183 :       if (j < d) X = FpXQ_pow(X, p, T, p);
    1193             :     }
    1194         671 :     gel(pols, 1) = ZXX_evalx0(FpXQXV_prod(v, T, p));
    1195             :   }
    1196             :   else
    1197             :   {
    1198             :     GEN vX, vp;
    1199         678 :     if (DEBUGLEVEL >= 6) timer_start(&ti);
    1200         678 :     vX = FpXQ_powers(X, n, T, p)+1;
    1201         678 :     vp = Fl_powers(pmodn, d, n);
    1202        7884 :     for (i = 1; i <= m; i++)
    1203             :     {
    1204       68694 :       for (j = 1; j <= d; j++)
    1205             :       {
    1206       61488 :         gel(v, j) = pol_x(0);
    1207       61488 :         gmael(v, j, 2) = FpX_neg(gel(vX, Fl_mul(GH[i], vp[j], n)), p);
    1208             :       }
    1209        7206 :       gel(pols, i) = ZXX_evalx0(FpXQXV_prod(v, T, p));
    1210             :     }
    1211         678 :     if (DEBUGLEVEL >= 6) timer_printf(&ti, "FpXQXV_prod");
    1212             :   }
    1213        1349 :   return pols;
    1214             : }
    1215             : 
    1216             : static GEN Flx_factcyclo_newton_pre(GEN Data, GEN N, ulong p, ulong m);
    1217             : /* n is an odd prime power prime to p and equal to the conductor
    1218             :  * of the splitting field of p in Q(zeta_n). d>1 and nf>1 */
    1219             : static GEN
    1220       33460 : FpX_factcyclo_newton_power(GEN N, GEN p, ulong m, int small)
    1221             : {
    1222             :   GEN Rs, H, T, F, pr, prs, pu, Data;
    1223       33460 :   long n = N[1], el = N[2], phin = N[4], g = N[5];
    1224       33460 :   long pmodn = umodiu(p, n), pmodel = umodiu(p, el);
    1225       33460 :   long d = Fl_order(pmodel, el-1, el), nf = phin/d;
    1226       33460 :   long r, s = 0, u = 1;
    1227             : 
    1228       33460 :   if (m != 1) m = nf;
    1229       35700 :   for (pu = p; cmpiu(pu,d) <= 0; u++) pu = mulii(pu,p);  /* d<p^u, pu=p^u */
    1230       33460 :   H = Fl_powers(pmodn, d, n);
    1231       33460 :   T = galoissubcyclo(utoi(n), utoi(pmodn), 0, 0);
    1232       33460 :   F = gausspol(T, H, N, d, nf, g);
    1233       33460 :   r = QX_den_pval(F, p);
    1234       33460 :   Rs = ZpX_roots_all(T, p, nf, &s);
    1235       33460 :   if (DEBUGLEVEL >= 2) err_printf("(u,s,r)=(%ld,%ld,%ld)\n",u,s,r);
    1236       33460 :   pr = powiu(p, r); prs = powiu(p, r+s); /* Usually, r=0, s=1, pr=1, prs=p */
    1237       33460 :   F = r ? RgX_to_FpX(RgX_Rg_mul(F, pr), prs) : RgX_to_FpX(F, prs);
    1238       33460 :   Data = mkvec4(T, F, Rs, mkvecsmalln(6, d, nf, g, r, s, u));
    1239       33460 :   if (small && lgefint(pu) == 3)
    1240       31564 :     return Flx_factcyclo_newton_pre(Data, N, uel(p,2), m);
    1241             :   else
    1242        1896 :     return FpX_factcyclo_newton_pre(Data, N, p, m);
    1243             : }
    1244             : 
    1245             : static GEN
    1246        2802 : FpX_split(ulong n, GEN p, ulong m)
    1247             : {
    1248             :   ulong i, j;
    1249        2802 :   GEN v, C, vx, z = rootsof1u_Fp(n, p);
    1250        2802 :   if (m == 1) return mkvec(deg1pol_shallow(gen_1, Fp_neg(z,p), 0));
    1251        1401 :   v = cgetg(m+1, t_VEC); C = coprimes_zv(n); vx = Fp_powers(z, n-1, p);
    1252       18495 :   for (i = j = 1; i <= n; i++)
    1253       17094 :     if (C[i]) gel(v, j++) = deg1pol_shallow(gen_1, Fp_neg(gel(vx,i+1), p), 0);
    1254        1401 :   return gen_sort(v, (void*)cmpii, &gen_cmp_RgX);
    1255             : }
    1256             : 
    1257             : /* n is a prime power prime to p. n is not necessarily equal to the
    1258             :  * conductor of the splitting field of p in Q(zeta_n). */
    1259             : static GEN
    1260        2658 : FpX_factcyclo_prime_power_i(long el, long e, GEN p, long m)
    1261             : {
    1262        2658 :   GEN z = set_e0_e1(el, e, p), v;
    1263        2658 :   long n = z[1], e0 = z[2], e1 = z[3], phin = z[4], g = z[5];
    1264        2658 :   long d = z[6], f = z[7]; /* d and f for n=el^e0 */
    1265             : 
    1266        2658 :   if (f == 1) v = mkvec(FpX_polcyclo(n, p));
    1267        2658 :   else if (d == 1) v = FpX_split(n, p, (m==1)? 1: f);
    1268        2658 :   else if (el == 2) v = FpX_factcyclo_gen(NULL, n, p, m); /* d==2 in this case */
    1269        2658 :   else if (!use_newton(d,f)) v = FpX_factcyclo_gen(NULL, n, p, m);
    1270             :   else
    1271             :   {
    1272        1896 :     GEN N = mkvecsmall5(n, el, e0, phin, g);
    1273        1896 :     v = FpX_factcyclo_newton_power(N, p, m, 0);
    1274             :   }
    1275        2658 :   if (e1)
    1276             :   {
    1277           0 :     long i, l = lg(v), ele1 = upowuu(el, e1);
    1278           0 :     for (i = 1; i < l; i++) gel(v, i) = RgX_inflate(gel(v, i), ele1);
    1279             :   }
    1280        2658 :   return v;
    1281             : }
    1282             : static GEN
    1283          14 : FpX_factcyclo_prime_power(long el, long e, GEN p, long m)
    1284             : {
    1285          14 :   pari_sp av = avma;
    1286          14 :   return gerepilecopy(av, FpX_factcyclo_prime_power_i(el, e, p, m));
    1287             : }
    1288             : 
    1289             : static GEN
    1290           7 : FpX_factcyclo_fact(GEN fn, GEN p, ulong m, long ascent)
    1291             : {
    1292           7 :   GEN EL = gel(fn, 1), E = gel(fn, 2), v1 = NULL;
    1293           7 :   long i, l = lg(EL), n1 = 1;
    1294             : 
    1295          21 :   for (i = 1; i < l; i++)
    1296             :   {
    1297          14 :     long j = ascent? i: l-i, n2 = upowuu(EL[j], E[j]);
    1298          14 :     GEN v2 = FpX_factcyclo_prime_power(EL[j], E[j], p, m);
    1299          14 :     v1 = v1? FpX_factcyclo_lift(n1, v1, n2, v2, p, m): v2;
    1300          14 :     n1 *= n2;
    1301             :   }
    1302           7 :   return v1;
    1303             : }
    1304             : 
    1305             : static GEN
    1306       15807 : Flv_FlvV_factorback(GEN g, GEN x, ulong q)
    1307       34270 : { pari_APPLY_ulong(Flv_factorback(g, gel(x,i), q)) }
    1308             : 
    1309             : /* return the structure and the generators of G/H. G=(Z/nZ)^, H=<p>.
    1310             :  * For efficiency assume p mod n != 1 (trivial otherwise) */
    1311             : static GEN
    1312       15807 : get_GH_gen(long n, long pmodn)
    1313             : {
    1314       15807 :   GEN G = znstar0(utoipos(n), 1), cycG = znstar_get_cyc(G);
    1315             :   GEN cycGH, gG, gGH, Ui, P;
    1316             :   ulong expG;
    1317       15807 :   P = hnfmodid(mkmat(Zideallog(G, utoi(pmodn))), cycG);
    1318       15807 :   cycGH = ZV_to_nv(ZM_snf_group(P, NULL, &Ui));
    1319       15807 :   expG = itou(cyc_get_expo(cycG));
    1320       15807 :   gG = ZV_to_Flv(znstar_get_gen(G), n);
    1321       15807 :   gGH = Flv_FlvV_factorback(gG, ZM_to_Flm(Ui, expG), n);
    1322       15807 :   return mkvec2(gGH, cycGH);
    1323             : }
    1324             : 
    1325             : /* 1st output */
    1326             : static void
    1327           0 : header(GEN fn, long n, long d, long f, GEN p)
    1328             : {
    1329           0 :   GEN EL = gel(fn, 1), E = gel(fn, 2);
    1330           0 :   long i, l = lg(EL)-1;
    1331           0 :   err_printf("n=%lu=", n);
    1332           0 :   for (i = 1; i <= l; i++)
    1333             :   {
    1334           0 :     long el = EL[i], e = E[i];
    1335           0 :     err_printf("%ld", el);
    1336           0 :     if (e > 1) err_printf("^%ld", e);
    1337           0 :     if (i < l) err_printf("*");
    1338             :   }
    1339           0 :   err_printf(", p=%Ps, phi(%lu)=%lu*%lu\n", p, n, d, f);
    1340           0 :   err_printf("(n,d,f) : (%ld,%ld,%ld) --> ",n,d,f);
    1341           0 : }
    1342             : 
    1343             : static ulong
    1344       94605 : FpX_factcyclo_just_conductor_init(GEN *pData, ulong n, GEN p, ulong m)
    1345             : {
    1346       94605 :   GEN fn = factoru(n), GH = NULL, GHgen = NULL;
    1347       94605 :   long phin = eulerphiu_fact(fn), pmodn = umodiu(p, n);
    1348       94605 :   long d = Fl_order(pmodn, phin, n), f = phin/d; /* d > 1 */
    1349       94605 :   ulong action = set_action(fn, p, d, f);
    1350       94605 :   if (action & ~NEWTON_POWER)
    1351             :   { /* needed for GENERAL* */
    1352       60390 :     GEN H = znstar_generate(n, mkvecsmall(pmodn));
    1353       60390 :     GH = znstar_cosets(n, phin, H); /* representatives of G/H */
    1354       60390 :     if (action & (NEWTON_GENERAL_NEW | NEWTON_GENERAL))
    1355       15807 :       GHgen = get_GH_gen(n, pmodn);  /* gen and order of G/H */
    1356             :   }
    1357       94605 :   *pData = mkvec5(GHgen, GH, fn, p, mkvecsmall4(n, d, f, m));
    1358       94605 :   if (DEBUGLEVEL >= 1)
    1359             :   {
    1360           0 :     err_printf("(%ld,%ld,%ld)  action=%ld\n", n, d, f, action);
    1361           0 :     if (GHgen)
    1362             :     {
    1363           0 :       GEN cycGH = gel(GHgen,2), gGH = gel(GHgen,1);
    1364           0 :       err_printf("G(K/Q)=%Ps gen=%Ps\n", zv_to_ZV(cycGH), zv_to_ZV(gGH));
    1365             :     }
    1366             :   }
    1367       94605 :   return action;
    1368             : }
    1369             : 
    1370             : static GEN
    1371        5698 : FpX_factcyclo_just_conductor(ulong n, GEN p, ulong m)
    1372             : {
    1373             :   GEN Data, fn;
    1374        5698 :   ulong action = FpX_factcyclo_just_conductor_init(&Data, n, p, m);
    1375        5698 :   fn = gel(Data,3);
    1376        5698 :   if (action & GENERAL)
    1377         587 :     return FpX_factcyclo_gen(gel(Data,2), n, p, m);
    1378        5111 :   else if (action & NEWTON_POWER)
    1379        2644 :     return FpX_factcyclo_prime_power_i(ucoeff(fn,1,1), ucoeff(fn,1,2), p, m);
    1380        2467 :   else if (action & NEWTON_GENERAL)
    1381        2414 :     return FpX_factcyclo_newton_general(Data);
    1382          53 :   else if (action & NEWTON_GENERAL_NEW)
    1383          46 :     return FpX_factcyclo_newton_general_new3(Data);
    1384             :   else
    1385           7 :     return FpX_factcyclo_fact(fn, p, m, action & ASCENT);
    1386             : }
    1387             : 
    1388             : static GEN
    1389       10656 : FpX_factcyclo_i(ulong n, GEN p, long fl)
    1390             : {
    1391       10656 :   GEN fn = factoru(n), z;
    1392       10656 :   long phin = eulerphiu_fact(fn), pmodn = umodiu(p, n);
    1393       10656 :   ulong d = Fl_order(pmodn, phin, n), f = phin/d, fK;
    1394             : 
    1395       10656 :   if (DEBUGLEVEL >= 1) header(fn, n, d, f, p);
    1396       10656 :   if (f == 1) { z = FpX_polcyclo(n, p); return fl? z: mkvec(z); }
    1397        8500 :   else if (d == 1) /* p=1 (mod n), zeta_n in Z_p */
    1398         774 :   { z = FpX_split(n, p, fl? 1: f); return fl? gel(z,1): z; }
    1399        7726 :   fK = znstar_conductor(znstar_generate(n, mkvecsmall(pmodn)));
    1400        7726 :   if (fK != n && umodiu(p, fK) == 1)
    1401        2028 :     z = FpX_split(fK, p, fl? 1: f);
    1402             :   else
    1403        5698 :     z = FpX_factcyclo_just_conductor(fK, p, fl? 1: f);
    1404        7726 :   if (n > fK)
    1405             :   {
    1406        4294 :     GEN vP = const_vec(n, NULL);
    1407        4294 :     long i, l = fl? 2: lg(z);
    1408       14795 :     for (i = 1; i < l; i++)
    1409       10501 :       gel(z, i) = FpX_conductor_lift(gel(z, i), p, fn, fK, vP);
    1410             :   }
    1411        7726 :   return fl? gel(z,1): gen_sort(z,(void*)cmpii, &gen_cmp_RgX);
    1412             : }
    1413             : 
    1414             : GEN
    1415          42 : FpX_factcyclo(ulong n, GEN p, ulong m)
    1416          42 : { pari_sp av = avma; return gerepilecopy(av, FpX_factcyclo_i(n, p, m)); }
    1417             : 
    1418             : /*  Data = [H, GH, i_t, d0, kT, [n, d, f, n_T, mitk]]
    1419             :  *  N2 = [p, pr, pu, pru] */
    1420             : static GEN
    1421       24102 : Flx_pol_newton_general(GEN Data, GEN N2, GEN vT, ulong x)
    1422             : {
    1423       24102 :   GEN i_t = gel(Data, 3), kT = gel(Data, 5), N = gel(Data, 6);
    1424       24102 :   long k, d = N[2], n_T = N[4], mitk = N[5];
    1425       24102 :   long p = N2[1], pr = N2[2], pu = N2[3], pru = N2[4];
    1426       24102 :   GEN R = cgetg(1+mitk, t_VECSMALL);
    1427             : 
    1428      123717 :   for (k = 1; k <= n_T; k++) uel(R,kT[k]) = Flx_eval(gel(vT, kT[k]), x, pru) / pr;
    1429       24102 :   return Flx_Newton_perm(d, R, i_t, pu, p);
    1430             : }
    1431             : 
    1432             : /* n is any integer prime to p, but must be equal to the conductor
    1433             :  * of the splitting field of p in Q(zeta_n).
    1434             :  * GH=G/H={g_1, ... ,g_f}
    1435             :  * Data = [GHgen, GH, fn, p, [n, d, f, m]] */
    1436             : static GEN
    1437       13340 : Flx_factcyclo_newton_general(GEN Data)
    1438             : {
    1439       13340 :   GEN GH = gel(Data, 2), fn = gel(Data, 3), p = gel(Data, 4);
    1440       13340 :   ulong up = p[2], n = mael(Data, 5, 1), pmodn = up%n;
    1441       13340 :   long d = mael(Data, 5, 2), f = mael(Data, 5, 3), m = mael(Data, 5, 4);
    1442       13340 :   long i, k, n_T, mitk, r, s = 0, u = 1;
    1443             :   GEN vT, kT, H, i_t, T, d0d1, Data2, Data3, R, Rs, pr, pu, pru;
    1444             :   pari_timer ti;
    1445             : 
    1446       13340 :   if (m != 1) m = f;
    1447       14593 :   for (pu = p; cmpiu(pu,d) <= 0; u++) pu = muliu(pu, up);  /* d<pu, pu=p^u */
    1448             : 
    1449       13340 :   H = Fl_powers(pmodn, d-1, n); /* H=<p> */
    1450       13340 :   i_t = get_i_t(n, pmodn); /* i_t[1+i]=k ==> t_i=t_k */
    1451       13340 :   kT = get_kT(i_t, d); n_T = lg(kT)-1; mitk = kT[n_T];
    1452       13340 :   if (DEBUGLEVEL == 2) err_printf("kT=%Ps %ld elements\n",kT,n_T);
    1453       13340 :   if (DEBUGLEVEL >= 6) timer_start(&ti);
    1454       13340 :   T = galoissubcyclo(utoi(n), utoi(pmodn), 0, 0);
    1455       13340 :   if (DEBUGLEVEL >= 6) timer_printf(&ti, "galoissubcyclo");
    1456       13340 :   d0d1 = get_d0_d1(T, gel(fn,1)); /* d0*T_k(x) is in Z[x] */
    1457       13340 :   Data2 = mkvecn(6, H, GH, i_t, d0d1, kT, mkvecsmalln(5, n, d, f, n_T, mitk));
    1458       13340 :   vT = get_vT(Data2, 0);
    1459       13340 :   if (DEBUGLEVEL == 4) err_printf("vT=%Ps\n",vT);
    1460       13340 :   r = QXV_den_pval(vT, kT, p);
    1461       13340 :   Rs = ZpX_roots_all(T, p, f, &s);
    1462       13340 :   if (DEBUGLEVEL >= 2) err_printf("(u,s,r)=(%ld,%ld,%ld)\n",u,s,r);
    1463       13340 :   if (r+u < s) pari_err_BUG("Flx_factcyclo_newton_general, T is not separable mod p^(r+u)");
    1464             :   /* R and vT are mod p^(r+u) */
    1465       13340 :   R = (r+u==s) ? Rs : ZV_sort_shallow(ZX_Zp_liftroots(T, Rs, p, s, r+u));
    1466       13340 :   pr = powiu(p, r); pru = powiu(p, r+u); /* Usually, r=0, s=1, pr=1, pru=p */
    1467       13340 :   if (lgefint(pru) > 3)  /* ULONG_MAX < p^(r+u), probably won't occur */
    1468             :   {
    1469           0 :     for (k = 1; k <= n_T; k++)
    1470             :     {
    1471           0 :       long itk = kT[k];
    1472           0 :       GEN z = r? RgX_Rg_mul(gel(vT, itk), pr): gel(vT, itk);
    1473           0 :       gel(vT, itk) = RgX_to_FpX(z, pru);
    1474             :     }
    1475           0 :     Data3 = mkvec4(p, pr, pu, pru);
    1476           0 :     for (i = 1; i <= m; i++)
    1477           0 :       gel(R,i) = ZX_to_nx(FpX_pol_newton_general(Data2, Data3, vT, gel(R,i)));
    1478           0 :     if (DEBUGLEVEL >= 6) timer_printf(&ti, "FpX_pol_newton_general");
    1479             :   }
    1480             :   else
    1481             :   {
    1482       13340 :     ulong upr = itou(pr), upru = itou(pru), upu = itou(pu);
    1483       63651 :     for (k = 1; k <= n_T; k++)
    1484             :     {
    1485       50311 :       long itk = kT[k];
    1486       50311 :       GEN z = r? RgX_muls(gel(vT, itk), upr): gel(vT, itk);
    1487       50311 :       gel(vT, itk) = RgX_to_Flx(z, upru);
    1488             :     }
    1489       13340 :     Data3 = mkvecsmall4(up, upr, upu, upru);
    1490       13340 :     if (DEBUGLEVEL >= 6) timer_start(&ti);
    1491       37442 :     for (i = 1; i <= m; i++)
    1492       24102 :       gel(R,i) = Flx_pol_newton_general(Data2, Data3, vT, itou(gel(R,i)));
    1493       13340 :     if (DEBUGLEVEL >= 6) timer_printf(&ti, "Flx_pol_newton_general");
    1494             :   }
    1495       13340 :   return R;
    1496             : }
    1497             : 
    1498             : /*  Data=[vT, gGH, Rs, Rrs, i_t, kt, p, pu, pr, prs,
    1499             :  *       [n, r, s, n_t, mitk, d], div] */
    1500             : static GEN
    1501         336 : Flx_pol_newton_general_new3(GEN Data, long k)
    1502             : {
    1503         336 :   GEN i_t = gel(Data,5), p = gel(Data,7), pu = gel(Data,8), prs = gel(Data,10);
    1504         336 :   long d = mael(Data, 11, 6);
    1505          48 :   GEN v_t_p = (lgefint(prs)>3)? ZV_to_nv(Fp_mk_v_t_p3(Data, k))
    1506         336 :                               : Fl_mk_v_t_p3(Data, k);
    1507         336 :   if (DEBUGLEVEL == 3) err_printf("v_t_p=%Ps\n",v_t_p);
    1508         336 :   return Flx_Newton_perm(d, v_t_p, i_t, pu[2], p[2]);
    1509             : }
    1510             : 
    1511             : /* Data = [GHgen, GH, fn, p, [n, d, f, m]] */
    1512             : static GEN
    1513           7 : Flx_factcyclo_newton_general_new3(GEN Data)
    1514             : {
    1515           7 :   long i, f = mael(Data, 5, 3), m = mael(Data, 5, 4);
    1516             :   GEN Data2, pu, pols;
    1517             :   pari_timer ti;
    1518             : 
    1519           7 :   if (m != 1) m = f;
    1520           7 :   pols = cgetg(1+m, t_VEC);
    1521           7 :   Data2 = newton_general_new_pre3(Data); pu = gel(Data2, 8);
    1522             :   /* Data2 = [vT, gGH, Rs, Rrs, i_t, kt, p, pu, pr, prs,
    1523             :               [n, r, s, n_t, mitk, d], div] */
    1524           7 :   if (DEBUGLEVEL >= 6) timer_start(&ti);
    1525           7 :   if (lgefint(pu) > 3)  /* ULONG_MAX < p^u, probably won't occur */
    1526           0 :   { for (i = 1; i <= m; i++)
    1527           0 :       gel(pols, i) = ZX_to_nx(FpX_pol_newton_general_new3(Data2, i));
    1528           0 :     if (DEBUGLEVEL >= 6) timer_printf(&ti, "FpX_pol_newton_general_new3"); }
    1529             :   else
    1530         343 :   { for (i = 1; i <= m; i++)
    1531         336 :       gel(pols, i) = Flx_pol_newton_general_new3(Data2, i);
    1532           7 :     if (DEBUGLEVEL >= 6) timer_printf(&ti, "Flx_pol_newton_general_new3"); }
    1533           7 :   return pols;
    1534             : }
    1535             : 
    1536             : /* return normalized z(-x) */
    1537             : static GEN
    1538       65972 : Flx_1st_lift_2(GEN z, ulong p)
    1539             : {
    1540       65972 :   long i, r = lg(z);
    1541       65972 :   GEN x = cgetg(r, t_VECSMALL);
    1542       65972 :   x[1] = z[1];
    1543       65972 :   if (odd(r))
    1544      194270 :     for (i = 2; i<r; i++) uel(x,i) = odd(i)? Fl_neg(uel(z,i), p) : uel(z,i);
    1545             :   else
    1546      231633 :     for (i = 2; i<r; i++) uel(x,i) = odd(i)? uel(z,i): Fl_neg(uel(z,i), p);
    1547       65972 :   return x;
    1548             : }
    1549             : 
    1550             : /* el does not divides e.
    1551             :  * construct Phi_{e*el}(x) from Phi_e(x). */
    1552             : static GEN
    1553       42709 : Flx_1st_lift(GEN z, ulong p, ulong e, ulong el, GEN vP)
    1554             : {
    1555       42709 :    GEN z2, z3, P = gel(vP, e);
    1556       42709 :    if (!gel(vP, e)) P = gel(vP, e) = Flx_polcyclo(e, p);
    1557       42709 :    z2 = Flx_inflate(z, el);
    1558       42709 :    z3 = Flx_normalize(Flx_gcd(P, z2, p), p);
    1559       42709 :    return Flx_div(z2, z3, p);
    1560             : }
    1561             : 
    1562             : static GEN
    1563      158258 : Flx_lift(GEN z, ulong p, ulong e, ulong el, ulong r, ulong s, GEN vP)
    1564             : {
    1565      158258 :   if (s == 0)
    1566             :   {
    1567      108681 :     z = (el==2) ? Flx_1st_lift_2(z, p) : Flx_1st_lift(z, p, e, el, vP);
    1568      108681 :     if (r >= 2) z = Flx_inflate(z, upowuu(el, r-1));
    1569             :   }
    1570             :   else
    1571       49577 :     z = Flx_inflate(z, upowuu(el, r-s));
    1572      158258 :   return z;
    1573             : }
    1574             : 
    1575             : /* e is the conductor of the splitting field of p in Q(zeta_n) */
    1576             : static GEN
    1577      140965 : Flx_conductor_lift(GEN z, ulong p, GEN fn, ulong e, GEN vP)
    1578             : {
    1579      140965 :   GEN EL = gel(fn, 1), En = gel(fn, 2);
    1580      140965 :   long i, r = lg(EL), new_e = e;
    1581             : 
    1582      432170 :   for (i = 1; i < r; i++)
    1583             :   {
    1584      291205 :     long el = EL[i], en = En[i], ee = u_lval(e, el);
    1585      291205 :     if (ee < en)
    1586             :     {
    1587      158258 :       z = Flx_lift(z, p, new_e, el, en, ee, vP);
    1588      158258 :       new_e *= upowuu(el, en-ee);
    1589             :     }
    1590             :   }
    1591      140965 :   return z;
    1592             : }
    1593             : 
    1594             : /* R0 is mod p^u, d < p^u */
    1595             : static GEN
    1596       57409 : Flx_pol_newton(long j, GEN R0, GEN E, GEN D3, long d, long f, ulong p)
    1597             : {
    1598       57409 :   ulong u = D3[3];
    1599       57409 :   GEN R = cgetg(f+1, t_VECSMALL);
    1600             :   long i;
    1601      233473 :   for (i = 1; i <= f; i++) R[i] = R0[1+(i+j)%f];
    1602       57409 :   return Flx_Newton_perm(d, R, E, upowuu(p,u), p);
    1603             : }
    1604             : 
    1605             : /* Data = [T, F, Rs, [d, nf, g, r, s, u]], nf>1 */
    1606             : static GEN
    1607       31564 : Flx_factcyclo_newton_pre(GEN Data, GEN N, ulong p, ulong m)
    1608             : {
    1609       31564 :   GEN T = gel(Data, 1), F = gel(Data, 2), Rs = gel(Data, 3), D4 = gel(Data, 4);
    1610       31564 :   long d = D4[1], nf = D4[2], g = D4[3], r = D4[4], s = D4[5], u = D4[6];
    1611       31564 :   GEN pols, E, R, p0 = utoi(p), Data3;
    1612       31564 :   ulong i, n = N[1], pmodn = p%n;
    1613             :   pari_timer ti;
    1614             : 
    1615       31564 :   if (m != 1) m = nf;
    1616       31564 :   pols = cgetg(1+m, t_VEC);
    1617       31564 :   E = set_E(pmodn, n, d, nf, g);
    1618       31564 :   R = set_R(T, F, Rs, p0, nf, r, s, u);
    1619       31564 :   R = ZV_to_nv(R);
    1620       31564 :   Data3 = mkvecsmall3(r, s, u);
    1621       31564 :   if (DEBUGLEVEL >= 6) timer_start(&ti);
    1622       88973 :   for (i = 1; i <= m; i++) gel(pols, i) = Flx_pol_newton(i, R,E,Data3, d,nf,p);
    1623       31564 :   if (DEBUGLEVEL >= 6) timer_printf(&ti, "Flx_pol_newton");
    1624       31564 :   return pols;
    1625             : }
    1626             : 
    1627             : /* gcd(n1,n2)=1, e = gcd(d1,d2).
    1628             :  * phi(n1) = d1*nf1, phi(n2) = d2*nf2.
    1629             :  * d = lcm(d1,d2) = d1*d2/e, nf = phi(n1)*phi(n2)/d = nf1*nf2*e. */
    1630             : static GEN
    1631           0 : Flx_factcyclo_lift(long n1, GEN v1, long n2, GEN v2, long p, long m)
    1632             : {
    1633           0 :   pari_sp av = avma;
    1634           0 :   long d1 = degpol(gel(v1, 1)), lv1 = lg(v1), nf1 = eulerphiu(n1)/d1;
    1635           0 :   long d2 = degpol(gel(v2, 1)), lv2 = lg(v2), nf2 = eulerphiu(n2)/d2;
    1636           0 :   long e = ugcd(d1, d2), nf = nf1*nf2*e, need_factor = (e!=1);
    1637           0 :   long i, j, k = 0;
    1638           0 :   GEN v, z = NULL;
    1639             :   pari_timer ti;
    1640             : 
    1641           0 :   if (DEBUGLEVEL >= 6) timer_start(&ti);
    1642           0 :   if (m != 1) m = nf;
    1643           0 :   v = cgetg(1+m, t_VEC);
    1644           0 :   if (m == 1)
    1645             :   {
    1646           0 :     GEN x1 = gel(v1, 1), x2 = gel(v2, 1);
    1647           0 :     z = Flx_gcd(Flx_inflate(x1, n2), Flx_inflate(x2, n1), p);
    1648           0 :     z = Flx_normalize(z, p);  /* Flx_gcd sometimes returns non-monic */
    1649           0 :     gel(v, 1) = (!need_factor)? z : gmael(Flx_factor(z, p), 1, 1);
    1650             :   }
    1651             :   else
    1652           0 :     for (i = 1; i < lv1; i++)
    1653           0 :       for (j = 1; j < lv2; j++)
    1654             :       {
    1655           0 :         GEN x1 = gel(v1, i), x2 = gel(v2, j);
    1656           0 :         z = Flx_gcd(Flx_inflate(x1, n2), Flx_inflate(x2, n1), p);
    1657           0 :         z = Flx_normalize(z, p);  /* needed */
    1658           0 :         if (!need_factor) gel(v, ++k) = z;
    1659             :         else
    1660             :         {
    1661           0 :           GEN z1 = gel(Flx_factor(z, p), 1);
    1662           0 :           long i, l = lg(z1);
    1663           0 :           for (i = 1; i < l; i++) gel(v, ++k) = gel(z1, i);
    1664             :         }
    1665             :       }
    1666           0 :   if (DEBUGLEVEL >= 6)
    1667           0 :     timer_printf(&ti, "Flx_factcyclo_lift (%ld,%ld)*(%ld,%ld)-->(%ld,%ld)-->(%ld,%ld)",
    1668           0 :         d1, nf1, d2, nf2, degpol(z), nf1*nf2, d1*d2/e, nf);
    1669           0 :   return gerepilecopy(av, v);
    1670             : }
    1671             : 
    1672             : /* factor polcyclo(n) mod p based on an idea of Bill Allombert; d>1 and nf>1 */
    1673             : static GEN
    1674       43996 : Flx_factcyclo_gen(GEN GH, ulong n, ulong p, ulong m)
    1675             : {
    1676       43996 :   GEN fu = factoru(n), fa = zm_to_ZM(fu), p0 = utoi(p);
    1677             :   GEN T, X, pd_n, v, pols;
    1678       43996 :   ulong i, j, pmodn = p%n, phin = eulerphiu_fact(fu);
    1679       43996 :   ulong d = Fl_order(pmodn, phin, n), nf = phin/d;
    1680             :   pari_timer ti;
    1681             : 
    1682       43996 :   if (m != 1) m = nf;
    1683       43996 :   if (m != 1 && !GH) /* Flx_factcyclo_fact is used */
    1684             :   {
    1685           0 :     GEN H = znstar_generate(n, mkvecsmall(pmodn));
    1686           0 :     GH = znstar_cosets(n, phin, H); /* representatives of G/H */
    1687             :   }
    1688             : 
    1689       43996 :   pols = cgetg(1+m, t_VEC);
    1690       43996 :   v = cgetg(1+d, t_VEC);
    1691       43996 :   pd_n = diviuexact(subis(powiu(p0, d), 1), n); /* (p^d-1)/n */
    1692       43996 :   T = ZX_to_Flx(init_Fq(p0, d, evalvarn(1)), p);
    1693       43996 :   random_Flx(degpol(T), T[1], p);  /* skip 1st one */
    1694       43996 :   if (DEBUGLEVEL >= 6) timer_start(&ti);
    1695       82769 :   do X = Flxq_pow(random_Flx(degpol(T), T[1], p), pd_n, T, p);
    1696       82769 :   while (lg(X)<3 || equaliu(Flxq_order(X, fa, T, p), n)==0); /* find zeta_n */
    1697       43996 :   if (DEBUGLEVEL >= 6) timer_printf(&ti, "find X");
    1698             : 
    1699       43996 :   if (m == 1)
    1700             :   {
    1701      102528 :     for (j = 1; j <= d; j++)
    1702             :     {
    1703       80481 :       gel(v, j) = polx_FlxX(0, 1);
    1704       80481 :       gmael(v, j, 2) = Flx_neg(X, p);
    1705       80481 :       if (j < d) X = Flxq_powu(X, p, T, p);
    1706             :     }
    1707       22047 :     gel(pols, 1) = FlxX_to_Flx(FlxqXV_prod(v, T, p));
    1708             :   }
    1709             :   else
    1710             :   {
    1711             :     GEN vX, vp;
    1712       21949 :     if (DEBUGLEVEL >= 6) timer_start(&ti);
    1713       21949 :     vX = Flxq_powers(X, n, T, p)+1;
    1714       21949 :     vp = Fl_powers(pmodn, d, n);
    1715      190844 :     for (i = 1; i <= m; i++)
    1716             :     {
    1717      757867 :       for (j = 1; j <= d; j++)
    1718             :       {
    1719      588972 :         gel(v, j) = polx_FlxX(0, 1);
    1720      588972 :         gmael(v, j, 2) = Flx_neg(gel(vX, Fl_mul(GH[i], vp[j], n)), p);
    1721             :       }
    1722      168895 :       gel(pols, i) = FlxX_to_Flx(FlxqXV_prod(v, T, p));
    1723             :     }
    1724       21949 :     if (DEBUGLEVEL >= 6) timer_printf(&ti, "FlxqXV_prod");
    1725             :   }
    1726       43996 :   return pols;
    1727             : }
    1728             : 
    1729             : static int
    1730     1734612 : cmpGuGu(GEN a, GEN b) { return (ulong)a < (ulong)b? -1: (a == b? 0: 1); }
    1731             : 
    1732             : /* p=1 (mod n). If m!=1, then m=phi(n) */
    1733             : static GEN
    1734       34186 : Flx_split(ulong n, ulong p, ulong m)
    1735             : {
    1736       34186 :   ulong i, j, z = rootsof1_Fl(n, p);
    1737             :   GEN v, C, vx;
    1738       34186 :   if (m == 1) return mkvec(mkvecsmall3(0, Fl_neg(z,p), 1));
    1739       17016 :   v = cgetg(m+1, t_VEC); C = coprimes_zv(n); vx = Fl_powers(z, n-1, p);
    1740      223026 :   for (i = j = 1; i <= n; i++)
    1741      206010 :     if (C[i]) gel(v, j++) = mkvecsmall3(0, Fl_neg(vx[i+1], p), 1);
    1742       17016 :   return gen_sort(v, (void*)cmpGuGu, &gen_cmp_RgX);
    1743             : }
    1744             : 
    1745             : /* d==1 or f==1 occurs */
    1746             : static GEN
    1747       31564 : Flx_factcyclo_prime_power_i(long el, long e, long p, long m)
    1748             : {
    1749       31564 :   GEN p0 = utoipos(p), z = set_e0_e1(el, e, p0), v;
    1750       31564 :   long n = z[1], e0 = z[2], e1 = z[3], phin = z[4], g = z[5];
    1751       31564 :   long d = z[6], f = z[7]; /* d and f for n=el^e0 */
    1752             : 
    1753       31564 :   if (f == 1) v = mkvec(Flx_polcyclo(n, p));
    1754       31564 :   else if (d == 1) v = Flx_split(n, p, (m==1)?1:f);
    1755       31564 :   else if (el == 2) v = Flx_factcyclo_gen(NULL, n, p, m);/* d==2 in this case */
    1756       31564 :   else if (!use_newton(d, f)) v = Flx_factcyclo_gen(NULL, n, p, m);
    1757             :   else
    1758             :   {
    1759       31564 :     GEN N = mkvecsmall5(n, el, e0, phin, g);
    1760       31564 :     v = FpX_factcyclo_newton_power(N, p0, m, 1);
    1761       31564 :     if (typ(gel(v,1)) == t_POL)
    1762             :     { /* ZX: convert to Flx */
    1763           0 :       long i, l = lg(v);
    1764           0 :       for (i = 1; i < l; i++) gel(v,i) = ZX_to_nx(gel(v,i));
    1765             :     }
    1766             :   }
    1767       31564 :   if (e1)
    1768             :   {
    1769           0 :     long i, l = lg(v), ele1 = upowuu(el, e1);
    1770           0 :     for (i = 1; i < l; i++) gel(v, i) = Flx_inflate(gel(v, i), ele1);
    1771             :   }
    1772       31564 :   return v;
    1773             : }
    1774             : static GEN
    1775           0 : Flx_factcyclo_prime_power(long el, long e, long p, long m)
    1776             : {
    1777           0 :   pari_sp av = avma;
    1778           0 :   return gerepilecopy(av, Flx_factcyclo_prime_power_i(el, e, p, m));
    1779             : }
    1780             : 
    1781             : static GEN
    1782           0 : Flx_factcyclo_fact(GEN fn, ulong p, ulong m, long ascent)
    1783             : {
    1784           0 :   GEN EL = gel(fn, 1), E = gel(fn, 2), v1, v2;
    1785           0 :   long l = lg(EL), i, j, n1, n2;
    1786             : 
    1787           0 :   j = ascent? 1: l-1;
    1788           0 :   n1 = upowuu(EL[j], E[j]);
    1789           0 :   v1 = Flx_factcyclo_prime_power(EL[j], E[j], p, m);
    1790           0 :   for (i = 2; i < l; i++)
    1791             :   {
    1792           0 :     j = ascent? i: l-i;
    1793           0 :     n2 = upowuu(EL[j], E[j]);
    1794           0 :     v2 = Flx_factcyclo_prime_power(EL[j], E[j], p, m);
    1795           0 :     v1 = Flx_factcyclo_lift(n1, v1, n2, v2, p, m);
    1796           0 :     n1 *= n2;
    1797             :   }
    1798           0 :   return v1;
    1799             : }
    1800             : 
    1801             : static GEN
    1802       88907 : Flx_factcyclo_just_conductor(ulong n, ulong p, ulong m)
    1803             : {
    1804             :   GEN Data, fn;
    1805       88907 :   ulong action = FpX_factcyclo_just_conductor_init(&Data, n, utoipos(p), m);
    1806       88907 :   fn = gel(Data,3);
    1807       88907 :   if (action & GENERAL)
    1808       43996 :     return Flx_factcyclo_gen(gel(Data,2), n, p, m);
    1809       44911 :   else if (action & NEWTON_POWER)
    1810       31564 :     return Flx_factcyclo_prime_power_i(ucoeff(fn,1,1), ucoeff(fn,1,2), p, m);
    1811       13347 :   else if (action & NEWTON_GENERAL)
    1812       13340 :     return Flx_factcyclo_newton_general(Data);
    1813           7 :   else if (action & NEWTON_GENERAL_NEW)
    1814           7 :     return Flx_factcyclo_newton_general_new3(Data);
    1815             :   else
    1816           0 :     return Flx_factcyclo_fact(fn, p, m, action & ASCENT);
    1817             : }
    1818             : 
    1819             : static GEN
    1820      156721 : Flx_factcyclo_i(ulong n, ulong p, ulong fl)
    1821             : {
    1822      156721 :   GEN fn = factoru(n), z;
    1823      156721 :   ulong phin = eulerphiu_fact(fn), pmodn = p%n;
    1824      156721 :   ulong d = Fl_order(pmodn, phin, n), f = phin/d, fK;
    1825             : 
    1826      156721 :   if (DEBUGLEVEL >= 1) header(fn, n, d, f, utoi(p));
    1827      156721 :   if (f == 1) { z = Flx_polcyclo(n, p); return fl? z: mkvec(z); }
    1828      123093 :   if (d == 1) /* p=1 (mod n), zeta_n in Z_p */
    1829        9488 :   { z = Flx_split(n, p, fl? 1: f); return fl? gel(z,1): z; }
    1830      113605 :   fK = znstar_conductor(znstar_generate(n, mkvecsmall(pmodn)));
    1831      113605 :   if (fK != n && p % fK == 1)
    1832       24698 :     z = Flx_split(fK, p, fl? 1: f);
    1833             :   else
    1834       88907 :     z = Flx_factcyclo_just_conductor(fK, p, fl? 1: f);
    1835      113605 :   if (n > fK)
    1836             :   {
    1837       58055 :     GEN vP = const_vec(n, NULL);
    1838       58055 :     long i, l = fl? 2: lg(z);
    1839      199020 :     for (i = 1; i < l; i++)
    1840      140965 :       gel(z, i) = Flx_conductor_lift(gel(z, i), p, fn, fK, vP);
    1841             :   }
    1842      113605 :   return fl? gel(z,1): gen_sort(z,(void*)cmpGuGu, &gen_cmp_RgX);
    1843             : }
    1844             : 
    1845             : GEN
    1846         308 : Flx_factcyclo(ulong n, ulong p, ulong m)
    1847         308 : { pari_sp av = avma; return gerepilecopy(av, Flx_factcyclo_i(n, p, m)); }
    1848             : 
    1849             : GEN
    1850      167027 : factormodcyclo(long n, GEN p, long fl, long v)
    1851             : {
    1852      167027 :   const char *fun = "factormodcyclo";
    1853      167027 :   pari_sp av = avma;
    1854             :   long i, l;
    1855             :   GEN z;
    1856      167027 :   if (v < 0) v = 0;
    1857      167027 :   if (fl < 0 || fl > 1) pari_err_FLAG(fun);
    1858      167027 :   if (n <= 0) pari_err_DOMAIN(fun, "n", "<=", gen_0, stoi(n));
    1859      167027 :   if (typ(p) != t_INT) pari_err_TYPE(fun, p);
    1860      167027 :   if (dvdui(n, p)) pari_err_COPRIME(fun, stoi(n), p);
    1861      167027 :   if (fl)
    1862             :   {
    1863       83503 :     if (lgefint(p) == 3)
    1864       78203 :       z = Flx_to_ZX(Flx_factcyclo_i(n, p[2], 1));
    1865             :     else
    1866        5300 :       z = FpX_factcyclo_i(n, p, 1);
    1867       83503 :     setvarn(z, v);
    1868       83503 :     return gerepileupto(av, FpX_to_mod(z, p));
    1869             :   }
    1870             :   else
    1871             :   {
    1872       83524 :     if (lgefint(p) == 3)
    1873       78210 :       z = FlxC_to_ZXC(Flx_factcyclo_i(n, p[2], 0));
    1874             :     else
    1875        5314 :       z = FpX_factcyclo_i(n, p, 0);
    1876      465409 :     l = lg(z); for (i = 1; i < l; i++) setvarn(gel(z, i), v);
    1877       83524 :     return gerepileupto(av, FpXC_to_mod(z, p));
    1878             :   }
    1879             : }

Generated by: LCOV version 1.16