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 - FpXQX_factor.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.18.0 lcov report (development 29818-b3e15d99d2) Lines: 1614 1957 82.5 %
Date: 2024-12-27 09:09:37 Functions: 127 154 82.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 2016  The PARI group.
       2             : 
       3             : This file is part of the PARI/GP package.
       4             : 
       5             : PARI/GP is free software; you can redistribute it and/or modify it under the
       6             : terms of the GNU General Public License as published by the Free Software
       7             : Foundation; either version 2 of the License, or (at your option) any later
       8             : version. It is distributed in the hope that it will be useful, but WITHOUT
       9             : ANY WARRANTY WHATSOEVER.
      10             : 
      11             : Check the License for details. You should have received a copy of it, along
      12             : with the package; see the file 'COPYING'. If not, write to the Free Software
      13             : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      14             : 
      15             : #include "pari.h"
      16             : #include "paripriv.h"
      17             : 
      18             : #define DEBUGLEVEL DEBUGLEVEL_factorff
      19             : 
      20             : /*******************************************************************/
      21             : /**                                                               **/
      22             : /**           Isomorphisms between finite fields                  **/
      23             : /**                                                               **/
      24             : /*******************************************************************/
      25             : static void
      26          14 : err_Flxq(const char *s, GEN P, ulong l)
      27             : {
      28          14 :   if (!uisprime(l)) pari_err_PRIME(s, utoi(l));
      29          14 :   pari_err_IRREDPOL(s, Flx_to_ZX(get_Flx_mod(P)));
      30           0 : }
      31             : static void
      32           0 : err_FpXQ(const char *s, GEN P, GEN l)
      33             : {
      34           0 :   if (!BPSW_psp(l)) pari_err_PRIME(s, l);
      35           0 :   pari_err_IRREDPOL(s, get_FpX_mod(P));
      36           0 : }
      37             : 
      38             : /* compute the reciprocical isomorphism of S mod T,p, i.e. V such that
      39             :  * V(S)=X  mod T,p*/
      40             : static GEN
      41        2828 : Flxq_ffisom_inv_pre(GEN S, GEN T, ulong p, ulong pi)
      42             : {
      43        2828 :   pari_sp ltop = avma;
      44        2828 :   long n = get_Flx_degree(T);
      45        2828 :   GEN M = Flxq_matrix_pow_pre(S,n,n,T,p,pi);
      46        2828 :   GEN V = Flm_Flc_invimage(M, vecsmall_ei(n, 2), p);
      47        2828 :   if (!V) err_Flxq("Flxq_ffisom_inv", T, p);
      48        2828 :   return gerepileupto(ltop, Flv_to_Flx(V, get_Flx_var(T)));
      49             : }
      50             : GEN
      51           0 : Flxq_ffisom_inv(GEN S, GEN T, ulong p)
      52           0 : { return Flxq_ffisom_inv_pre(S, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
      53             : 
      54             : GEN
      55         588 : FpXQ_ffisom_inv(GEN S,GEN T, GEN p)
      56             : {
      57         588 :   pari_sp ltop = avma;
      58         588 :   long n = get_FpX_degree(T);
      59         588 :   GEN M = FpXQ_matrix_pow(S,n,n,T,p);
      60         588 :   GEN V = FpM_FpC_invimage(M, col_ei(n, 2), p);
      61         588 :   if (!V) err_FpXQ("Flxq_ffisom_inv", T, p);
      62         588 :   return gerepilecopy(ltop, RgV_to_RgX(V, get_FpX_var(T)));
      63             : }
      64             : 
      65             : /* Let M the matrix of the Frobenius automorphism of Fp[X]/(T). Compute M^d
      66             :  * TODO: use left-right binary (tricky!) */
      67             : GEN
      68         399 : Flm_Frobenius_pow(GEN M, long d, GEN T, ulong p)
      69             : {
      70         399 :   pari_sp ltop=avma;
      71         399 :   long i,l = get_Flx_degree(T);
      72         399 :   GEN R, W = gel(M,2);
      73        1337 :   for (i = 2; i <= d; ++i) W = Flm_Flc_mul(M,W,p);
      74         399 :   R=Flxq_matrix_pow(Flv_to_Flx(W,get_Flx_var(T)),l,l,T,p);
      75         399 :   return gerepileupto(ltop,R);
      76             : }
      77             : 
      78             : GEN
      79          35 : FpM_Frobenius_pow(GEN M, long d, GEN T, GEN p)
      80             : {
      81          35 :   pari_sp ltop=avma;
      82          35 :   long i,l = get_FpX_degree(T);
      83          35 :   GEN R, W = gel(M,2);
      84         147 :   for (i = 2; i <= d; ++i) W = FpM_FpC_mul(M,W,p);
      85          35 :   R=FpXQ_matrix_pow(RgV_to_RgX(W, get_FpX_var(T)),l,l,T,p);
      86          35 :   return gerepilecopy(ltop,R);
      87             : }
      88             : 
      89             : /* Essentially we want to compute FqM_ker(MA-pol_x(v),U,l)
      90             :  * To avoid use of matrix in Fq we compute FpM_ker(U(MA),l) then recover the
      91             :  * eigenvalue by Galois action */
      92             : static GEN
      93       40319 : Flx_Flm_Flc_eval(GEN U, GEN MA, GEN a, ulong p)
      94             : {
      95       40319 :   long i, l = lg(U);
      96       40319 :   GEN b = Flv_Fl_mul(a, uel(U, l-1), p);
      97      163995 :   for (i=l-2; i>=2; i--)
      98      123676 :     b = Flv_add(Flm_Flc_mul(MA, b, p), Flv_Fl_mul(a, uel(U, i), p), p);
      99       40319 :   return b;
     100             : }
     101             : 
     102             : static GEN
     103       39208 : Flx_intersect_ker(GEN P, GEN MA, GEN U, ulong p)
     104             : {
     105       39208 :   pari_sp ltop = avma;
     106       39208 :   long i, vp = get_Flx_var(P), vu = get_Flx_var(U), r = get_Flx_degree(U);
     107             :   GEN V, A, R;
     108             :   ulong ib0;
     109             :   pari_timer T;
     110       39208 :   if (DEBUGLEVEL>=4) timer_start(&T);
     111       39208 :   V = Flx_div(Flx_Fl_add(monomial_Flx(1, get_Flx_degree(P), vu), p-1, p), U, p);
     112             :   do
     113             :   {
     114       40319 :     A = Flx_Flm_Flc_eval(V, MA, random_Flv(lg(MA)-1, p), p);
     115       40319 :   } while (zv_equal0(A));
     116       39208 :   if (DEBUGLEVEL>=4) timer_printf(&T,"matrix polcyclo");
     117             :   /*The formula is
     118             :    * a_{r-1} = -\phi(a_0)/b_0
     119             :    * a_{i-1} = \phi(a_i)+b_ia_{r-1}  i=r-1 to 1
     120             :    * Where a_0=A[1] and b_i=U[i+2] */
     121       39208 :   ib0 = Fl_inv(Fl_neg(U[2], p), p);
     122       39208 :   R = cgetg(r+1,t_MAT);
     123       39208 :   gel(R,1) = A;
     124       39208 :   gel(R,r) = Flm_Flc_mul(MA, Flv_Fl_mul(A,ib0, p), p);
     125       45060 :   for(i=r-1; i>1; i--)
     126             :   {
     127        5852 :     gel(R,i) = Flm_Flc_mul(MA,gel(R,i+1),p);
     128        5852 :     Flv_add_inplace(gel(R,i), Flv_Fl_mul(gel(R,r), U[i+2], p), p);
     129             :   }
     130       39208 :   return gerepileupto(ltop, Flm_to_FlxX(Flm_transpose(R),vp,vu));
     131             : }
     132             : 
     133             : static GEN
     134         182 : FpX_FpM_FpC_eval(GEN U, GEN MA, GEN a, GEN p)
     135             : {
     136         182 :   long i, l = lg(U);
     137         182 :   GEN b = FpC_Fp_mul(a, gel(U, l-1), p);
     138         966 :   for (i=l-2; i>=2; i--)
     139         784 :     b = FpC_add(FpM_FpC_mul(MA, b, p), FpC_Fp_mul(a, gel(U, i), p), p);
     140         182 :   return b;
     141             : }
     142             : 
     143             : static GEN
     144         182 : FpX_intersect_ker(GEN P, GEN MA, GEN U, GEN l)
     145             : {
     146         182 :   pari_sp ltop = avma;
     147         182 :   long i, vp = get_FpX_var(P), vu = get_FpX_var(U), r = get_FpX_degree(U);
     148             :   GEN V, A, R, ib0;
     149             :   pari_timer T;
     150         182 :   if (DEBUGLEVEL>=4) timer_start(&T);
     151         182 :   V = FpX_div(FpX_Fp_sub(pol_xn(get_FpX_degree(P), vu), gen_1, l), U, l);
     152             :   do
     153             :   {
     154         182 :     A = FpX_FpM_FpC_eval(V, MA, random_FpC(lg(MA)-1, l), l);
     155         182 :   } while (ZV_equal0(A));
     156         182 :   if (DEBUGLEVEL>=4) timer_printf(&T,"matrix polcyclo");
     157             :   /*The formula is
     158             :    * a_{r-1} = -\phi(a_0)/b_0
     159             :    * a_{i-1} = \phi(a_i)+b_ia_{r-1}  i=r-1 to 1
     160             :    * Where a_0=A[1] and b_i=U[i+2] */
     161         182 :   ib0 = Fp_inv(negi(gel(U,2)),l);
     162         182 :   R = cgetg(r+1,t_MAT);
     163         182 :   gel(R,1) = A;
     164         182 :   gel(R,r) = FpM_FpC_mul(MA, FpC_Fp_mul(A,ib0,l), l);
     165         518 :   for(i=r-1;i>1;i--)
     166         336 :     gel(R,i) = FpC_add(FpM_FpC_mul(MA,gel(R,i+1),l),
     167         336 :         FpC_Fp_mul(gel(R,r), gel(U,i+2), l),l);
     168         182 :   return gerepilecopy(ltop,RgM_to_RgXX(shallowtrans(R),vp,vu));
     169             : }
     170             : 
     171             : /* n must divide both the degree of P and Q.  Compute SP and SQ such
     172             :  * that the subfield of FF_l[X]/(P) generated by SP and the subfield of
     173             :  * FF_l[X]/(Q) generated by SQ are isomorphic of degree n.  P and Q do
     174             :  * not need to be of the same variable; if MA, resp. MB, is not NULL, must be
     175             :  * the matrix of the Frobenius map in FF_l[X]/(P), resp. FF_l[X]/(Q).
     176             :  * Implementation choice:  we assume the prime p is large so we handle
     177             :  * Frobenius as matrices. */
     178             : static void
     179       43264 : Flx_ffintersect_pre(GEN P, GEN Q, long n, ulong l, ulong li, GEN *SP, GEN *SQ, GEN MA, GEN MB)
     180             : {
     181       43264 :   pari_sp ltop = avma;
     182       43264 :   long vp = get_Flx_var(P), vq =  get_Flx_var(Q);
     183       43264 :   long np = get_Flx_degree(P), nq = get_Flx_degree(Q), e;
     184             :   ulong pg;
     185             :   GEN A, B, Ap, Bp;
     186       43264 :   if (np<=0) pari_err_IRREDPOL("FpX_ffintersect", P);
     187       43264 :   if (nq<=0) pari_err_IRREDPOL("FpX_ffintersect", Q);
     188       43264 :   if (n<=0 || np%n || nq%n)
     189           0 :     pari_err_TYPE("FpX_ffintersect [bad degrees]",stoi(n));
     190       43264 :   li = SMALL_ULONG(l)? 0: get_Fl_red(l);
     191       43264 :   e = u_lvalrem(n, l, &pg);
     192       43265 :   if(!MA) MA = Flx_matFrobenius_pre(P,l,li);
     193       43265 :   if(!MB) MB = Flx_matFrobenius_pre(Q,l,li);
     194       43265 :   A = Ap = pol0_Flx(vp);
     195       43264 :   B = Bp = pol0_Flx(vq);
     196       43264 :   if (pg > 1)
     197             :   {
     198             :     pari_timer T;
     199       40174 :     GEN ipg = utoipos(pg);
     200       40174 :     if (l%pg == 1)
     201             :     { /* more efficient special case */
     202             :       ulong L, z, An, Bn;
     203       20571 :       z = Fl_neg(rootsof1_Fl(pg, l), l);
     204       20571 :       if (DEBUGLEVEL>=4) timer_start(&T);
     205       20571 :       A = Flm_ker(Flm_Fl_add(MA, z, l),l);
     206       20571 :       if (lg(A)!=2) err_Flxq("FpX_ffintersect",P,l);
     207       20571 :       A = Flv_to_Flx(gel(A,1),vp);
     208             : 
     209       20571 :       B = Flm_ker(Flm_Fl_add(MB, z, l),l);
     210       20571 :       if (lg(B)!=2) err_Flxq("FpX_ffintersect",Q,l);
     211       20564 :       B = Flv_to_Flx(gel(B,1),vq);
     212             : 
     213       20564 :       if (DEBUGLEVEL>=4) timer_printf(&T, "FpM_ker");
     214       20564 :       An = Flxq_powu_pre(A,pg,P,l,li)[2];
     215       20564 :       Bn = Flxq_powu_pre(B,pg,Q,l,li)[2];
     216       20564 :       if (!Bn) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q));
     217       20564 :       z = Fl_div(An,Bn,l);
     218       20564 :       L = Fl_sqrtn(z, pg, l, NULL);
     219       20564 :       if (L==ULONG_MAX) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q));
     220       20564 :       if (DEBUGLEVEL>=4) timer_printf(&T, "Fp_sqrtn");
     221       20564 :       B = Flx_Fl_mul(B,L,l);
     222             :     }
     223             :     else
     224             :     {
     225             :       GEN L, An, Bn, z, U;
     226       19603 :       U = gmael(Flx_factor(ZX_to_Flx(polcyclo(pg, fetch_var()),l),l),1,1);
     227       19604 :       A = Flx_intersect_ker(P, MA, U, l);
     228       19604 :       B = Flx_intersect_ker(Q, MB, U, l);
     229       19604 :       if (DEBUGLEVEL>=4) timer_start(&T);
     230       19604 :       An = gel(FlxYqq_pow(A,ipg,P,U,l),2);
     231       19604 :       Bn = gel(FlxYqq_pow(B,ipg,Q,U,l),2);
     232       19604 :       if (DEBUGLEVEL>=4) timer_printf(&T,"pows [P,Q]");
     233       19604 :       z = Flxq_div_pre(An,Bn,U,l,li);
     234       19603 :       L = Flxq_sqrtn(z,ipg,U,l,NULL);
     235       19604 :       if (!L) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q));
     236       19604 :       if (DEBUGLEVEL>=4) timer_printf(&T,"FpXQ_sqrtn");
     237       19604 :       B = FlxqX_Flxq_mul_pre(B,L,U,l,li);
     238       19604 :       A = FlxY_evalx_pre(A,0,l,li);
     239       19604 :       B = FlxY_evalx_pre(B,0,l,li);
     240       19604 :       (void)delete_var();
     241             :     }
     242             :   }
     243       43258 :   if (e)
     244             :   {
     245             :     GEN VP, VQ, Ay, By;
     246        3153 :     ulong lmun = l-1;
     247             :     long j;
     248        3153 :     MA = Flm_Fl_add(MA,lmun,l);
     249        3153 :     MB = Flm_Fl_add(MB,lmun,l);
     250        3153 :     Ay = pol1_Flx(vp);
     251        3153 :     By = pol1_Flx(vq);
     252        3153 :     VP = vecsmall_ei(np, 1);
     253        3153 :     VQ = np == nq? VP: vecsmall_ei(nq, 1); /* save memory */
     254        6715 :     for(j=0;j<e;j++)
     255             :     {
     256        3569 :       if (j)
     257             :       {
     258         416 :         Ay = Flxq_mul_pre(Ay,Flxq_powu_pre(Ap,lmun,P,l,li),P,l,li);
     259         416 :         VP = Flx_to_Flv(Ay,np);
     260             :       }
     261        3569 :       Ap = Flm_Flc_invimage(MA,VP,l);
     262        3569 :       if (!Ap) err_Flxq("FpX_ffintersect",P,l);
     263        3569 :       Ap = Flv_to_Flx(Ap,vp);
     264             : 
     265        3569 :       if (j)
     266             :       {
     267         416 :         By = Flxq_mul_pre(By,Flxq_powu_pre(Bp,lmun,Q,l,li),Q,l,li);
     268         416 :         VQ = Flx_to_Flv(By,nq);
     269             :       }
     270        3569 :       Bp = Flm_Flc_invimage(MB,VQ,l);
     271        3569 :       if (!Bp) err_Flxq("FpX_ffintersect",Q,l);
     272        3562 :       Bp = Flv_to_Flx(Bp,vq);
     273             :     }
     274             :   }
     275       43251 :   *SP = Flx_add(A,Ap,l);
     276       43251 :   *SQ = Flx_add(B,Bp,l);
     277       43251 :   gerepileall(ltop,2,SP,SQ);
     278       43251 : }
     279             : void
     280           0 : Flx_ffintersect(GEN P, GEN Q, long n, ulong p, GEN *SP, GEN *SQ, GEN MA, GEN MB)
     281             : {
     282           0 :   ulong pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
     283           0 :   Flx_ffintersect_pre(P, Q, n, p, pi, SP, SQ, MA, MB);
     284           0 : }
     285             : 
     286             : /* Let l be a prime number, P, Q in Z[X]; both are irreducible modulo l and
     287             :  * degree(P) divides degree(Q).  Output a monomorphism between F_l[X]/(P) and
     288             :  * F_l[X]/(Q) as a polynomial R such that Q | P(R) mod l.  If P and Q have the
     289             :  * same degree, it is of course an isomorphism.  */
     290             : GEN
     291        2828 : Flx_ffisom(GEN P,GEN Q,ulong l)
     292             : {
     293        2828 :   pari_sp av = avma;
     294             :   GEN SP, SQ, R;
     295        2828 :   ulong li = SMALL_ULONG(l)? 0: get_Fl_red(l);
     296        2828 :   Flx_ffintersect_pre(P,Q,get_Flx_degree(P),l,li,&SP,&SQ,NULL,NULL);
     297        2828 :   R = Flxq_ffisom_inv_pre(SP,P,l,li);
     298        2828 :   return gerepileupto(av, Flx_Flxq_eval_pre(R,SQ,Q,l,li));
     299             : }
     300             : 
     301             : void
     302         322 : FpX_ffintersect(GEN P, GEN Q, long n, GEN l, GEN *SP, GEN *SQ, GEN MA, GEN MB)
     303             : {
     304         322 :   pari_sp ltop = avma;
     305             :   long vp, vq, np, nq, e;
     306             :   ulong pg;
     307             :   GEN A, B, Ap, Bp;
     308         322 :   if (lgefint(l)==3)
     309             :   {
     310           0 :     ulong pp = l[2];
     311           0 :     GEN Pp = ZX_to_Flx(P,pp), Qp = ZX_to_Flx(Q,pp);
     312           0 :     GEN MAp = MA ? ZM_to_Flm(MA, pp): NULL;
     313           0 :     GEN MBp = MB ? ZM_to_Flm(MB, pp): NULL;
     314           0 :     Flx_ffintersect(Pp, Qp, n, pp, SP, SQ, MAp, MBp);
     315           0 :     *SP = Flx_to_ZX(*SP); *SQ = Flx_to_ZX(*SQ);
     316           0 :     gerepileall(ltop,2,SP,SQ);
     317           0 :     return;
     318             :   }
     319         322 :   vp = get_FpX_var(P); np = get_FpX_degree(P);
     320         322 :   vq = get_FpX_var(Q); nq = get_FpX_degree(Q);
     321         322 :   if (np<=0) pari_err_IRREDPOL("FpX_ffintersect", P);
     322         322 :   if (nq<=0) pari_err_IRREDPOL("FpX_ffintersect", Q);
     323         322 :   if (n<=0 || np%n || nq%n)
     324           0 :     pari_err_TYPE("FpX_ffintersect [bad degrees]",stoi(n));
     325         322 :   e = u_pvalrem(n, l, &pg);
     326         322 :   if(!MA) MA = FpX_matFrobenius(P, l);
     327         322 :   if(!MB) MB = FpX_matFrobenius(Q, l);
     328         322 :   A = Ap = pol_0(vp);
     329         322 :   B = Bp = pol_0(vq);
     330         322 :   if (pg > 1)
     331             :   {
     332         322 :     GEN ipg = utoipos(pg);
     333             :     pari_timer T;
     334         322 :     if (umodiu(l,pg) == 1)
     335             :     /* No need to use relative extension, so don't. (Well, now we don't
     336             :      * in the other case either, but this special case is more efficient) */
     337             :     {
     338             :       GEN L, An, Bn, z;
     339         231 :       z = negi( rootsof1u_Fp(pg, l) );
     340         231 :       if (DEBUGLEVEL>=4) timer_start(&T);
     341         231 :       A = FpM_ker(RgM_Rg_add_shallow(MA, z),l);
     342         231 :       if (lg(A)!=2) err_FpXQ("FpX_ffintersect",P,l);
     343         231 :       A = RgV_to_RgX(gel(A,1),vp);
     344             : 
     345         231 :       B = FpM_ker(RgM_Rg_add_shallow(MB, z),l);
     346         231 :       if (lg(B)!=2) err_FpXQ("FpX_ffintersect",Q,l);
     347         231 :       B = RgV_to_RgX(gel(B,1),vq);
     348             : 
     349         231 :       if (DEBUGLEVEL>=4) timer_printf(&T, "FpM_ker");
     350         231 :       An = gel(FpXQ_pow(A,ipg,P,l),2);
     351         231 :       Bn = gel(FpXQ_pow(B,ipg,Q,l),2);
     352         231 :       if (!signe(Bn)) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q));
     353         231 :       z = Fp_div(An,Bn,l);
     354         231 :       L = Fp_sqrtn(z,ipg,l,NULL);
     355         231 :       if (!L) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q));
     356         231 :       if (DEBUGLEVEL>=4) timer_printf(&T, "Fp_sqrtn");
     357         231 :       B = FpX_Fp_mul(B,L,l);
     358             :     }
     359             :     else
     360             :     {
     361             :       GEN L, An, Bn, z, U;
     362          91 :       U = gmael(FpX_factor(polcyclo(pg,fetch_var()),l),1,1);
     363          91 :       A = FpX_intersect_ker(P, MA, U, l);
     364          91 :       B = FpX_intersect_ker(Q, MB, U, l);
     365          91 :       if (DEBUGLEVEL>=4) timer_start(&T);
     366          91 :       An = gel(FpXYQQ_pow(A,ipg,P,U,l),2);
     367          91 :       Bn = gel(FpXYQQ_pow(B,ipg,Q,U,l),2);
     368          91 :       if (DEBUGLEVEL>=4) timer_printf(&T,"pows [P,Q]");
     369          91 :       if (!signe(Bn)) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q));
     370          91 :       z = Fq_div(An,Bn,U,l);
     371          91 :       L = Fq_sqrtn(z,ipg,U,l,NULL);
     372          91 :       if (!L) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q));
     373          91 :       if (DEBUGLEVEL>=4) timer_printf(&T,"FpXQ_sqrtn");
     374          91 :       B = FqX_Fq_mul(B,L,U,l);
     375          91 :       A = FpXY_evalx(A,gen_0,l);
     376          91 :       B = FpXY_evalx(B,gen_0,l);
     377          91 :       (void)delete_var();
     378             :     }
     379             :   }
     380         322 :   if (e)
     381             :   {
     382           0 :     GEN VP, VQ, Ay, By, lmun = subiu(l,1);
     383             :     long j;
     384           0 :     MA = RgM_Rg_add_shallow(MA,gen_m1);
     385           0 :     MB = RgM_Rg_add_shallow(MB,gen_m1);
     386           0 :     Ay = pol_1(vp);
     387           0 :     By = pol_1(vq);
     388           0 :     VP = col_ei(np, 1);
     389           0 :     VQ = np == nq? VP: col_ei(nq, 1); /* save memory */
     390           0 :     for(j=0;j<e;j++)
     391             :     {
     392           0 :       if (j)
     393             :       {
     394           0 :         Ay = FpXQ_mul(Ay,FpXQ_pow(Ap,lmun,P,l),P,l);
     395           0 :         VP = RgX_to_RgC(Ay,np);
     396             :       }
     397           0 :       Ap = FpM_FpC_invimage(MA,VP,l);
     398           0 :       if (!Ap) err_FpXQ("FpX_ffintersect",P,l);
     399           0 :       Ap = RgV_to_RgX(Ap,vp);
     400             : 
     401           0 :       if (j)
     402             :       {
     403           0 :         By = FpXQ_mul(By,FpXQ_pow(Bp,lmun,Q,l),Q,l);
     404           0 :         VQ = RgX_to_RgC(By,nq);
     405             :       }
     406           0 :       Bp = FpM_FpC_invimage(MB,VQ,l);
     407           0 :       if (!Bp) err_FpXQ("FpX_ffintersect",Q,l);
     408           0 :       Bp = RgV_to_RgX(Bp,vq);
     409             :     }
     410             :   }
     411         322 :   *SP = FpX_add(A,Ap,l);
     412         322 :   *SQ = FpX_add(B,Bp,l);
     413         322 :   gerepileall(ltop,2,SP,SQ);
     414             : }
     415             : /* Let l be a prime number, P, Q in Z[X]; both are irreducible modulo l and
     416             :  * degree(P) divides degree(Q).  Output a monomorphism between F_l[X]/(P) and
     417             :  * F_l[X]/(Q) as a polynomial R such that Q | P(R) mod l.  If P and Q have the
     418             :  * same degree, it is of course an isomorphism.  */
     419             : GEN
     420        2786 : FpX_ffisom(GEN P, GEN Q, GEN p)
     421             : {
     422        2786 :   pari_sp av = avma;
     423             :   GEN SP, SQ, R;
     424        2786 :   if (lgefint(p)==3)
     425             :   {
     426        2786 :     ulong pp = p[2];
     427        2786 :     GEN R = Flx_ffisom(ZX_to_Flx(P,pp), ZX_to_Flx(Q,pp), pp);
     428        2786 :     return gerepileupto(av, Flx_to_ZX(R));
     429             :   }
     430           0 :   FpX_ffintersect(P,Q,get_FpX_degree(P),p,&SP,&SQ,NULL,NULL);
     431           0 :   R = FpXQ_ffisom_inv(SP,P,p);
     432           0 :   return gerepileupto(av, FpX_FpXQ_eval(R,SQ,Q,p));
     433             : }
     434             : 
     435             : /* Let l be a prime number, P a ZX irreducible modulo l, MP the matrix of the
     436             :  * Frobenius automorphism of F_l[X]/(P).
     437             :  * Factor P over the subfield of F_l[X]/(P) of index d. */
     438             : static GEN
     439         322 : FpX_factorgalois(GEN P, GEN l, long d, long w, GEN MP)
     440             : {
     441         322 :   pari_sp ltop = avma;
     442             :   GEN R, V, Tl, z, M;
     443         322 :   long v = get_FpX_var(P), n = get_FpX_degree(P);
     444         322 :   long k, m = n/d;
     445             : 
     446             :   /* x - y */
     447         322 :   if (m == 1) return deg1pol_shallow(gen_1, deg1pol_shallow(subis(l,1), gen_0, w), v);
     448          35 :   M = FpM_Frobenius_pow(MP,d,P,l);
     449             : 
     450          35 :   Tl = leafcopy(P); setvarn(Tl,w);
     451          35 :   V = cgetg(m+1,t_VEC);
     452          35 :   gel(V,1) = pol_x(w);
     453          35 :   z = gel(M,2);
     454          35 :   gel(V,2) = RgV_to_RgX(z,w);
     455          77 :   for(k=3;k<=m;k++)
     456             :   {
     457          42 :     z = FpM_FpC_mul(M,z,l);
     458          42 :     gel(V,k) = RgV_to_RgX(z,w);
     459             :   }
     460          35 :   R = FqV_roots_to_pol(V,Tl,l,v);
     461          35 :   return gerepileupto(ltop,R);
     462             : }
     463             : /* same: P is an Flx, MP an Flm */
     464             : static GEN
     465       40423 : Flx_factorgalois(GEN P, ulong l, long d, long w, GEN MP)
     466             : {
     467       40423 :   pari_sp ltop = avma;
     468             :   GEN R, V, Tl, z, M;
     469       40423 :   long k, n = get_Flx_degree(P), m = n/d;
     470       40423 :   long v = get_Flx_var(P);
     471             : 
     472       40423 :   if (m == 1) {
     473       40024 :     R = polx_Flx(v);
     474       40024 :     gel(R,2) = z = polx_Flx(w); z[3] = l - 1; /* - y */
     475       40024 :     gel(R,3) = pol1_Flx(w);
     476       40024 :     return R; /* x - y */
     477             :   }
     478         399 :   M = Flm_Frobenius_pow(MP,d,P,l);
     479             : 
     480         399 :   Tl = leafcopy(P); Tl[1] = w;
     481         399 :   V = cgetg(m+1,t_VEC);
     482         399 :   gel(V,1) = polx_Flx(w);
     483         399 :   z = gel(M,2);
     484         399 :   gel(V,2) = Flv_to_Flx(z,w);
     485         700 :   for(k=3;k<=m;k++)
     486             :   {
     487         301 :     z = Flm_Flc_mul(M,z,l);
     488         301 :     gel(V,k) = Flv_to_Flx(z,w);
     489             :   }
     490         399 :   R = FlxqV_roots_to_pol(V,Tl,l,v);
     491         399 :   return gerepileupto(ltop,R);
     492             : }
     493             : 
     494             : GEN
     495      111566 : Flx_factorff_irred(GEN P, GEN Q, ulong p)
     496             : {
     497      111566 :   pari_sp ltop = avma, av;
     498             :   GEN SP, SQ, MP, MQ, M, FP, FQ, E, V, IR, res;
     499      111566 :   long np = get_Flx_degree(P), nq = get_Flx_degree(Q), d = ugcd(np,nq);
     500      111566 :   long i, vp = get_Flx_var(P), vq = get_Flx_var(Q);
     501             :   ulong pi, PI;
     502      111566 :   if (d==1) retmkcol(Flx_to_FlxX(P, vq));
     503       40437 :   PI = get_Fl_red(p);
     504       40437 :   pi = SMALL_ULONG(p)? 0: PI; /* PI for Fp, pi for Fp[x] */
     505       40437 :   FQ = Flx_matFrobenius_pre(Q,p,pi);
     506       40437 :   av = avma;
     507       40437 :   FP = Flx_matFrobenius_pre(P,p,pi);
     508       40436 :   Flx_ffintersect_pre(P,Q,d,p,pi,&SP,&SQ, FP, FQ);
     509       40423 :   E = Flx_factorgalois(P,p,d,vq, FP);
     510       40423 :   E = FlxX_to_Flm(E,np);
     511       40423 :   MP= Flxq_matrix_pow_pre(SP,np,d,P,p,pi);
     512       40423 :   IR= gel(Flm_indexrank(MP,p),1);
     513       40423 :   E = rowpermute(E, IR);
     514       40423 :   M = rowpermute(MP,IR);
     515       40423 :   M = Flm_inv(M,p);
     516       40423 :   MQ= Flxq_matrix_pow_pre(SQ,nq,d,Q,p,pi);
     517       40422 :   M = Flm_mul_pre(MQ,M,p,PI);
     518       40423 :   M = Flm_mul_pre(M,E,p,PI);
     519       40423 :   M = gerepileupto(av,M);
     520       40423 :   V = cgetg(d+1,t_VEC);
     521       40422 :   gel(V,1) = M;
     522      176113 :   for(i=2;i<=d;i++) gel(V,i) = Flm_mul_pre(FQ,gel(V,i-1),p,PI);
     523       40423 :   res = cgetg(d+1,t_COL);
     524      216534 :   for(i=1;i<=d;i++) gel(res,i) = Flm_to_FlxX(gel(V,i),vp,vq);
     525       40421 :   return gerepileupto(ltop,res);
     526             : }
     527             : 
     528             : /* P,Q irreducible over F_p. Factor P over FF_p[X] / Q  [factors are ordered as
     529             :  * a Frobenius cycle] */
     530             : GEN
     531       32879 : FpX_factorff_irred(GEN P, GEN Q, GEN p)
     532             : {
     533       32879 :   pari_sp ltop = avma, av;
     534             :   GEN res;
     535       32879 :   long np = get_FpX_degree(P), nq = get_FpX_degree(Q), d = ugcd(np,nq);
     536       32879 :   if (d==1) return mkcolcopy(P);
     537             : 
     538       32816 :   if (lgefint(p)==3)
     539             :   {
     540       32494 :     ulong pp = p[2];
     541       32494 :     GEN F = Flx_factorff_irred(ZX_to_Flx(P,pp), ZX_to_Flx(Q,pp), pp);
     542       32494 :     long i, lF = lg(F);
     543       32494 :     res = cgetg(lF, t_COL);
     544      182922 :     for(i=1; i<lF; i++)
     545      150429 :       gel(res,i) = FlxX_to_ZXX(gel(F,i));
     546             :   }
     547             :   else
     548             :   {
     549             :     GEN SP, SQ, MP, MQ, M, FP, FQ, E, V, IR;
     550         322 :     long i, vp = get_FpX_var(P), vq = get_FpX_var(Q);
     551         322 :     FQ = FpX_matFrobenius(Q,p);
     552         322 :     av = avma;
     553         322 :     FP = FpX_matFrobenius(P,p);
     554         322 :     FpX_ffintersect(P,Q,d,p,&SP,&SQ,FP,FQ);
     555             : 
     556         322 :     E = FpX_factorgalois(P,p,d,vq,FP);
     557         322 :     E = RgXX_to_RgM(E,np);
     558         322 :     MP= FpXQ_matrix_pow(SP,np,d,P,p);
     559         322 :     IR= gel(FpM_indexrank(MP,p),1);
     560         322 :     E = rowpermute(E, IR);
     561         322 :     M = rowpermute(MP,IR);
     562         322 :     M = FpM_inv(M,p);
     563         322 :     MQ= FpXQ_matrix_pow(SQ,nq,d,Q,p);
     564         322 :     M = FpM_mul(MQ,M,p);
     565         322 :     M = FpM_mul(M,E,p);
     566         322 :     M = gerepileupto(av,M);
     567         322 :     V = cgetg(d+1,t_VEC);
     568         322 :     gel(V,1) = M;
     569        1050 :     for(i=2;i<=d;i++)
     570         728 :       gel(V,i) = FpM_mul(FQ,gel(V,i-1),p);
     571         322 :     res = cgetg(d+1,t_COL);
     572        1372 :     for(i=1;i<=d;i++)
     573        1050 :       gel(res,i) = RgM_to_RgXX(gel(V,i),vp,vq);
     574             :   }
     575       32815 :   return gerepilecopy(ltop,res);
     576             : }
     577             : 
     578             : /* not memory-clean, as Flx_factorff_i, returning only linear factors */
     579             : static GEN
     580       29926 : Flx_rootsff_i(GEN P, GEN T, ulong p)
     581             : {
     582       29926 :   GEN V, F = gel(Flx_factor(P,p), 1);
     583       29926 :   long i, lfact = 1, nmax = lgpol(P), n = lg(F), dT = get_Flx_degree(T);
     584             : 
     585       29926 :   V = cgetg(nmax,t_COL);
     586       63701 :   for(i=1;i<n;i++)
     587             :   {
     588       33775 :     GEN R, Fi = gel(F,i);
     589       33775 :     long di = degpol(Fi), j, r;
     590       33775 :     if (dT % di) continue;
     591       32256 :     R = Flx_factorff_irred(gel(F,i),T,p);
     592       32256 :     r = lg(R);
     593       79497 :     for (j=1; j<r; j++,lfact++)
     594       47241 :       gel(V,lfact) = Flx_neg(gmael(R,j, 2), p);
     595             :   }
     596       29926 :   setlg(V,lfact);
     597       29926 :   gen_sort_inplace(V, (void*) &cmp_Flx, &cmp_nodata, NULL);
     598       29926 :   return V;
     599             : }
     600             : GEN
     601           0 : Flx_rootsff(GEN P, GEN T, ulong p)
     602             : {
     603           0 :   pari_sp av = avma;
     604           0 :   return gerepilecopy(av, Flx_rootsff_i(P, T, p));
     605             : }
     606             : 
     607             : /* dummy implementation */
     608             : static GEN
     609       16520 : F2x_rootsff_i(GEN P, GEN T)
     610             : {
     611       16520 :   return FlxC_to_F2xC(Flx_rootsff_i(F2x_to_Flx(P), F2x_to_Flx(T), 2UL));
     612             : }
     613             : 
     614             : /* not memory-clean, as FpX_factorff_i, returning only linear factors */
     615             : static GEN
     616         308 : FpX_rootsff_i(GEN P, GEN T, GEN p)
     617             : {
     618             :   GEN V, F;
     619             :   long i, lfact, nmax, n, dT;
     620         308 :   if (lgefint(p)==3)
     621             :   {
     622           0 :     ulong pp = p[2];
     623           0 :     GEN V = Flx_rootsff_i(ZX_to_Flx(P,pp), ZXT_to_FlxT(T,pp), pp);
     624           0 :     return FlxC_to_ZXC(V);
     625             :   }
     626         308 :   F = gel(FpX_factor(P,p), 1);
     627         308 :   lfact = 1; nmax = lgpol(P); n = lg(F); dT = get_FpX_degree(T);
     628             : 
     629         308 :   V = cgetg(nmax,t_COL);
     630         630 :   for(i=1;i<n;i++)
     631             :   {
     632         322 :     GEN R, Fi = gel(F,i);
     633         322 :     long di = degpol(Fi), j, r;
     634         322 :     if (dT % di) continue;
     635         322 :     R = FpX_factorff_irred(gel(F,i),T,p);
     636         322 :     r = lg(R);
     637        1260 :     for (j=1; j<r; j++,lfact++)
     638         938 :       gel(V,lfact) = Fq_to_FpXQ(Fq_neg(gmael(R,j, 2), T, p), T, p);
     639             :   }
     640         308 :   setlg(V,lfact);
     641         308 :   gen_sort_inplace(V, (void*) &cmp_RgX, &cmp_nodata, NULL);
     642         308 :   return V;
     643             : }
     644             : GEN
     645           0 : FpX_rootsff(GEN P, GEN T, GEN p)
     646             : {
     647           0 :   pari_sp av = avma;
     648           0 :   return gerepilecopy(av, FpX_rootsff_i(P, T, p));
     649             : }
     650             : 
     651             : static GEN
     652       12047 : Flx_factorff_i(GEN P, GEN T, ulong p)
     653             : {
     654       12047 :   GEN V, E, F = Flx_factor(P, p);
     655       12047 :   long i, lfact = 1, nmax = lgpol(P), n = lgcols(F);
     656             : 
     657       12047 :   V = cgetg(nmax,t_VEC);
     658       12047 :   E = cgetg(nmax,t_VECSMALL);
     659       58849 :   for(i=1;i<n;i++)
     660             :   {
     661       46816 :     GEN R = Flx_factorff_irred(gmael(F,1,i),T,p), e = gmael(F,2,i);
     662       46802 :     long j, r = lg(R);
     663       96376 :     for (j=1; j<r; j++,lfact++)
     664             :     {
     665       49574 :       gel(V,lfact) = gel(R,j);
     666       49574 :       gel(E,lfact) = e;
     667             :     }
     668             :   }
     669       12033 :   setlg(V,lfact);
     670       12033 :   setlg(E,lfact); return sort_factor_pol(mkvec2(V,E), cmp_Flx);
     671             : }
     672             : 
     673             : static long
     674        7084 : simpleff_to_nbfact(GEN F, long dT)
     675             : {
     676        7084 :   long i, l = lg(F), k = 0;
     677       90146 :   for (i = 1; i < l; i++) k += ugcd(uel(F,i), dT);
     678        7084 :   return k;
     679             : }
     680             : 
     681             : static long
     682        7084 : Flx_nbfactff(GEN P, GEN T, ulong p)
     683             : {
     684        7084 :   pari_sp av = avma;
     685        7084 :   GEN F = gel(Flx_degfact(P, p), 1);
     686        7084 :   long s = simpleff_to_nbfact(F, get_Flx_degree(T));
     687        7084 :   return gc_long(av,s);
     688             : }
     689             : 
     690             : /* dummy implementation */
     691             : static GEN
     692         504 : F2x_factorff_i(GEN P, GEN T)
     693             : {
     694         504 :   GEN M = Flx_factorff_i(F2x_to_Flx(P), F2x_to_Flx(T), 2);
     695         497 :   return mkvec2(FlxXC_to_F2xXC(gel(M,1)), gel(M,2));
     696             : }
     697             : 
     698             : /* not memory-clean */
     699             : static GEN
     700          63 : FpX_factorff_i(GEN P, GEN T, GEN p)
     701             : {
     702          63 :   GEN V, E, F = FpX_factor(P,p);
     703          63 :   long i, lfact = 1, nmax = lgpol(P), n = lgcols(F);
     704             : 
     705          63 :   V = cgetg(nmax,t_VEC);
     706          63 :   E = cgetg(nmax,t_VECSMALL);
     707         126 :   for(i=1;i<n;i++)
     708             :   {
     709          63 :     GEN R = FpX_factorff_irred(gmael(F,1,i),T,p), e = gmael(F,2,i);
     710          63 :     long j, r = lg(R);
     711         238 :     for (j=1; j<r; j++,lfact++)
     712             :     {
     713         175 :       gel(V,lfact) = gel(R,j);
     714         175 :       gel(E,lfact) = e;
     715             :     }
     716             :   }
     717          63 :   setlg(V,lfact);
     718          63 :   setlg(E,lfact); return sort_factor_pol(mkvec2(V,E), cmp_RgX);
     719             : }
     720             : 
     721             : static long
     722           0 : FpX_nbfactff(GEN P, GEN T, GEN p)
     723             : {
     724           0 :   pari_sp av = avma;
     725           0 :   GEN F = gel(FpX_degfact(P, p), 1);
     726           0 :   long s = simpleff_to_nbfact(F, get_FpX_degree(T));
     727           0 :   return gc_long(av,s);
     728             : }
     729             : 
     730             : GEN
     731           0 : FpX_factorff(GEN P, GEN T, GEN p)
     732             : {
     733           0 :   pari_sp av = avma;
     734           0 :   return gerepilecopy(av, FpX_factorff_i(P, T, p));
     735             : }
     736             : 
     737             : /***********************************************************************/
     738             : /**                                                                   **/
     739             : /**               Factorisation over finite fields                    **/
     740             : /**                                                                   **/
     741             : /***********************************************************************/
     742             : 
     743             : static GEN
     744       12178 : FlxqXQ_halfFrobenius_i(GEN a, GEN xp, GEN Xp, GEN S, GEN T, ulong p, ulong pi)
     745             : {
     746       12178 :   GEN ap2 = FlxqXQ_powu_pre(a, p>>1, S, T, p, pi);
     747       12178 :   GEN V = FlxqXQ_autsum_pre(mkvec3(xp, Xp, ap2), get_Flx_degree(T), S, T, p,pi);
     748       12178 :   return gel(V,3);
     749             : }
     750             : 
     751             : GEN
     752         470 : FlxqXQ_halfFrobenius(GEN a, GEN S, GEN T, ulong p)
     753             : {
     754         470 :   ulong pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
     755         470 :   long vT = get_Flx_var(T);
     756             :   GEN xp, Xp;
     757         470 :   T = Flx_get_red_pre(T, p, pi);
     758         470 :   S = FlxqX_get_red_pre(S, T, p, pi);
     759         470 :   xp = Flx_Frobenius_pre(T, p, pi);
     760         470 :   Xp = FlxqXQ_powu_pre(polx_FlxX(get_FlxqX_var(S), vT), p, S, T, p, pi);
     761         470 :   return FlxqXQ_halfFrobenius_i(a, xp, Xp, S, T, p, pi);
     762             : }
     763             : 
     764             : static GEN
     765        1208 : FpXQXQ_halfFrobenius_i(GEN a, GEN xp, GEN Xp, GEN S, GEN T, GEN p)
     766             : {
     767        1208 :   GEN ap2 = FpXQXQ_pow(a, shifti(p,-1), S, T, p);
     768        1208 :   GEN V = FpXQXQ_autsum(mkvec3(xp, Xp, ap2), get_FpX_degree(T), S, T, p);
     769        1208 :   return gel(V, 3);
     770             : }
     771             : 
     772             : GEN
     773         238 : FpXQXQ_halfFrobenius(GEN a, GEN S, GEN T, GEN p)
     774             : {
     775         238 :   pari_sp av = avma;
     776             :   GEN z;
     777         238 :   if (lgefint(p)==3)
     778             :   {
     779          99 :     ulong pp = p[2];
     780          99 :     long v = get_FpX_var(T);
     781          99 :     GEN Tp = ZXT_to_FlxT(T,pp), Sp = ZXXT_to_FlxXT(S, pp, v);
     782          99 :     z = FlxX_to_ZXX(FlxqXQ_halfFrobenius(ZXX_to_FlxX(a,pp,v),Sp,Tp,pp));
     783             :   }
     784             :   else
     785             :   {
     786             :     GEN xp, Xp;
     787         139 :     T = FpX_get_red(T, p);
     788         139 :     S = FpXQX_get_red(S, T, p);
     789         139 :     xp = FpX_Frobenius(T, p);
     790         139 :     Xp = FpXQXQ_pow(pol_x(get_FpXQX_var(S)), p, S, T, p);
     791         139 :     z = FpXQXQ_halfFrobenius_i(a, xp, Xp, S, T, p);
     792             :   }
     793         238 :   return gerepilecopy(av, z);
     794             : }
     795             : 
     796             : static GEN
     797       69345 : FlxqXQ_Frobenius(GEN xp, GEN Xp, GEN f, GEN T, ulong p, ulong pi)
     798             : {
     799       69345 :   ulong dT = get_Flx_degree(T), df = get_FlxqX_degree(f);
     800       69345 :   GEN q = powuu(p,dT);
     801       69345 :   if (expi(q) >= expu(dT)*(long)usqrt(df))
     802       69303 :     return gel(FlxqXQ_autpow_pre(mkvec2(xp, Xp), dT, f, T, p, pi), 2);
     803             :   else
     804          42 :     return FlxqXQ_pow_pre(pol_x(get_FlxqX_var(f)), q, f, T, p, pi);
     805             : }
     806             : 
     807             : GEN
     808        9871 : FlxqX_Frobenius_pre(GEN S, GEN T, ulong p, ulong pi)
     809             : {
     810        9871 :   pari_sp av = avma;
     811        9871 :   GEN X  = polx_FlxX(get_FlxqX_var(S), get_Flx_var(T));
     812        9871 :   GEN xp = Flx_Frobenius_pre(T, p, pi);
     813        9871 :   GEN Xp = FlxqXQ_powu_pre(X, p, S, T, p, pi);
     814        9871 :   GEN Xq = FlxqXQ_Frobenius(xp, Xp, S, T, p, pi);
     815        9871 :   return gerepilecopy(av, Xq);
     816             : }
     817             : GEN
     818         678 : FlxqX_Frobenius(GEN S, GEN T, ulong p)
     819         678 : { return FlxqX_Frobenius_pre(S, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
     820             : 
     821             : static GEN
     822         493 : FpXQXQ_Frobenius(GEN xp, GEN Xp, GEN f, GEN T, GEN p)
     823             : {
     824         493 :   ulong dT = get_FpX_degree(T), df = get_FpXQX_degree(f);
     825         493 :   GEN q = powiu(p, dT);
     826         493 :   if (expi(q) >= expu(dT)*(long)usqrt(df))
     827         493 :     return gel(FpXQXQ_autpow(mkvec2(xp, Xp), dT, f, T, p), 2);
     828             :   else
     829           0 :     return FpXQXQ_pow(pol_x(get_FpXQX_var(f)), q, f, T, p);
     830             : }
     831             : 
     832             : GEN
     833         388 : FpXQX_Frobenius(GEN S, GEN T, GEN p)
     834             : {
     835         388 :   pari_sp av = avma;
     836         388 :   GEN X  = pol_x(get_FpXQX_var(S));
     837         388 :   GEN xp = FpX_Frobenius(T, p);
     838         388 :   GEN Xp = FpXQXQ_pow(X, p, S, T, p);
     839         388 :   GEN Xq = FpXQXQ_Frobenius(xp, Xp, S, T, p);
     840         388 :   return gerepilecopy(av, Xq);
     841             : }
     842             : 
     843             : static GEN
     844       70497 : F2xqXQ_Frobenius(GEN xp, GEN Xp, GEN f, GEN T)
     845             : {
     846       70497 :   ulong dT = get_F2x_degree(T), df = get_F2xqX_degree(f);
     847       70497 :   if (dT >= expu(dT)*usqrt(df))
     848       70490 :     return gel(F2xqXQ_autpow(mkvec2(xp, Xp), dT, f, T), 2);
     849             :   else
     850             :   {
     851           7 :     long v = get_F2xqX_var(f), vT = get_F2x_var(T);
     852           7 :     return F2xqXQ_pow(polx_F2xX(v,vT), int2n(dT), f, T);
     853             :   }
     854             : }
     855             : 
     856             : static GEN
     857        9004 : FlxqX_split_part(GEN f, GEN T, ulong p)
     858             : {
     859        9004 :   long n = degpol(f);
     860             :   GEN z, Xq, X;
     861             :   ulong pi;
     862        9004 :   if (n <= 1) return f;
     863        9004 :   pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
     864        9004 :   X = polx_FlxX(varn(f),get_Flx_var(T));
     865        9004 :   f = FlxqX_red_pre(f, T, p, pi);
     866        9004 :   Xq = FlxqX_Frobenius_pre(f, T, p, pi);
     867        9004 :   z = FlxX_sub(Xq, X , p);
     868        9004 :   return FlxqX_gcd_pre(z, f, T, p, pi);
     869             : }
     870             : 
     871             : GEN
     872        1701 : FpXQX_split_part(GEN f, GEN T, GEN p)
     873             : {
     874        1701 :   if(lgefint(p)==3)
     875             :   {
     876        1685 :     ulong pp=p[2];
     877        1685 :     GEN Tp = ZXT_to_FlxT(T, pp);
     878        1685 :     GEN z = FlxqX_split_part(ZXX_to_FlxX(f, pp, get_FpX_var(T)), Tp, pp);
     879        1685 :     return FlxX_to_ZXX(z);
     880             :   } else
     881             :   {
     882          16 :     long n = degpol(f);
     883          16 :     GEN z, X = pol_x(varn(f));
     884          16 :     if (n <= 1) return f;
     885          16 :     f = FpXQX_red(f, T, p);
     886          16 :     z = FpXQX_Frobenius(f, T, p);
     887          16 :     z = FpXX_sub(z, X , p);
     888          16 :     return FpXQX_gcd(z, f, T, p);
     889             :   }
     890             : }
     891             : 
     892             : long
     893        1645 : FpXQX_nbroots(GEN f, GEN T, GEN p)
     894             : {
     895        1645 :   pari_sp av = avma;
     896        1645 :   GEN z = FpXQX_split_part(f, T, p);
     897        1645 :   return gc_long(av, degpol(z));
     898             : }
     899             : 
     900             : long
     901      122857 : FqX_nbroots(GEN f, GEN T, GEN p)
     902      122857 : { return T ? FpXQX_nbroots(f, T, p): FpX_nbroots(f, p); }
     903             : 
     904             : long
     905        7319 : FlxqX_nbroots(GEN f, GEN T, ulong p)
     906             : {
     907        7319 :   pari_sp av = avma;
     908        7319 :   GEN z = FlxqX_split_part(f, T, p);
     909        7319 :   return gc_long(av, degpol(z));
     910             : }
     911             : 
     912             : static GEN
     913           0 : FlxqX_Berlekamp_ker_i(GEN Xq, GEN S, GEN T, ulong p)
     914             : {
     915           0 :   long j, N = get_FlxqX_degree(S);
     916           0 :   GEN Q  = FlxqXQ_matrix_pow(Xq,N,N,S,T,p);
     917           0 :   for (j=1; j<=N; j++)
     918           0 :     gcoeff(Q,j,j) = Flx_Fl_add(gcoeff(Q,j,j), p-1, p);
     919           0 :   return FlxqM_ker(Q,T,p);
     920             : }
     921             : 
     922             : static GEN
     923           0 : FpXQX_Berlekamp_ker_i(GEN Xq, GEN S, GEN T, GEN p)
     924             : {
     925           0 :   long j,N = get_FpXQX_degree(S);
     926           0 :   GEN Q  = FpXQXQ_matrix_pow(Xq,N,N,S,T,p);
     927           0 :   for (j=1; j<=N; j++)
     928           0 :     gcoeff(Q,j,j) = Fq_sub(gcoeff(Q,j,j), gen_1, T, p);
     929           0 :   return FqM_ker(Q,T,p);
     930             : }
     931             : 
     932             : static long
     933        2661 : isabsolutepol(GEN f)
     934             : {
     935        2661 :   long i, l = lg(f);
     936        4524 :   for(i=2; i<l; i++)
     937             :   {
     938        4153 :     GEN c = gel(f,i);
     939        4153 :     if (typ(c) == t_POL && degpol(c) > 0) return 0;
     940             :   }
     941         371 :   return 1;
     942             : }
     943             : 
     944             : #define set_irred(i) { if ((i)>ir) swap(t[i],t[ir]); ir++;}
     945             : 
     946             : static long
     947           0 : FlxqX_split_Berlekamp(GEN *t, GEN xp, GEN T, ulong p, ulong pi)
     948             : {
     949           0 :   GEN u = *t, a,b,vker,pol;
     950           0 :   long vu = varn(u), vT = get_Flx_var(T), dT = get_Flx_degree(T);
     951             :   long d, i, ir, L, la, lb;
     952             :   GEN S, X, Xp, Xq;
     953           0 :   if (degpol(u)==1) return 1;
     954           0 :   T = Flx_get_red_pre(T, p, pi);
     955           0 :   S = FlxqX_get_red_pre(u, T, p, pi);
     956           0 :   X  = polx_FlxX(get_FlxqX_var(S),get_Flx_var(T));
     957           0 :   Xp = FlxqXQ_powu_pre(X, p, S, T, p, pi);
     958           0 :   Xq = FlxqXQ_Frobenius(xp, Xp, S, T, p, pi);
     959           0 :   vker = FlxqX_Berlekamp_ker_i(Xq, S, T, p);
     960           0 :   vker = Flm_to_FlxV(vker,u[1]);
     961           0 :   d = lg(vker)-1;
     962           0 :   ir = 0;
     963             :   /* t[i] irreducible for i < ir, still to be treated for i < L */
     964           0 :   for (L=1; L<d; )
     965             :   {
     966           0 :     pol= scalarpol(random_Flx(dT,vT,p),vu);
     967           0 :     for (i=2; i<=d; i++)
     968           0 :       pol = FlxX_add(pol, FlxqX_Flxq_mul_pre(gel(vker,i),
     969             :                                              random_Flx(dT,vT,p), T, p, pi), p);
     970           0 :     pol = FlxqX_red_pre(pol,T,p,pi);
     971           0 :     for (i=ir; i<L && L<d; i++)
     972             :     {
     973           0 :       a = t[i]; la = degpol(a);
     974           0 :       if (la == 1) { set_irred(i); }
     975             :       else
     976             :       {
     977           0 :         pari_sp av = avma;
     978           0 :         GEN S = FlxqX_get_red_pre(a, T, p, pi);
     979           0 :         b = FlxqX_rem_pre(pol, S, T,p,pi);
     980           0 :         if (degpol(b)<=0) { set_avma(av); continue; }
     981           0 :         b = FlxqXQ_halfFrobenius_i(b, xp, FlxqX_rem_pre(Xp,S,T,p,pi), S,T,p,pi);
     982           0 :         if (degpol(b)<=0) { set_avma(av); continue; }
     983           0 :         gel(b,2) = Flxq_sub(gel(b,2), gen_1,T,p);
     984           0 :         b = FlxqX_gcd_pre(a,b, T,p,pi); lb = degpol(b);
     985           0 :         if (lb && lb < la)
     986             :         {
     987           0 :           b = FlxqX_normalize_pre(b, T,p,pi);
     988           0 :           t[L] = FlxqX_div_pre(a,b,T,p,pi);
     989           0 :           t[i]= b; L++;
     990             :         }
     991           0 :         else set_avma(av);
     992             :       }
     993             :     }
     994             :   }
     995           0 :   return d;
     996             : }
     997             : 
     998             : static long
     999           0 : FpXQX_split_Berlekamp(GEN *t, GEN T, GEN p)
    1000             : {
    1001           0 :   GEN u = *t, a, b, vker, pol;
    1002             :   GEN X, xp, Xp, Xq, S;
    1003           0 :   long vu = varn(u), vT = get_FpX_var(T), dT = get_FpX_degree(T);
    1004             :   long d, i, ir, L, la, lb;
    1005           0 :   if (degpol(u)==1) return 1;
    1006           0 :   T = FpX_get_red(T, p);
    1007           0 :   xp = FpX_Frobenius(T, p);
    1008           0 :   S = FpXQX_get_red(u, T, p);
    1009           0 :   X  = pol_x(get_FpXQX_var(S));
    1010           0 :   Xp = FpXQXQ_pow(X, p, S, T, p);
    1011           0 :   Xq = FpXQXQ_Frobenius(xp, Xp, S, T, p);
    1012           0 :   vker = FpXQX_Berlekamp_ker_i(Xq, S, T, p);
    1013           0 :   vker = RgM_to_RgXV(vker,vu);
    1014           0 :   d = lg(vker)-1;
    1015           0 :   ir = 0;
    1016             :   /* t[i] irreducible for i < ir, still to be treated for i < L */
    1017           0 :   for (L=1; L<d; )
    1018             :   {
    1019           0 :     pol= scalarpol(random_FpX(dT,vT,p),vu);
    1020           0 :     for (i=2; i<=d; i++)
    1021           0 :       pol = FqX_add(pol, FqX_Fq_mul(gel(vker,i),
    1022             :                                     random_FpX(dT,vT,p), T, p), T, p);
    1023           0 :     pol = FpXQX_red(pol,T,p);
    1024           0 :     for (i=ir; i<L && L<d; i++)
    1025             :     {
    1026           0 :       a = t[i]; la = degpol(a);
    1027           0 :       if (la == 1) { set_irred(i); }
    1028             :       else
    1029             :       {
    1030           0 :         pari_sp av = avma;
    1031           0 :         GEN S = FpXQX_get_red(a, T, p);
    1032           0 :         b = FqX_rem(pol, S, T,p);
    1033           0 :         if (degpol(b)<=0) { set_avma(av); continue; }
    1034           0 :         b = FpXQXQ_halfFrobenius_i(b, xp, FpXQX_rem(Xp, S, T, p), S, T, p);
    1035           0 :         if (degpol(b)<=0) { set_avma(av); continue; }
    1036           0 :         gel(b,2) = Fq_sub(gel(b,2), gen_1,T,p);
    1037           0 :         b = FqX_gcd(a,b, T,p); lb = degpol(b);
    1038           0 :         if (lb && lb < la)
    1039             :         {
    1040           0 :           b = FpXQX_normalize(b, T,p);
    1041           0 :           t[L] = FqX_div(a,b,T,p);
    1042           0 :           t[i]= b; L++;
    1043             :         }
    1044           0 :         else set_avma(av);
    1045             :       }
    1046             :     }
    1047             :   }
    1048           0 :   return d;
    1049             : }
    1050             : 
    1051             : static GEN
    1052       11557 : F2xqX_quad_roots(GEN P, GEN T)
    1053             : {
    1054       11557 :   GEN b= gel(P,3), c = gel(P,2);
    1055       11557 :   if (lgpol(b))
    1056             :   {
    1057       10227 :     GEN z, d = F2xq_div(c, F2xq_sqr(b,T),T);
    1058       10227 :     if (F2xq_trace(d,T))
    1059        1001 :       return cgetg(1, t_COL);
    1060        9226 :     z = F2xq_mul(b, F2xq_Artin_Schreier(d, T), T);
    1061        9226 :     return mkcol2(z, F2x_add(b, z));
    1062             :   }
    1063             :   else
    1064        1330 :     return mkcol(F2xq_sqrt(c, T));
    1065             : }
    1066             : 
    1067             : /* Assume p>2 and x monic */
    1068             : static GEN
    1069       14691 : FlxqX_quad_roots(GEN x, GEN T, ulong p, ulong pi)
    1070             : {
    1071       14691 :   GEN s, D, nb, b = gel(x,3), c = gel(x,2);
    1072       14691 :   D = Flx_sub(Flxq_sqr_pre(b,T,p,pi), Flx_mulu(c,4,p), p);
    1073       14691 :   nb = Flx_neg(b,p);
    1074       14691 :   if (lgpol(D)==0) return mkcol(Flx_halve(nb, p));
    1075       14649 :   s = Flxq_sqrt(D,T,p);
    1076       14649 :   if (!s) return cgetg(1, t_COL);
    1077       14187 :   s = Flx_halve(Flx_add(s,nb,p),p);
    1078       14187 :   return mkcol2(s, Flx_sub(nb,s,p));
    1079             : }
    1080             : 
    1081             : static GEN
    1082         839 : FpXQX_quad_roots(GEN x, GEN T, GEN p)
    1083             : {
    1084         839 :   GEN s, D, nb, b = gel(x,3), c = gel(x,2);
    1085         839 :   if (absequaliu(p, 2))
    1086             :   {
    1087           0 :     GEN f2 = ZXX_to_F2xX(x, get_FpX_var(T));
    1088           0 :     s = F2xqX_quad_roots(f2, ZX_to_F2x(get_FpX_mod(T)));
    1089           0 :     return F2xC_to_ZXC(s);
    1090             :   }
    1091         839 :   D = Fq_sub(Fq_sqr(b,T,p), Fq_Fp_mul(c,utoi(4),T,p), T,p);
    1092         839 :   nb = Fq_neg(b,T,p);
    1093         839 :   if (signe(D)==0)
    1094           0 :     return mkcol(Fq_to_FpXQ(Fq_halve(nb,T, p),T,p));
    1095         839 :   s = Fq_sqrt(D,T,p);
    1096         839 :   if (!s) return cgetg(1, t_COL);
    1097         825 :   s = Fq_halve(Fq_add(s,nb,T,p),T, p);
    1098         825 :   return mkcol2(Fq_to_FpXQ(s,T,p), Fq_to_FpXQ(Fq_sub(nb,s,T,p),T,p));
    1099             : }
    1100             : 
    1101             : static GEN
    1102        9289 : F2xqX_Frobenius_deflate(GEN S, GEN T)
    1103             : {
    1104        9289 :   GEN F = RgX_deflate(S, 2);
    1105        9289 :   long i, l = lg(F);
    1106       33243 :   for (i=2; i<l; i++)
    1107       23954 :     gel(F,i) = F2xq_sqrt(gel(F,i), T);
    1108        9289 :   return F;
    1109             : }
    1110             : 
    1111             : static GEN
    1112       17024 : F2xX_to_F2x(GEN x)
    1113             : {
    1114       17024 :   long l=nbits2lg(lgpol(x));
    1115       17024 :   GEN z=cgetg(l,t_VECSMALL);
    1116             :   long i,j,k;
    1117       17024 :   z[1]=x[1];
    1118       64526 :   for(i=2, k=1,j=BITS_IN_LONG;i<lg(x);i++,j++)
    1119             :   {
    1120       47502 :     if (j==BITS_IN_LONG)
    1121             :     {
    1122       17051 :       j=0; k++; z[k]=0;
    1123             :     }
    1124       47502 :     if (lgpol(gel(x,i)))
    1125       34615 :       z[k]|=1UL<<j;
    1126             :   }
    1127       17024 :   return F2x_renormalize(z,l);
    1128             : }
    1129             : 
    1130             : static GEN
    1131      205807 : F2xqX_easyroots(GEN f, GEN T)
    1132             : {
    1133      205807 :   if (F2xY_degreex(f) <= 0) return F2x_rootsff_i(F2xX_to_F2x(f), T);
    1134      189287 :   if (degpol(f)==1) return mkcol(constant_coeff(f));
    1135      154119 :   if (degpol(f)==2) return F2xqX_quad_roots(f,T);
    1136      143150 :   return NULL;
    1137             : }
    1138             : 
    1139             : /* Adapted from Shoup NTL */
    1140             : GEN
    1141       71232 : F2xqX_factor_squarefree(GEN f, GEN T)
    1142             : {
    1143       71232 :   pari_sp av = avma;
    1144             :   GEN r, t, v, tv;
    1145       71232 :   long i, q, n = degpol(f);
    1146       71232 :   GEN u = const_vec(n+1, pol1_F2xX(varn(f), get_F2x_var(T)));
    1147       71232 :   for(q = 1;;q *= 2)
    1148             :   {
    1149       80521 :     r = F2xqX_gcd(f, F2xX_deriv(f), T);
    1150       80521 :     if (degpol(r) == 0)
    1151             :     {
    1152       69559 :       gel(u, q) = F2xqX_normalize(f, T);
    1153       69559 :       break;
    1154             :     }
    1155       10962 :     t = F2xqX_div(f, r, T);
    1156       10962 :     if (degpol(t) > 0)
    1157             :     {
    1158             :       long j;
    1159       10052 :       for(j = 1;;j++)
    1160             :       {
    1161       14952 :         v = F2xqX_gcd(r, t, T);
    1162       14952 :         tv = F2xqX_div(t, v, T);
    1163       14952 :         if (degpol(tv) > 0)
    1164       11718 :           gel(u, j*q) = F2xqX_normalize(tv, T);
    1165       14952 :         if (degpol(v) <= 0) break;
    1166        4900 :         r = F2xqX_div(r, v, T);
    1167        4900 :         t = v;
    1168             :       }
    1169       10052 :       if (degpol(r) == 0) break;
    1170             :     }
    1171        9289 :     f = F2xqX_Frobenius_deflate(r, T);
    1172             :   }
    1173      417242 :   for (i = n; i; i--)
    1174      417242 :     if (degpol(gel(u,i))) break;
    1175       71232 :   setlg(u,i+1); return gerepilecopy(av, u);
    1176             : }
    1177             : 
    1178             : long
    1179          56 : F2xqX_ispower(GEN f, long k, GEN T, GEN *pt_r)
    1180             : {
    1181          56 :   pari_sp av = avma;
    1182             :   GEN lc, F;
    1183          56 :   long i, l, n = degpol(f);
    1184          56 :   if (n % k) return 0;
    1185          56 :   lc = F2xq_sqrtn(leading_coeff(f), stoi(k), T, NULL);
    1186          56 :   if (!lc) return gc_long(av,0);
    1187          56 :   F = F2xqX_factor_squarefree(f, T); l = lg(F)-1;
    1188        2030 :   for(i=1; i<=l; i++)
    1189        1981 :     if (i%k && degpol(gel(F,i))) return gc_long(av,0);
    1190          49 :   if (pt_r)
    1191             :   {
    1192          49 :     long v = varn(f);
    1193          49 :     GEN r = scalarpol(lc, v), s = pol1_F2xX(v, T[1]);
    1194        2023 :     for(i=l; i>=1; i--)
    1195             :     {
    1196        1974 :       if (i%k) continue;
    1197         406 :       s = F2xqX_mul(s, gel(F,i), T);
    1198         406 :       r = F2xqX_mul(r, s, T);
    1199             :     }
    1200          49 :     *pt_r = gerepileupto(av, r);
    1201           0 :   } else set_avma(av);
    1202          49 :   return 1;
    1203             : }
    1204             : 
    1205             : static void
    1206       49889 : F2xqX_roots_edf(GEN Sp, GEN xp, GEN Xp, GEN T, GEN V, long idx)
    1207             : {
    1208             :   pari_sp btop;
    1209       49889 :   long n = degpol(Sp);
    1210             :   GEN S, f, ff;
    1211       49889 :   long dT = get_F2x_degree(T);
    1212       49889 :   GEN R = F2xqX_easyroots(Sp, T);
    1213       49889 :   if (R)
    1214             :   {
    1215       47754 :     long i, l = lg(R)-1;
    1216      105987 :     for (i=0; i<l; i++)
    1217       58233 :       gel(V, idx+i) = gel(R,1+i);
    1218       47754 :     return;
    1219             :   }
    1220        2135 :   S = F2xqX_get_red(Sp, T);
    1221        2135 :   Xp = F2xqX_rem(Xp, S, T);
    1222        2135 :   btop = avma;
    1223             :   while (1)
    1224         595 :   {
    1225        2730 :     GEN a = random_F2xqX(degpol(Sp), varn(Sp), T);
    1226        2730 :     GEN R = gel(F2xqXQ_auttrace(mkvec3(xp, Xp, a), dT, S, T), 3);
    1227        2730 :     f = F2xqX_gcd(R, Sp, T);
    1228        2730 :     if (degpol(f) > 0 && degpol(f) < n) break;
    1229         595 :     set_avma(btop);
    1230             :   }
    1231        2135 :   f = gerepileupto(btop, F2xqX_normalize(f, T));
    1232        2135 :   ff = F2xqX_div(Sp, f, T);
    1233        2135 :   F2xqX_roots_edf(f, xp, Xp, T, V, idx);
    1234        2135 :   F2xqX_roots_edf(ff,xp, Xp, T, V, idx+degpol(f));
    1235             : }
    1236             : 
    1237             : static GEN
    1238       80787 : F2xqX_roots_ddf(GEN f, GEN xp, GEN T)
    1239             : {
    1240             :   GEN X, Xp, Xq, g, V;
    1241             :   long n;
    1242       80787 :   GEN R = F2xqX_easyroots(f, T);
    1243       80787 :   if (R) return R;
    1244       70147 :   X  = pol_x(varn(f));
    1245       70147 :   Xp = F2xqXQ_sqr(X, f, T);
    1246       70147 :   Xq = F2xqXQ_Frobenius(xp, Xp, f, T);
    1247       70147 :   g = F2xqX_gcd(F2xX_add(Xq, X), f, T);
    1248       70147 :   n = degpol(g);
    1249       70147 :   if (n==0) return cgetg(1, t_COL);
    1250       45619 :   g = F2xqX_normalize(g, T);
    1251       45619 :   V = cgetg(n+1,t_COL);
    1252       45619 :   F2xqX_roots_edf(g, xp, Xp, T, V, 1);
    1253       45619 :   return V;
    1254             : }
    1255             : static GEN
    1256       75138 : F2xqX_roots_i(GEN S, GEN T)
    1257             : {
    1258             :   GEN M;
    1259       75138 :   S = F2xqX_red(S, T);
    1260       75138 :   if (!signe(S)) pari_err_ROOTS0("F2xqX_roots");
    1261       75138 :   if (degpol(S)==0) return cgetg(1, t_COL);
    1262       75131 :   S = F2xqX_normalize(S, T);
    1263       75131 :   M = F2xqX_easyroots(S, T);
    1264       75131 :   if (!M)
    1265             :   {
    1266       70868 :     GEN xp = F2x_Frobenius(T);
    1267       70868 :     GEN F, V = F2xqX_factor_squarefree(S, T);
    1268       70868 :     long i, j, l = lg(V);
    1269       70868 :     F = cgetg(l, t_VEC);
    1270      154567 :     for (i=1, j=1; i < l; i++)
    1271       83699 :       if (degpol(gel(V,i)))
    1272       80787 :         gel(F, j++) = F2xqX_roots_ddf(gel(V,i), xp, T);
    1273       70868 :     setlg(F,j); M = shallowconcat1(F);
    1274             :   }
    1275       75131 :   gen_sort_inplace(M, (void*) &cmp_Flx, &cmp_nodata, NULL);
    1276       75131 :   return M;
    1277             : }
    1278             : 
    1279             : static GEN
    1280      183795 : FlxqX_easyroots(GEN f, GEN T, ulong p, ulong pi)
    1281             : {
    1282      183795 :   if (FlxY_degreex(f) <= 0) return Flx_rootsff_i(FlxX_to_Flx(f), T, p);
    1283      170389 :   if (degpol(f)==1) return mkcol(Flx_neg(constant_coeff(f), p));
    1284      141585 :   if (degpol(f)==2) return FlxqX_quad_roots(f,T,p,pi);
    1285      127726 :   return NULL;
    1286             : }
    1287             : 
    1288             : static GEN
    1289         581 : FlxqX_invFrobenius(GEN xp, GEN T, ulong p, ulong pi)
    1290         581 : { return Flxq_autpow_pre(xp, get_Flx_degree(T)-1, T, p, pi); }
    1291             : 
    1292             : static GEN
    1293         644 : FlxqX_Frobenius_deflate(GEN S, GEN ixp, GEN T, ulong p)
    1294             : {
    1295         644 :   GEN F = RgX_deflate(S, p);
    1296         644 :   long i, l = lg(F);
    1297         644 :   if (typ(ixp)==t_INT)
    1298           0 :     for (i=2; i<l; i++)
    1299           0 :       gel(F,i) = Flxq_pow(gel(F,i), ixp, T, p);
    1300             :   else
    1301             :   {
    1302         644 :     long n = brent_kung_optpow(get_Flx_degree(T)-1, l-2, 1);
    1303         644 :     GEN V = Flxq_powers(ixp, n, T, p);
    1304        5747 :     for (i=2; i<l; i++)
    1305        5103 :       gel(F,i) = Flx_FlxqV_eval(gel(F,i), V, T, p);
    1306             :   }
    1307         644 :   return F;
    1308             : }
    1309             : 
    1310             : /* Adapted from Shoup NTL */
    1311             : static GEN
    1312       59975 : FlxqX_factor_squarefree_i(GEN f, GEN xp, GEN T, ulong p, ulong pi)
    1313             : {
    1314       59975 :   pari_sp av = avma;
    1315       59975 :   long i, q, n = degpol(f);
    1316       59975 :   GEN u = const_vec(n+1, pol1_FlxX(varn(f),get_Flx_var(T)));
    1317       59975 :   GEN r, t, v, tv, ixp = NULL;
    1318       59975 :   for(q = 1;; q *= p)
    1319             :   {
    1320       60619 :     r = FlxqX_gcd_pre(f, FlxX_deriv(f, p), T, p, pi);
    1321       60619 :     if (degpol(r) == 0)
    1322             :     {
    1323       55743 :       gel(u, q) = FlxqX_normalize_pre(f, T, p, pi);
    1324       55743 :       break;
    1325             :     }
    1326        4876 :     t = FlxqX_div_pre(f, r, T, p, pi);
    1327        4876 :     if (degpol(t) > 0)
    1328             :     {
    1329             :       long j;
    1330        4659 :       for(j = 1;;j++)
    1331             :       {
    1332       10151 :         v = FlxqX_gcd_pre(r, t, T, p, pi);
    1333       10151 :         tv = FlxqX_div_pre(t, v, T, p, pi);
    1334       10151 :         if (degpol(tv) > 0)
    1335        8765 :           gel(u, j*q) = FlxqX_normalize_pre(tv, T, p, pi);
    1336       10151 :         if (degpol(v) <= 0) break;
    1337        5492 :         r = FlxqX_div_pre(r, v, T, p, pi);
    1338        5492 :         t = v;
    1339             :       }
    1340        4659 :       if (degpol(r) == 0) break;
    1341             :     }
    1342         644 :     if (!xp)   xp = Flx_Frobenius_pre(T, p, pi);
    1343         644 :     if (!ixp) ixp = FlxqX_invFrobenius(xp, T, p, pi);
    1344         644 :     f = FlxqX_Frobenius_deflate(r, ixp, T, p);
    1345             :   }
    1346      323948 :   for (i = n; i; i--)
    1347      323948 :     if (degpol(gel(u,i))) break;
    1348       59975 :   setlg(u,i+1); return gerepilecopy(av, u);
    1349             : }
    1350             : 
    1351             : GEN
    1352          42 : FlxqX_factor_squarefree_pre(GEN f, GEN T, ulong p, ulong pi)
    1353          42 : { return FlxqX_factor_squarefree_i(f, NULL, T, p, pi); }
    1354             : GEN
    1355           0 : FlxqX_factor_squarefree(GEN f, GEN T, ulong p)
    1356           0 : { return FlxqX_factor_squarefree_pre(f,T,p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    1357             : 
    1358             : long
    1359          98 : FlxqX_ispower(GEN f, ulong k, GEN T, ulong p, GEN *pt_r)
    1360             : {
    1361          98 :   pari_sp av = avma;
    1362             :   GEN lc, F;
    1363          98 :   long i, l, n = degpol(f), v = varn(f);
    1364             :   ulong pi;
    1365             : 
    1366          98 :   if (n % k) return 0;
    1367          98 :   lc = Flxq_sqrtn(leading_coeff(f), stoi(k), T, p, NULL);
    1368          98 :   if (!lc) return gc_long(av,0);
    1369          98 :   pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
    1370          98 :   F = FlxqX_factor_squarefree_i(f, NULL, T, p, pi); l = lg(F)-1;
    1371        3521 :   for(i=1; i<=l; i++)
    1372        3437 :     if (i%k && degpol(gel(F,i))) return gc_long(av,0);
    1373          84 :   if (pt_r)
    1374             :   {
    1375          84 :     GEN r = scalarpol(lc, v), s = pol1_FlxX(v, T[1]);
    1376        3507 :     for(i=l; i>=1; i--)
    1377             :     {
    1378        3423 :       if (i%k) continue;
    1379         700 :       s = FlxqX_mul_pre(s, gel(F,i), T, p, pi);
    1380         700 :       r = FlxqX_mul_pre(r, s, T, p, pi);
    1381             :     }
    1382          84 :     *pt_r = gerepileupto(av, r);
    1383           0 :   } else set_avma(av);
    1384          84 :   return 1;
    1385             : }
    1386             : 
    1387             : static GEN
    1388        9442 : FlxqX_roots_split(GEN Sp, GEN xp, GEN Xp, GEN S, GEN T, ulong p, long pi)
    1389             : {
    1390        9442 :   pari_sp btop = avma;
    1391        9442 :   long n = degpol(Sp);
    1392             :   GEN f;
    1393        9442 :   long vT = get_Flx_var(T), dT = get_Flx_degree(T);
    1394             :   pari_timer ti;
    1395        9442 :   if (DEBUGLEVEL >= 7) timer_start(&ti);
    1396             :   while (1)
    1397        2021 :   {
    1398       11463 :     GEN a = deg1pol(pol1_Flx(vT), random_Flx(dT, vT, p), varn(Sp));
    1399       11463 :     GEN R = FlxqXQ_halfFrobenius_i(a, xp, Xp, S, T, p, pi);
    1400       11463 :     if (DEBUGLEVEL >= 7) timer_printf(&ti, "FlxqXQ_halfFrobenius");
    1401       11463 :     f = FlxqX_gcd_pre(FlxX_Flx_sub(R, pol1_Flx(vT), p), Sp, T, p, pi);
    1402       11463 :     if (degpol(f) > 0 && degpol(f) < n) break;
    1403        2021 :     set_avma(btop);
    1404             :   }
    1405        9442 :   return gerepileupto(btop, FlxqX_normalize_pre(f, T, p, pi));
    1406             : }
    1407             : 
    1408             : static void
    1409       53422 : FlxqX_roots_edf(GEN Sp, GEN xp, GEN Xp, GEN T, ulong p, ulong pi, GEN V, long idx)
    1410             : {
    1411             :   GEN S, f, ff;
    1412       53422 :   GEN R = FlxqX_easyroots(Sp, T, p, pi);
    1413       53422 :   if (R)
    1414             :   {
    1415       44342 :     long i, l = lg(R)-1;
    1416      102484 :     for (i=0; i<l; i++)
    1417       58142 :       gel(V, idx+i) = gel(R,1+i);
    1418       44342 :     return;
    1419             :   }
    1420        9080 :   S  = FlxqX_get_red_pre(Sp, T, p, pi);
    1421        9080 :   Xp = FlxqX_rem_pre(Xp, S, T, p, pi);
    1422        9080 :   f  = FlxqX_roots_split(Sp, xp, Xp, S, T, p, pi);
    1423        9080 :   ff = FlxqX_div_pre(Sp, f, T, p, pi);
    1424        9080 :   FlxqX_roots_edf(f, xp, Xp, T, p, pi, V, idx);
    1425        9080 :   FlxqX_roots_edf(ff,xp, Xp, T, p, pi, V, idx+degpol(f));
    1426             : }
    1427             : 
    1428             : static GEN
    1429       63886 : FlxqX_roots_ddf(GEN f, GEN xp, GEN T, ulong p, ulong pi)
    1430             : {
    1431             :   GEN X, Xp, Xq, g, V;
    1432             :   long n;
    1433       63886 :   GEN R = FlxqX_easyroots(f, T, p, pi);
    1434       63886 :   if (R) return R;
    1435       59118 :   X  = pol_x(varn(f));
    1436       59118 :   Xp = FlxqXQ_powu_pre(X, p, f, T, p, pi);
    1437       59118 :   Xq = FlxqXQ_Frobenius(xp, Xp, f, T, p, pi);
    1438       59118 :   g = FlxqX_gcd_pre(FlxX_sub(Xq, X, p), f, T, p, pi);
    1439       59118 :   n = degpol(g);
    1440       59118 :   if (n==0) return cgetg(1, t_COL);
    1441       35262 :   g = FlxqX_normalize_pre(g, T, p, pi);
    1442       35262 :   V = cgetg(n+1,t_COL);
    1443       35262 :   FlxqX_roots_edf(g, xp, Xp, T, p, pi, V, 1);
    1444       35262 :   return V;
    1445             : }
    1446             : 
    1447             : /* do not handle p==2 */
    1448             : static GEN
    1449       66494 : FlxqX_roots_i(GEN S, GEN T, ulong p)
    1450             : {
    1451       66494 :   ulong pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
    1452             :   GEN M;
    1453       66494 :   S = FlxqX_red_pre(S, T, p, pi);
    1454       66494 :   if (!signe(S)) pari_err_ROOTS0("FlxqX_roots");
    1455       66494 :   if (degpol(S)==0) return cgetg(1, t_COL);
    1456       66487 :   S = FlxqX_normalize_pre(S, T, p, pi);
    1457       66487 :   M = FlxqX_easyroots(S, T, p, pi);
    1458       66487 :   if (!M)
    1459             :   {
    1460       59528 :     GEN xp = Flx_Frobenius_pre(T, p, pi);
    1461       59528 :     GEN F, V = FlxqX_factor_squarefree_i(S, xp, T, p, pi);
    1462       59528 :     long i, j, l = lg(V);
    1463       59528 :     F = cgetg(l, t_VEC);
    1464      124051 :     for (i=1, j=1; i < l; i++)
    1465       64523 :       if (degpol(gel(V,i)))
    1466       63886 :         gel(F, j++) = FlxqX_roots_ddf(gel(V,i), xp, T, p, pi);
    1467       59528 :     setlg(F,j); M = shallowconcat1(F);
    1468             :   }
    1469       66487 :   gen_sort_inplace(M, (void*) &cmp_Flx, &cmp_nodata, NULL);
    1470       66487 :   return M;
    1471             : }
    1472             : 
    1473             : static GEN
    1474        2576 : FpXQX_easyroots(GEN f, GEN T, GEN p)
    1475             : {
    1476        2576 :   if (isabsolutepol(f)) return FpX_rootsff_i(simplify_shallow(f), T, p);
    1477        2268 :   if (degpol(f)==1) return mkcol(Fq_to_FpXQ(Fq_neg(constant_coeff(f),T,p),T,p));
    1478        1867 :   if (degpol(f)==2) return FpXQX_quad_roots(f,T,p);
    1479        1071 :   return NULL;
    1480             : }
    1481             : 
    1482             : /* Adapted from Shoup NTL */
    1483             : static GEN
    1484         210 : FpXQX_factor_Yun(GEN f, GEN T, GEN p)
    1485             : {
    1486         210 :   pari_sp av = avma;
    1487             :   GEN r, t, v, tv;
    1488         210 :   long j, n = degpol(f);
    1489         210 :   GEN u = const_vec(n+1, pol_1(varn(f)));
    1490         210 :   r = FpXQX_gcd(f, FpXX_deriv(f, p), T, p);
    1491         210 :   t = FpXQX_div(f, r, T, p);
    1492         210 :   for (j = 1;;j++)
    1493             :   {
    1494        1652 :     v = FpXQX_gcd(r, t, T, p);
    1495        1652 :     tv = FpXQX_div(t, v, T, p);
    1496        1652 :     if (degpol(tv) > 0)
    1497         252 :       gel(u, j) = FpXQX_normalize(tv, T, p);
    1498        1652 :     if (degpol(v) <= 0) break;
    1499        1442 :     r = FpXQX_div(r, v, T, p);
    1500        1442 :     t = v;
    1501             :   }
    1502         210 :   setlg(u, j+1); return gerepilecopy(av, u);
    1503             : }
    1504             : 
    1505             : GEN
    1506           7 : FpXQX_factor_squarefree(GEN f, GEN T, GEN p)
    1507             : {
    1508           7 :   if (lgefint(p)==3)
    1509             :   {
    1510           0 :     pari_sp av = avma;
    1511           0 :     ulong pp = p[2];
    1512             :     GEN M;
    1513           0 :     long vT = get_FpX_var(T);
    1514           0 :     if (pp==2)
    1515             :     {
    1516           0 :       M = F2xqX_factor_squarefree(ZXX_to_F2xX(f, vT),  ZX_to_F2x(get_FpX_mod(T)));
    1517           0 :       return gerepileupto(av, F2xXC_to_ZXXC(M));
    1518             :     }
    1519           0 :     M = FlxqX_factor_squarefree(ZXX_to_FlxX(f, pp, vT),  ZXT_to_FlxT(T, pp), pp);
    1520           0 :     return gerepileupto(av, FlxXC_to_ZXXC(M));
    1521             :   }
    1522           7 :   return FpXQX_factor_Yun(f, T, p);
    1523             : }
    1524             : 
    1525             : GEN
    1526           0 : FpXQX_roots_mult(GEN f, long n, GEN T, GEN p)
    1527             : {
    1528           0 :   pari_sp av = avma;
    1529           0 :   GEN V = FpXQX_factor_squarefree(f, T, p), W;
    1530           0 :   long l = lg(V), i;
    1531           0 :   if (l <= n) return cgetg(1,t_COL);
    1532           0 :   W = cgetg(l-n+1,t_VEC);
    1533           0 :   for (i = n; i < l; i++)
    1534           0 :     gel(W,i-n+1) = FpXQX_roots(gel(V,i), T, p);
    1535           0 :   W = shallowconcat1(W);
    1536           0 :   gen_sort_inplace(W, (void*) &cmp_RgX, &cmp_nodata, NULL);
    1537           0 :   return gerepilecopy(av, W);
    1538             : }
    1539             : 
    1540             : long
    1541          98 : FpXQX_ispower(GEN f, ulong k, GEN T, GEN p, GEN *pt_r)
    1542             : {
    1543          98 :   pari_sp av = avma;
    1544             :   GEN lc, F;
    1545          98 :   long i, l, n = degpol(f), v = varn(f);
    1546          98 :   if (n % k) return 0;
    1547          98 :   if (lgefint(p)==3)
    1548             :   {
    1549          42 :     ulong pp = p[2];
    1550          42 :     GEN fp = ZXX_to_FlxX(f, pp, varn(T));
    1551          42 :     if (!FlxqX_ispower(fp, k, ZX_to_Flx(T,pp), pp, pt_r)) return gc_long(av,0);
    1552          35 :     if (pt_r) *pt_r = gerepileupto(av, FlxX_to_ZXX(*pt_r));
    1553           0 :     else set_avma(av);
    1554          35 :     return 1;
    1555             :   }
    1556          56 :   lc = FpXQ_sqrtn(leading_coeff(f), stoi(k), T, p, NULL);
    1557          56 :   if (!lc) return gc_long(av,0);
    1558          56 :   F = FpXQX_factor_Yun(f, T, p); l = lg(F)-1;
    1559        1533 :   for(i=1; i <= l; i++)
    1560        1484 :     if (i%k && degpol(gel(F,i))) return gc_long(av,0);
    1561          49 :   if (pt_r)
    1562             :   {
    1563          49 :     GEN r = scalarpol(lc, v), s = pol_1(v);
    1564        1526 :     for(i=l; i>=1; i--)
    1565             :     {
    1566        1477 :       if (i%k) continue;
    1567         308 :       s = FpXQX_mul(s, gel(F,i), T, p);
    1568         308 :       r = FpXQX_mul(r, s, T, p);
    1569             :     }
    1570          49 :     *pt_r = gerepileupto(av, r);
    1571           0 :   } else set_avma(av);
    1572          49 :   return 1;
    1573             : }
    1574             : 
    1575             : long
    1576         210 : FqX_ispower(GEN f, ulong k, GEN T, GEN p, GEN *pt_r)
    1577         210 : { return T ? FpXQX_ispower(f, k, T, p, pt_r): FpX_ispower(f, k, p, pt_r); }
    1578             : 
    1579             : static GEN
    1580         928 : FpXQX_roots_split(GEN Sp, GEN xp, GEN Xp, GEN S, GEN T, GEN p)
    1581             : {
    1582         928 :   pari_sp btop = avma;
    1583         928 :   long n = degpol(Sp);
    1584             :   GEN f;
    1585         928 :   long vT = get_FpX_var(T), dT = get_FpX_degree(T);
    1586             :   pari_timer ti;
    1587         928 :   if (DEBUGLEVEL >= 7) timer_start(&ti);
    1588             :   while (1)
    1589         141 :   {
    1590        1069 :     GEN a = deg1pol(pol_1(vT), random_FpX(dT, vT, p), varn(Sp));
    1591        1069 :     GEN R = FpXQXQ_halfFrobenius_i(a, xp, Xp, S, T, p);
    1592        1069 :     if (DEBUGLEVEL >= 7) timer_printf(&ti, "FpXQXQ_halfFrobenius");
    1593        1069 :     f = FpXQX_gcd(FqX_Fq_sub(R, pol_1(vT), T, p), Sp, T, p);
    1594        1069 :     if (degpol(f) > 0 && degpol(f) < n) break;
    1595         141 :     set_avma(btop);
    1596             :   }
    1597         928 :   return gerepileupto(btop, FpXQX_normalize(f, T, p));
    1598             : }
    1599             : 
    1600             : static void
    1601        1893 : FpXQX_roots_edf(GEN Sp, GEN xp, GEN Xp, GEN T, GEN p, GEN V, long idx)
    1602             : {
    1603             :   GEN S, f, ff;
    1604        1893 :   GEN R = FpXQX_easyroots(Sp, T, p);
    1605        1893 :   if (R)
    1606             :   {
    1607         988 :     long i, l = lg(R)-1;
    1608        2576 :     for (i=0; i<l; i++)
    1609        1588 :       gel(V, idx+i) = gel(R,1+i);
    1610         988 :     return;
    1611             :   }
    1612         905 :   S  = FpXQX_get_red(Sp, T, p);
    1613         905 :   Xp = FpXQX_rem(Xp, S, T, p);
    1614         905 :   f  = FpXQX_roots_split(Sp, xp, Xp, S, T, p);
    1615         905 :   ff = FpXQX_div(Sp, f, T, p);
    1616         905 :   FpXQX_roots_edf(f, xp, Xp, T, p, V, idx);
    1617         905 :   FpXQX_roots_edf(ff,xp, Xp, T, p, V, idx+degpol(f));
    1618             : }
    1619             : 
    1620             : static GEN
    1621          83 : FpXQX_roots_ddf(GEN f, GEN xp, GEN T, GEN p)
    1622             : {
    1623             :   GEN X, Xp, Xq, g, V;
    1624             :   long n;
    1625          83 :   GEN R = FpXQX_easyroots(f, T, p);
    1626          83 :   if (R) return R;
    1627          83 :   X  = pol_x(varn(f));
    1628          83 :   Xp = FpXQXQ_pow(X, p, f, T, p);
    1629          83 :   Xq = FpXQXQ_Frobenius(xp, Xp, f, T, p);
    1630          83 :   g = FpXQX_gcd(FpXX_sub(Xq, X, p), f, T, p);
    1631          83 :   n = degpol(g);
    1632          83 :   if (n==0) return cgetg(1, t_COL);
    1633          83 :   g = FpXQX_normalize(g, T, p);
    1634          83 :   V = cgetg(n+1,t_COL);
    1635          83 :   FpXQX_roots_edf(g, xp, Xp, T, p, V, 1);
    1636          83 :   return V;
    1637             : }
    1638             : 
    1639             : /* do not handle small p */
    1640             : static GEN
    1641       24454 : FpXQX_roots_i(GEN S, GEN T, GEN p)
    1642             : {
    1643             :   GEN F, M;
    1644       24454 :   if (lgefint(p)==3)
    1645             :   {
    1646       23854 :     ulong pp = p[2];
    1647       23854 :     if (pp == 2)
    1648             :     {
    1649        3843 :       GEN V = F2xqX_roots_i(ZXX_to_F2xX(S,get_FpX_var(T)), ZX_to_F2x(get_FpX_mod(T)));
    1650        3843 :       return F2xC_to_ZXC(V);
    1651             :     }
    1652             :     else
    1653             :     {
    1654       20011 :       GEN V = FlxqX_roots_i(ZXX_to_FlxX(S,pp,get_FpX_var(T)),
    1655             :                             ZXT_to_FlxT(T,pp), pp);
    1656       20011 :       return FlxC_to_ZXC(V);
    1657             :     }
    1658             :   }
    1659         600 :   S = FpXQX_red(S, T, p);
    1660         600 :   if (!signe(S)) pari_err_ROOTS0("FpXQX_roots");
    1661         600 :   if (degpol(S)==0) return cgetg(1, t_COL);
    1662         600 :   S = FpXQX_normalize(S, T, p);
    1663         600 :   M = FpXQX_easyroots(S, T, p);
    1664         600 :   if (!M)
    1665             :   {
    1666          83 :     GEN xp = FpX_Frobenius(T, p);
    1667          83 :     GEN V = FpXQX_factor_Yun(S, T, p);
    1668          83 :     long i, j, l = lg(V);
    1669          83 :     F = cgetg(l, t_VEC);
    1670         166 :     for (i=1, j=1; i < l; i++)
    1671          83 :       if (degpol(gel(V,i)))
    1672          83 :         gel(F, j++) = FpXQX_roots_ddf(gel(V,i), xp, T, p);
    1673          83 :     setlg(F,j); M = shallowconcat1(F);
    1674             :   }
    1675         600 :   gen_sort_inplace(M, (void*) &cmp_RgX, &cmp_nodata, NULL);
    1676         600 :   return M;
    1677             : }
    1678             : 
    1679             : GEN
    1680       71295 : F2xqX_roots(GEN x, GEN T)
    1681             : {
    1682       71295 :   pari_sp av = avma;
    1683       71295 :   return gerepilecopy(av, F2xqX_roots_i(x, T));
    1684             : }
    1685             : 
    1686             : GEN
    1687       46483 : FlxqX_roots(GEN x, GEN T, ulong p)
    1688             : {
    1689       46483 :   pari_sp av = avma;
    1690       46483 :   if (p==2)
    1691             :   {
    1692           0 :     GEN V = F2xqX_roots_i(FlxX_to_F2xX(x), Flx_to_F2x(get_Flx_mod(T)));
    1693           0 :     return gerepileupto(av, F2xC_to_FlxC(V));
    1694             :   }
    1695       46483 :   return gerepilecopy(av, FlxqX_roots_i(x, T, p));
    1696             : }
    1697             : 
    1698             : GEN
    1699       24454 : FpXQX_roots(GEN x, GEN T, GEN p)
    1700             : {
    1701       24454 :   pari_sp av = avma;
    1702       24454 :   return gerepilecopy(av, FpXQX_roots_i(x, T, p));
    1703             : }
    1704             : 
    1705             : static GEN
    1706         595 : FE_concat(GEN F, GEN E, long l)
    1707             : {
    1708         595 :   setlg(E,l); E = shallowconcat1(E);
    1709         595 :   setlg(F,l); F = shallowconcat1(F); return mkvec2(F,E);
    1710             : }
    1711             : 
    1712             : static GEN
    1713         588 : F2xqX_factor_2(GEN f, GEN T)
    1714             : {
    1715         588 :   long v = varn(f), vT = get_F2x_var(T);
    1716         588 :   GEN r = F2xqX_quad_roots(f, T);
    1717         588 :   switch(lg(r)-1)
    1718             :   {
    1719          14 :   case 0:
    1720          14 :     return mkvec2(mkcolcopy(f), mkvecsmall(1));
    1721         567 :   case 1:
    1722         567 :     return mkvec2(mkcol(deg1pol_shallow(pol1_F2x(vT), gel(r,1), v)), mkvecsmall(2));
    1723           7 :   default: /* 2 */
    1724             :     {
    1725           7 :       GEN f1 = deg1pol_shallow(pol1_F2x(vT), gel(r,1), v);
    1726           7 :       GEN f2 = deg1pol_shallow(pol1_F2x(vT), gel(r,2), v);
    1727           7 :       GEN t = mkcol2(f1, f2), E = mkvecsmall2(1, 1);
    1728           7 :       sort_factor_pol(mkvec2(t, E), cmp_Flx);
    1729           7 :       return mkvec2(t, E);
    1730             :     }
    1731             :   }
    1732             : }
    1733             : 
    1734             : static GEN
    1735         832 : FlxqX_factor_2(GEN f, GEN T, ulong p, ulong pi)
    1736             : {
    1737         832 :   long v = varn(f), vT = get_Flx_var(T);
    1738         832 :   GEN r = FlxqX_quad_roots(f, T, p, pi);
    1739         832 :   switch(lg(r)-1)
    1740             :   {
    1741          56 :   case 0:
    1742          56 :     return mkvec2(mkcolcopy(f), mkvecsmall(1));
    1743          42 :   case 1:
    1744          84 :     return mkvec2(mkcol(deg1pol_shallow(pol1_Flx(vT),
    1745          42 :                         Flx_neg(gel(r,1), p), v)), mkvecsmall(2));
    1746         734 :   default: /* 2 */
    1747             :     {
    1748         734 :       GEN f1 = deg1pol_shallow(pol1_Flx(vT), Flx_neg(gel(r,1), p), v);
    1749         734 :       GEN f2 = deg1pol_shallow(pol1_Flx(vT), Flx_neg(gel(r,2), p), v);
    1750         734 :       GEN t = mkcol2(f1, f2), E = mkvecsmall2(1, 1);
    1751         734 :       sort_factor_pol(mkvec2(t, E), cmp_Flx);
    1752         734 :       return mkvec2(t, E);
    1753             :     }
    1754             :   }
    1755             : }
    1756             : 
    1757             : static GEN
    1758          43 : FpXQX_factor_2(GEN f, GEN T, GEN p)
    1759             : {
    1760          43 :   long v = varn(f);
    1761          43 :   GEN r = FpXQX_quad_roots(f, T, p);
    1762          43 :   switch(lg(r)-1)
    1763             :   {
    1764          14 :   case 0:
    1765          14 :     return mkvec2(mkcolcopy(f), mkvecsmall(1));
    1766           0 :   case 1:
    1767           0 :     return mkvec2(mkcol(deg1pol_shallow(gen_1, Fq_neg(gel(r,1), T, p), v)),
    1768             :         mkvecsmall(2));
    1769          29 :   default: /* 2 */
    1770             :     {
    1771          29 :       GEN f1 = deg1pol_shallow(gen_1, Fq_neg(gel(r,1), T, p), v);
    1772          29 :       GEN f2 = deg1pol_shallow(gen_1, Fq_neg(gel(r,2), T, p), v);
    1773          29 :       GEN t = mkcol2(f1, f2), E = mkvecsmall2(1, 1);
    1774          29 :       sort_factor_pol(mkvec2(t, E), cmp_RgX);
    1775          29 :       return mkvec2(t, E);
    1776             :     }
    1777             :   }
    1778             : }
    1779             : 
    1780             : static GEN
    1781         350 : F2xqX_ddf_Shoup(GEN S, GEN Xq, GEN T)
    1782             : {
    1783         350 :   pari_sp av = avma;
    1784             :   GEN b, g, h, F, f, Sr, xq;
    1785             :   long i, j, n, v, vT, dT, bo, ro;
    1786             :   long B, l, m;
    1787             :   pari_timer ti;
    1788         350 :   n = get_F2xqX_degree(S); v = get_F2xqX_var(S);
    1789         350 :   vT = get_F2x_var(T); dT = get_F2x_degree(T);
    1790         350 :   if (n == 0) return cgetg(1, t_VEC);
    1791         350 :   if (n == 1) return mkvec(get_F2xqX_mod(S));
    1792         140 :   B = n/2;
    1793         140 :   l = usqrt(B);
    1794         140 :   m = (B+l-1)/l;
    1795         140 :   S = F2xqX_get_red(S, T);
    1796         140 :   b = cgetg(l+2, t_VEC);
    1797         140 :   gel(b, 1) = polx_F2xX(v, vT);
    1798         140 :   gel(b, 2) = Xq;
    1799         140 :   bo = brent_kung_optpow(n, l-1, 1);
    1800         140 :   ro = l<=1 ? 0: (bo-1)/(l-1) + ((n-1)/bo);
    1801         140 :   if (DEBUGLEVEL>=7) timer_start(&ti);
    1802         140 :   if (dT <= ro)
    1803           0 :     for (i = 3; i <= l+1; i++)
    1804           0 :       gel(b, i) = F2xqXQ_pow(gel(b, i-1), int2n(dT), S, T);
    1805             :   else
    1806             :   {
    1807         140 :     xq = F2xqXQ_powers(gel(b, 2), bo, S, T);
    1808         140 :     if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: xq baby");
    1809         140 :     for (i = 3; i <= l+1; i++)
    1810           0 :       gel(b, i) = F2xqX_F2xqXQV_eval(gel(b, i-1), xq, S, T);
    1811             :   }
    1812         140 :   if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: baby");
    1813         140 :   xq = F2xqXQ_powers(gel(b, l+1), brent_kung_optpow(n, m-1, 1), S, T);
    1814         140 :   if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: xq giant");
    1815         140 :   g = cgetg(m+1, t_VEC);
    1816         140 :   gel(g, 1) = gel(xq, 2);
    1817         168 :   for(i = 2; i <= m; i++)
    1818          28 :     gel(g, i) = F2xqX_F2xqXQV_eval(gel(g, i-1), xq, S, T);
    1819         140 :   if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: giant");
    1820         140 :   h = cgetg(m+1, t_VEC);
    1821         308 :   for (j = 1; j <= m; j++)
    1822             :   {
    1823         168 :     pari_sp av = avma;
    1824         168 :     GEN gj = gel(g, j);
    1825         168 :     GEN e = F2xX_add(gj, gel(b, 1));
    1826         168 :     for (i = 2; i <= l; i++)
    1827           0 :       e = F2xqXQ_mul(e, F2xX_add(gj, gel(b, i)), S, T);
    1828         168 :     gel(h, j) = gerepileupto(av, e);
    1829             :   }
    1830         140 :   if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: diff");
    1831         140 :   Sr = get_F2xqX_mod(S);
    1832         140 :   F = cgetg(m+1, t_VEC);
    1833         308 :   for (j = 1; j <= m; j++)
    1834             :   {
    1835         168 :     GEN u = F2xqX_gcd(Sr, gel(h,j), T);
    1836         168 :     if (degpol(u))
    1837             :     {
    1838         112 :       u = F2xqX_normalize(u, T);
    1839         112 :       Sr = F2xqX_div(Sr, u, T);
    1840             :     }
    1841         168 :     gel(F,j) = u;
    1842             :   }
    1843         140 :   if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: F");
    1844         140 :   f = const_vec(n, pol1_F2xX(v, vT));
    1845         308 :   for (j = 1; j <= m; j++)
    1846             :   {
    1847         168 :     GEN e = gel(F, j);
    1848         168 :     for (i=l-1; i >= 0; i--)
    1849             :     {
    1850         168 :       GEN u = F2xqX_gcd(e, F2xX_add(gel(g, j), gel(b, i+1)), T);
    1851         168 :       if (degpol(u))
    1852             :       {
    1853         112 :         gel(f, l*j-i) = u = F2xqX_normalize(u, T);
    1854         112 :         e = F2xqX_div(e, u, T);
    1855             :       }
    1856         168 :       if (!degpol(e)) break;
    1857             :     }
    1858             :   }
    1859         140 :   if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: f");
    1860         140 :   if (degpol(Sr)) gel(f, degpol(Sr)) = Sr;
    1861         140 :   return gerepilecopy(av, f);
    1862             : }
    1863             : 
    1864             : static GEN
    1865          91 : F2xqX_ddf_i(GEN f, GEN T, GEN X, GEN xp)
    1866             : {
    1867             :   GEN Xp, Xq;
    1868          91 :   if (!get_F2xqX_degree(f)) return cgetg(1,t_VEC);
    1869          42 :   f = F2xqX_get_red(f, T);
    1870          42 :   Xp = F2xqXQ_sqr(X, f, T);
    1871          42 :   Xq = F2xqXQ_Frobenius(xp, Xp, f, T);
    1872          42 :   return F2xqX_ddf_Shoup(f, Xq, T);
    1873             : }
    1874             : static void
    1875          42 : F2xqX_ddf_init(GEN *S, GEN *T, GEN *xp, GEN *X)
    1876             : {
    1877          42 :   *T = F2x_get_red(*T);
    1878          42 :   *S = F2xqX_normalize(get_F2xqX_mod(*S), *T);
    1879          42 :   *xp = F2x_Frobenius(*T);
    1880          42 :   *X  = polx_F2xX(get_F2xqX_var(*S), get_F2x_var(*T));
    1881          42 : }
    1882             : GEN
    1883          42 : F2xqX_degfact(GEN S, GEN T)
    1884             : {
    1885             :   GEN xp, X, V;
    1886             :   long i, l;
    1887          42 :   F2xqX_ddf_init(&S,&T,&xp,&X);
    1888          42 :   V = F2xqX_factor_squarefree(S, T); l = lg(V);
    1889         133 :   for (i=1; i < l; i++) gel(V,i) = F2xqX_ddf_i(gel(V,i), T, X, xp);
    1890          42 :   return vddf_to_simplefact(V, degpol(S));
    1891             : }
    1892             : GEN
    1893           0 : F2xqX_ddf(GEN S, GEN T)
    1894             : {
    1895             :   GEN xp, X;
    1896           0 :   F2xqX_ddf_init(&S,&T,&xp,&X);
    1897           0 :   return ddf_to_ddf2( F2xqX_ddf_i(S, T, X, xp) );
    1898             : }
    1899             : 
    1900             : static void
    1901         168 : F2xqX_edf_simple(GEN Sp, GEN xp, GEN Xp, GEN Sq, long d, GEN T, GEN V, long idx)
    1902             : {
    1903         168 :   long v = varn(Sp), n = degpol(Sp), r = n/d;
    1904             :   GEN S, f, ff;
    1905         168 :   long dT = get_F2x_degree(T);
    1906         168 :   if (r==1) { gel(V, idx) = Sp; return; }
    1907          63 :   S = F2xqX_get_red(Sp, T);
    1908          63 :   Xp = F2xqX_rem(Xp, S, T);
    1909          63 :   Sq = F2xqXQV_red(Sq, S, T);
    1910             :   while (1)
    1911          39 :   {
    1912         102 :     pari_sp btop = avma;
    1913             :     long l;
    1914         102 :     GEN w0 = random_F2xqX(n, v, T), g = w0;
    1915         123 :     for (l=1; l<d; l++) /* sum_{0<i<d} w^(q^i), result in (F_q)^r */
    1916          21 :       g = F2xX_add(w0, F2xqX_F2xqXQV_eval(g, Sq, S, T));
    1917         102 :     w0 = g;
    1918         598 :     for (l=1; l<dT; l++) /* sum_{0<i<k} w^(2^i), result in (F_2)^r */
    1919         496 :       g = F2xX_add(w0, F2xqXQ_sqr(g,S,T));
    1920         102 :     f = F2xqX_gcd(g, Sp, T);
    1921         102 :     if (degpol(f) > 0 && degpol(f) < n) break;
    1922          39 :     set_avma(btop);
    1923             :   }
    1924          63 :   f = F2xqX_normalize(f, T);
    1925          63 :   ff = F2xqX_div(Sp, f , T);
    1926          63 :   F2xqX_edf_simple(f, xp, Xp, Sq, d, T, V, idx);
    1927          63 :   F2xqX_edf_simple(ff, xp, Xp, Sq, d, T, V, idx+degpol(f)/d);
    1928             : }
    1929             : 
    1930             : static GEN
    1931         308 : F2xqX_factor_Shoup(GEN S, GEN xp, GEN T)
    1932             : {
    1933         308 :   long i, n, s = 0;
    1934             :   GEN X, Xp, Xq, Sq, D, V;
    1935         308 :   long vT = get_F2x_var(T);
    1936             :   pari_timer ti;
    1937         308 :   n = get_F2xqX_degree(S);
    1938         308 :   S = F2xqX_get_red(S, T);
    1939         308 :   if (DEBUGLEVEL>=6) timer_start(&ti);
    1940         308 :   X  = polx_F2xX(get_F2xqX_var(S), vT);
    1941         308 :   Xp = F2xqXQ_sqr(X, S, T);
    1942         308 :   Xq = F2xqXQ_Frobenius(xp, Xp, S, T);
    1943         308 :   Sq = F2xqXQ_powers(Xq, n-1, S, T);
    1944         308 :   if (DEBUGLEVEL>=6) timer_printf(&ti,"F2xqX_Frobenius");
    1945         308 :   D = F2xqX_ddf_Shoup(S, Xq, T);
    1946         308 :   if (DEBUGLEVEL>=6) timer_printf(&ti,"F2xqX_ddf_Shoup");
    1947         308 :   s = ddf_to_nbfact(D);
    1948         308 :   V = cgetg(s+1, t_COL);
    1949         875 :   for (i = 1, s = 1; i <= n; i++)
    1950             :   {
    1951         567 :     GEN Di = gel(D,i);
    1952         567 :     long ni = degpol(Di), ri = ni/i;
    1953         567 :     if (ni == 0) continue;
    1954         364 :     Di = F2xqX_normalize(Di, T);
    1955         364 :     if (ni == i) { gel(V, s++) = Di; continue; }
    1956          42 :     F2xqX_edf_simple(Di, xp, Xp, Sq, i, T, V, s);
    1957          42 :     if (DEBUGLEVEL>=6) timer_printf(&ti,"F2xqX_edf(%ld)",i);
    1958          42 :     s += ri;
    1959             :   }
    1960         308 :   return V;
    1961             : }
    1962             : 
    1963             : static GEN
    1964        1407 : F2xqX_factor_Cantor(GEN f, GEN T)
    1965             : {
    1966             :   GEN xp, E, F, V;
    1967             :   long i, j, l;
    1968        1407 :   T = F2x_get_red(T);
    1969        1407 :   f = F2xqX_normalize(f, T);
    1970        1407 :   switch(degpol(f))
    1971             :   {
    1972          14 :     case -1: retmkmat2(mkcol(f), mkvecsmall(1));
    1973          14 :     case 0: return trivial_fact();
    1974          21 :     case 1: retmkmat2(mkcol(f), mkvecsmall(1));
    1975         588 :     case 2: return F2xqX_factor_2(f, T);
    1976             :   }
    1977         770 :   if (F2xY_degreex(f) <= 0) return F2x_factorff_i(F2xX_to_F2x(f), T);
    1978         266 :   xp = F2x_Frobenius(T);
    1979         266 :   V = F2xqX_factor_squarefree(f, T);
    1980         266 :   l = lg(V);
    1981         266 :   F = cgetg(l, t_VEC);
    1982         266 :   E = cgetg(l, t_VEC);
    1983         896 :   for (i=1, j=1; i < l; i++)
    1984         630 :     if (degpol(gel(V,i)))
    1985             :     {
    1986         308 :       GEN Fj = F2xqX_factor_Shoup(gel(V,i), xp, T);
    1987         308 :       gel(F, j) = Fj;
    1988         308 :       gel(E, j) = const_vecsmall(lg(Fj)-1, i);
    1989         308 :       j++;
    1990             :     }
    1991         266 :   return sort_factor_pol(FE_concat(F,E,j), cmp_Flx);
    1992             : }
    1993             : 
    1994             : static GEN
    1995           0 : FlxqX_Berlekamp_i(GEN f, GEN T, ulong p)
    1996             : {
    1997           0 :   long lfact, d = degpol(f), j, k, lV;
    1998             :   GEN E, t, V, xp;
    1999             :   ulong pi;
    2000           0 :   switch(d)
    2001             :   {
    2002           0 :     case -1: retmkmat2(mkcolcopy(f), mkvecsmall(1));
    2003           0 :     case 0: return trivial_fact();
    2004             :   }
    2005           0 :   pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
    2006           0 :   T = Flx_get_red_pre(T, p, pi);
    2007           0 :   f = FlxqX_normalize_pre(f, T, p, pi);
    2008           0 :   if (FlxY_degreex(f) <= 0) return Flx_factorff_i(FlxX_to_Flx(f), T, p);
    2009           0 :   if (degpol(f)==2) return FlxqX_factor_2(f, T, p, pi);
    2010           0 :   xp = Flx_Frobenius_pre(T, p, pi);
    2011           0 :   V = FlxqX_factor_squarefree_i(f, xp, T, p, pi); lV = lg(V);
    2012             : 
    2013             :   /* to hold factors and exponents */
    2014           0 :   t = cgetg(d+1,t_VEC);
    2015           0 :   E = cgetg(d+1, t_VECSMALL);
    2016           0 :   lfact = 1;
    2017           0 :   for (k=1; k<lV ; k++)
    2018             :   {
    2019           0 :     if (degpol(gel(V,k))==0) continue;
    2020           0 :     gel(t,lfact) = FlxqX_normalize_pre(gel(V, k), T,p, pi);
    2021           0 :     d = FlxqX_split_Berlekamp(&gel(t,lfact), xp, T, p, pi);
    2022           0 :     for (j = 0; j < d; j++) E[lfact+j] = k;
    2023           0 :     lfact += d;
    2024             :   }
    2025           0 :   setlg(t, lfact);
    2026           0 :   setlg(E, lfact);
    2027           0 :   return sort_factor_pol(mkvec2(t, E), cmp_Flx);
    2028             : }
    2029             : 
    2030             : static GEN
    2031           0 : FpXQX_Berlekamp_i(GEN f, GEN T, GEN p)
    2032             : {
    2033           0 :   long lfact, d = degpol(f), j, k, lV;
    2034             :   GEN E, t, V;
    2035           0 :   switch(d)
    2036             :   {
    2037           0 :     case -1: retmkmat2(mkcolcopy(f), mkvecsmall(1));
    2038           0 :     case 0: return trivial_fact();
    2039             :   }
    2040           0 :   T = FpX_get_red(T, p);
    2041           0 :   f = FpXQX_normalize(f, T, p);
    2042           0 :   if (isabsolutepol(f)) return FpX_factorff_i(simplify_shallow(f), T, p);
    2043           0 :   if (degpol(f)==2) return FpXQX_factor_2(f, T, p);
    2044           0 :   V = FpXQX_factor_Yun(f, T, p); lV = lg(V);
    2045             : 
    2046             :   /* to hold factors and exponents */
    2047           0 :   t = cgetg(d+1,t_VEC);
    2048           0 :   E = cgetg(d+1, t_VECSMALL);
    2049           0 :   lfact = 1;
    2050           0 :   for (k=1; k<lV ; k++)
    2051             :   {
    2052           0 :     if (degpol(gel(V,k))==0) continue;
    2053           0 :     gel(t,lfact) = FpXQX_normalize(gel(V, k), T,p);
    2054           0 :     d = FpXQX_split_Berlekamp(&gel(t,lfact), T, p);
    2055           0 :     for (j = 0; j < d; j++) E[lfact+j] = k;
    2056           0 :     lfact += d;
    2057             :   }
    2058           0 :   setlg(t, lfact);
    2059           0 :   setlg(E, lfact);
    2060           0 :   return sort_factor_pol(mkvec2(t, E), cmp_RgX);
    2061             : }
    2062             : 
    2063             : long
    2064         268 : FlxqX_ddf_degree(GEN S, GEN XP, GEN T, ulong p)
    2065             : {
    2066         268 :   pari_sp av = avma;
    2067             :   GEN X, b, g, xq, q;
    2068             :   long i, j, n, v, B, l, m, bo, ro;
    2069             :   ulong pi;
    2070             :   pari_timer ti;
    2071             :   hashtable h;
    2072             : 
    2073         268 :   n = get_FlxqX_degree(S); v = get_FlxqX_var(S);
    2074         268 :   X = polx_FlxX(v,get_Flx_var(T));
    2075         268 :   if (gequal(X,XP)) return 1;
    2076         268 :   pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
    2077         268 :   B = n/2;
    2078         268 :   l = usqrt(B);
    2079         268 :   m = (B+l-1)/l;
    2080         268 :   T = Flx_get_red_pre(T, p, pi);
    2081         268 :   S = FlxqX_get_red_pre(S, T, p, pi);
    2082         268 :   hash_init_GEN(&h, l+2, gequal, 1);
    2083         268 :   hash_insert_long(&h, X,  0);
    2084         268 :   hash_insert_long(&h, XP, 1);
    2085         268 :   bo = brent_kung_optpow(n, l-1, 1);
    2086         268 :   ro = l<=1 ? 0: (bo-1)/(l-1) + ((n-1)/bo);
    2087         268 :   q = powuu(p, get_Flx_degree(T));
    2088         268 :   if (DEBUGLEVEL>=7) timer_start(&ti);
    2089         268 :   b = XP;
    2090         268 :   if (expi(q) > ro)
    2091             :   {
    2092         268 :     xq = FlxqXQ_powers_pre(b, brent_kung_optpow(n, l-1, 1),  S, T, p, pi);
    2093         268 :     if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_degree: xq baby");
    2094           0 :   } else xq = NULL;
    2095         635 :   for (i = 3; i <= l+1; i++)
    2096             :   {
    2097         401 :     b = xq ? FlxqX_FlxqXQV_eval_pre(b, xq, S, T, p, pi)
    2098         401 :            : FlxqXQ_pow_pre(b, q, S, T, p, pi);
    2099         401 :     if (gequal(b,X)) return gc_long(av,i-1);
    2100         367 :     hash_insert_long(&h, b, i-1);
    2101             :   }
    2102         234 :   if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_degree: baby");
    2103         234 :   g = b;
    2104         234 :   xq = FlxqXQ_powers_pre(g, brent_kung_optpow(n, m, 1),  S, T, p, pi);
    2105         234 :   if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_degree: xq giant");
    2106         651 :   for(i = 2; i <= m+1; i++)
    2107             :   {
    2108         562 :     g = FlxqX_FlxqXQV_eval_pre(g, xq, S, T, p, pi);
    2109         562 :     if (hash_haskey_long(&h, g, &j)) return gc_long(av, l*i-j);
    2110             :   }
    2111          89 :   return gc_long(av,n);
    2112             : }
    2113             : 
    2114             : static GEN
    2115         545 : FlxqX_ddf_Shoup(GEN S, GEN Xq, GEN T, ulong p, ulong pi)
    2116             : {
    2117         545 :   pari_sp av = avma;
    2118             :   GEN b, g, h, F, f, Sr, xq, q;
    2119             :   long i, j, n, v, vT, bo, ro;
    2120             :   long B, l, m;
    2121             :   pari_timer ti;
    2122         545 :   n = get_FlxqX_degree(S); v = get_FlxqX_var(S);
    2123         545 :   vT = get_Flx_var(T);
    2124         545 :   if (n == 0) return cgetg(1, t_VEC);
    2125         545 :   if (n == 1) return mkvec(get_FlxqX_mod(S));
    2126         384 :   B = n/2;
    2127         384 :   l = usqrt(B);
    2128         384 :   m = (B+l-1)/l;
    2129         384 :   S = FlxqX_get_red_pre(S, T, p, pi);
    2130         384 :   b = cgetg(l+2, t_VEC);
    2131         384 :   gel(b, 1) = polx_FlxX(v, vT);
    2132         384 :   gel(b, 2) = Xq;
    2133         384 :   bo = brent_kung_optpow(n, l-1, 1);
    2134         384 :   ro = l<=1 ? 0: (bo-1)/(l-1) + ((n-1)/bo);
    2135         384 :   q = powuu(p, get_Flx_degree(T));
    2136         384 :   if (DEBUGLEVEL>=7) timer_start(&ti);
    2137         384 :   if (expi(q) <= ro)
    2138          21 :     for (i = 3; i <= l+1; i++)
    2139          14 :       gel(b, i) = FlxqXQ_pow_pre(gel(b, i-1), q, S, T, p, pi);
    2140             :   else
    2141             :   {
    2142         377 :     xq = FlxqXQ_powers_pre(gel(b, 2), bo, S, T, p, pi);
    2143         377 :     if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: xq baby");
    2144         377 :     for (i = 3; i <= l+1; i++)
    2145           0 :       gel(b, i) = FlxqX_FlxqXQV_eval_pre(gel(b, i-1), xq, S, T, p, pi);
    2146             :   }
    2147         384 :   if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: baby");
    2148         384 :   xq = FlxqXQ_powers_pre(gel(b, l+1), brent_kung_optpow(n, m-1, 1), S, T,p,pi);
    2149         384 :   if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: xq giant");
    2150         384 :   g = cgetg(m+1, t_VEC);
    2151         384 :   gel(g, 1) = gel(xq, 2);
    2152         753 :   for(i = 2; i <= m; i++)
    2153         369 :     gel(g, i) = FlxqX_FlxqXQV_eval_pre(gel(g, i-1), xq, S, T, p, pi);
    2154         384 :   if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: giant");
    2155         384 :   h = cgetg(m+1, t_VEC);
    2156        1137 :   for (j = 1; j <= m; j++)
    2157             :   {
    2158         753 :     pari_sp av = avma;
    2159         753 :     GEN gj = gel(g, j);
    2160         753 :     GEN e = FlxX_sub(gj, gel(b, 1), p);
    2161         823 :     for (i = 2; i <= l; i++)
    2162          70 :       e = FlxqXQ_mul_pre(e, FlxX_sub(gj, gel(b, i), p), S, T, p, pi);
    2163         753 :     gel(h, j) = gerepileupto(av, e);
    2164             :   }
    2165         384 :   if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: diff");
    2166         384 :   Sr = get_FlxqX_mod(S);
    2167         384 :   F = cgetg(m+1, t_VEC);
    2168        1137 :   for (j = 1; j <= m; j++)
    2169             :   {
    2170         753 :     GEN u = FlxqX_gcd_pre(Sr, gel(h, j), T, p, pi);
    2171         753 :     if (degpol(u))
    2172             :     {
    2173         307 :       u = FlxqX_normalize_pre(u, T, p, pi);
    2174         307 :       Sr = FlxqX_div_pre(Sr, u, T, p, pi);
    2175             :     }
    2176         753 :     gel(F,j) = u;
    2177             :   }
    2178         384 :   if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: F");
    2179         384 :   f = const_vec(n, pol1_FlxX(v, vT));
    2180        1137 :   for (j = 1; j <= m; j++)
    2181             :   {
    2182         753 :     GEN e = gel(F, j);
    2183         753 :     for (i=l-1; i >= 0; i--)
    2184             :     {
    2185         753 :       GEN u = FlxqX_gcd_pre(e, FlxX_sub(gel(g, j), gel(b, i+1), p), T, p, pi);
    2186         753 :       if (degpol(u))
    2187             :       {
    2188         307 :         gel(f, l*j-i) = u = FlxqX_normalize_pre(u, T, p, pi);
    2189         307 :         e = FlxqX_div_pre(e, u, T, p, pi);
    2190             :       }
    2191         753 :       if (!degpol(e)) break;
    2192             :     }
    2193             :   }
    2194         384 :   if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: f");
    2195         384 :   if (degpol(Sr)) gel(f, degpol(Sr)) = Sr;
    2196         384 :   return gerepilecopy(av, f);
    2197             : }
    2198             : 
    2199             : static GEN
    2200          42 : FlxqX_ddf_i(GEN f, GEN T, ulong p, ulong pi)
    2201             : {
    2202             :   GEN Xq;
    2203          42 :   if (!get_FlxqX_degree(f)) return cgetg(1, t_VEC);
    2204          42 :   f = FlxqX_get_red_pre(f, T, p, pi);
    2205          42 :   Xq = FlxqX_Frobenius_pre(f, T, p, pi);
    2206          42 :   return FlxqX_ddf_Shoup(f, Xq, T, p, pi);
    2207             : }
    2208             : GEN
    2209           0 : FlxqX_ddf(GEN S, GEN T, ulong p)
    2210             : {
    2211           0 :   ulong pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
    2212           0 :   T = Flx_get_red_pre(T, p, pi);
    2213           0 :   S = FlxqX_normalize_pre(get_FlxqX_mod(S), T, p, pi);
    2214           0 :   return ddf_to_ddf2( FlxqX_ddf_i(S, T, p, pi) );
    2215             : }
    2216             : GEN
    2217          42 : FlxqX_degfact(GEN S, GEN T, ulong p)
    2218             : {
    2219          42 :   ulong pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
    2220             :   GEN V;
    2221             :   long i, l;
    2222          42 :   T = Flx_get_red_pre(T, p, pi);
    2223          42 :   S = FlxqX_normalize_pre(get_FlxqX_mod(S), T, p, pi);
    2224          42 :   V = FlxqX_factor_squarefree_pre(S, T, p, pi); l = lg(V);
    2225          84 :   for (i=1; i < l; i++) gel(V,i) = FlxqX_ddf_i(gel(V,i), T, p, pi);
    2226          42 :   return vddf_to_simplefact(V, degpol(S));
    2227             : }
    2228             : 
    2229             : static void
    2230         362 : FlxqX_edf_rec(GEN S, GEN xp, GEN Xp, GEN hp, GEN t, long d, GEN T, ulong p,
    2231             :   ulong pi, GEN V, long idx)
    2232             : {
    2233         362 :   GEN Sp = get_FlxqX_mod(S);
    2234             :   GEN u1, u2, f1, f2;
    2235             :   GEN h;
    2236         362 :   h = FlxqX_get_red_pre(hp, T, p, pi);
    2237         362 :   t = FlxqX_rem_pre(t, S, T, p, pi);
    2238         362 :   Xp = FlxqX_rem_pre(Xp, h, T, p, pi);
    2239         362 :   u1 = FlxqX_roots_split(hp, xp, Xp, h, T, p, pi);
    2240         362 :   f1 = FlxqX_gcd_pre(FlxqX_FlxqXQ_eval_pre(u1, t, S, T, p, pi), Sp, T, p, pi);
    2241         362 :   f1 = FlxqX_normalize_pre(f1, T, p, pi);
    2242         362 :   u2 = FlxqX_div_pre(hp, u1, T, p, pi);
    2243         362 :   f2 = FlxqX_div_pre(Sp, f1, T, p, pi);
    2244         362 :   if (degpol(u1)==1)
    2245         257 :     gel(V, idx) = f1;
    2246             :   else
    2247         105 :     FlxqX_edf_rec(FlxqX_get_red_pre(f1, T, p, pi),
    2248             :                   xp, Xp, u1, t, d, T, p, pi, V, idx);
    2249         362 :   idx += degpol(f1)/d;
    2250         362 :   if (degpol(u2)==1)
    2251         251 :     gel(V, idx) = f2;
    2252             :   else
    2253         111 :     FlxqX_edf_rec(FlxqX_get_red_pre(f2, T, p, pi),
    2254             :                   xp, Xp, u2, t, d, T, p, pi, V, idx);
    2255         362 : }
    2256             : 
    2257             : static void
    2258         146 : FlxqX_edf(GEN Sp, GEN xp, GEN Xp, GEN Xq, long d, GEN T, ulong p, ulong pi,
    2259             :   GEN V, long idx)
    2260             : {
    2261         146 :   long n = degpol(Sp), r = n/d, vS = varn(Sp), vT = get_Flx_var(T);
    2262             :   GEN S, h, t;
    2263             :   pari_timer ti;
    2264         146 :   if (r==1) { gel(V, idx) = Sp; return; }
    2265         146 :   S = FlxqX_get_red_pre(Sp, T, p, pi);
    2266         146 :   Xp = FlxqX_rem_pre(Xp, S, T, p, pi);
    2267         146 :   Xq = FlxqX_rem_pre(Xq, S, T, p, pi);
    2268         146 :   if (DEBUGLEVEL>=7) timer_start(&ti);
    2269             :   do
    2270             :   {
    2271         188 :     GEN g = random_FlxqX(n, vS, T, p);
    2272         188 :     t = gel(FlxqXQ_auttrace_pre(mkvec2(Xq, g), d, S, T, p, pi), 2);
    2273         188 :     if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_edf: FlxqXQ_auttrace");
    2274         188 :     h = FlxqXQ_minpoly_pre(t, S, T, p, pi);
    2275         188 :     if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_edf: FlxqXQ_minpoly");
    2276         188 :   } while (degpol(h) != r);
    2277         146 :   Xp = FlxqXQ_powu_pre(polx_FlxX(vS, vT), p, h, T, p, pi);
    2278         146 :   FlxqX_edf_rec(S, xp, Xp, h, t, d, T, p, pi, V, idx);
    2279             : }
    2280             : 
    2281             : static void
    2282         357 : FlxqX_edf_simple(GEN Sp, GEN xp, GEN Xp, GEN Xq, long d, GEN T, ulong p,
    2283             :   ulong pi, GEN V, long idx)
    2284             : {
    2285         357 :   long v = varn(Sp), n = degpol(Sp), r = n/d;
    2286             :   GEN S, f, ff;
    2287         357 :   long vT = get_Flx_var(T), dT = get_Flx_degree(T);
    2288         357 :   if (r==1) { gel(V, idx) = Sp; return; }
    2289         175 :   S = FlxqX_get_red_pre(Sp, T, p, pi);
    2290         175 :   Xp = FlxqX_rem_pre(Xp, S, T, p, pi);
    2291         175 :   Xq = FlxqX_rem_pre(Xq, S, T, p, pi);
    2292             :   while (1)
    2293           0 :   {
    2294         175 :     pari_sp btop = avma;
    2295             :     long i;
    2296         175 :     GEN g = random_FlxqX(n, v, T, p);
    2297         175 :     GEN t = gel(FlxqXQ_auttrace_pre(mkvec2(Xq, g), d, S, T, p, pi), 2);
    2298         175 :     if (lgpol(t) == 0) continue;
    2299         245 :     for(i=1; i<=10; i++)
    2300             :     {
    2301         245 :       pari_sp btop2 = avma;
    2302         245 :       GEN r = random_Flx(dT, vT, p);
    2303         245 :       GEN R = FlxqXQ_halfFrobenius_i(FlxX_Flx_add(t, r, p), xp, Xp, S, T, p, pi);
    2304         245 :       f = FlxqX_gcd_pre(FlxX_Flx_sub(R, pol1_Flx(vT), p), Sp, T, p, pi);
    2305         245 :       if (degpol(f) > 0 && degpol(f) < n) break;
    2306          70 :       set_avma(btop2);
    2307             :     }
    2308         175 :     if (degpol(f) > 0 && degpol(f) < n) break;
    2309           0 :     set_avma(btop);
    2310             :   }
    2311         175 :   f = FlxqX_normalize_pre(f, T, p, pi);
    2312         175 :   ff = FlxqX_div_pre(Sp, f , T, p, pi);
    2313         175 :   FlxqX_edf_simple(f, xp, Xp, Xq, d, T, p, pi, V, idx);
    2314         175 :   FlxqX_edf_simple(ff, xp, Xp, Xq, d, T, p, pi, V, idx+degpol(f)/d);
    2315             : }
    2316             : 
    2317             : static GEN
    2318         356 : FlxqX_factor_Shoup(GEN S, GEN xp, GEN T, ulong p, ulong pi)
    2319             : {
    2320         356 :   long i, n, s = 0;
    2321             :   GEN X, Xp, Xq, D, V;
    2322         356 :   long dT = get_Flx_degree(T), vT = get_Flx_var(T);
    2323         356 :   long e = expi(powuu(p, dT));
    2324             :   pari_timer ti;
    2325         356 :   n = get_FlxqX_degree(S);
    2326         356 :   S = FlxqX_get_red_pre(S, T, p, pi);
    2327         356 :   if (DEBUGLEVEL>=6) timer_start(&ti);
    2328         356 :   X  = polx_FlxX(get_FlxqX_var(S), vT);
    2329         356 :   Xp = FlxqXQ_powu_pre(X, p, S, T, p, pi);
    2330         356 :   Xq = FlxqXQ_Frobenius(xp, Xp, S, T, p, pi);
    2331         356 :   if (DEBUGLEVEL>=6) timer_printf(&ti,"FlxqX_Frobenius");
    2332         356 :   D = FlxqX_ddf_Shoup(S, Xq, T, p, pi);
    2333         356 :   if (DEBUGLEVEL>=6) timer_printf(&ti,"FlxqX_ddf_Shoup");
    2334         356 :   s = ddf_to_nbfact(D);
    2335         356 :   V = cgetg(s+1, t_COL);
    2336        1428 :   for (i = 1, s = 1; i <= n; i++)
    2337             :   {
    2338        1072 :     GEN Di = gel(D,i);
    2339        1072 :     long ni = degpol(Di), ri = ni/i;
    2340        1072 :     if (ni == 0) continue;
    2341         391 :     Di = FlxqX_normalize_pre(Di, T, p, pi);
    2342         391 :     if (ni == i) { gel(V, s++) = Di; continue; }
    2343         153 :     if (ri <= e*expu(e))
    2344         146 :       FlxqX_edf(Di, xp, Xp, Xq, i, T, p, pi, V, s);
    2345             :     else
    2346           7 :       FlxqX_edf_simple(Di, xp, Xp, Xq, i, T, p, pi, V, s);
    2347         153 :     if (DEBUGLEVEL>=6) timer_printf(&ti,"FlxqX_edf(%ld)",i);
    2348         153 :     s += ri;
    2349             :   }
    2350         356 :   return V;
    2351             : }
    2352             : 
    2353             : static GEN
    2354       12745 : FlxqX_factor_Cantor(GEN f, GEN T, ulong p)
    2355             : {
    2356       12745 :   ulong pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
    2357             :   GEN xp, E, F, V;
    2358             :   long i, j, l;
    2359       12745 :   T = Flx_get_red_pre(T, p, pi);
    2360       12745 :   f = FlxqX_normalize_pre(f, T, p, pi);
    2361       12745 :   switch(degpol(f))
    2362             :   {
    2363          21 :     case -1: retmkmat2(mkcol(f), mkvecsmall(1));
    2364          21 :     case 0: return trivial_fact();
    2365          21 :     case 1: retmkmat2(mkcol(f), mkvecsmall(1));
    2366         832 :     case 2: return FlxqX_factor_2(f, T, p, pi);
    2367             :   }
    2368       11850 :   if (FlxY_degreex(f) <= 0) return Flx_factorff_i(FlxX_to_Flx(f), T, p);
    2369         307 :   xp = Flx_Frobenius_pre(T, p, pi);
    2370         307 :   V = FlxqX_factor_squarefree_i(f, xp, get_Flx_mod(T), p, pi);
    2371         307 :   l = lg(V);
    2372         307 :   F = cgetg(l, t_VEC);
    2373         307 :   E = cgetg(l, t_VEC);
    2374        1097 :   for (i=1, j=1; i < l; i++)
    2375         790 :     if (degpol(gel(V,i)))
    2376             :     {
    2377         356 :       GEN Fj = FlxqX_factor_Shoup(gel(V,i), xp, T, p, pi);
    2378         356 :       gel(F, j) = Fj;
    2379         356 :       gel(E, j) = const_vecsmall(lg(Fj)-1, i);
    2380         356 :       j++;
    2381             :     }
    2382         307 :   return sort_factor_pol(FE_concat(F,E,j), cmp_Flx);
    2383             : }
    2384             : 
    2385             : /* T must be squarefree mod p*/
    2386             : GEN
    2387         147 : FlxqX_nbfact_by_degree(GEN f, long *nb, GEN T, ulong p)
    2388             : {
    2389             :   GEN Xq, D;
    2390             :   pari_timer ti;
    2391         147 :   long i, s, n = get_FlxqX_degree(f);
    2392         147 :   ulong pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
    2393         147 :   GEN V = const_vecsmall(n, 0);
    2394         147 :   pari_sp av = avma;
    2395         147 :   T = Flx_get_red_pre(T, p, pi);
    2396         147 :   f = FlxqX_get_red_pre(f, T, p, pi);
    2397         147 :   if (DEBUGLEVEL>=6) timer_start(&ti);
    2398         147 :   Xq = FlxqX_Frobenius_pre(f, T, p, pi);
    2399         147 :   if (DEBUGLEVEL>=6) timer_printf(&ti,"FlxqX_Frobenius");
    2400         147 :   D = FlxqX_ddf_Shoup(f, Xq, T, p, pi);
    2401         147 :   if (DEBUGLEVEL>=6) timer_printf(&ti,"FlxqX_ddf_Shoup");
    2402         945 :   for (i = 1, s = 0; i <= n; i++) { V[i] = degpol(gel(D,i))/i; s += V[i]; }
    2403         147 :   *nb = s; set_avma(av); return V;
    2404             : }
    2405             : 
    2406             : long
    2407           0 : FlxqX_nbfact_Frobenius(GEN S, GEN Xq, GEN T, ulong p)
    2408             : {
    2409           0 :   pari_sp av = avma;
    2410           0 :   GEN u = get_FlxqX_mod(S);
    2411             :   long s;
    2412           0 :   if (FlxY_degreex(u) <= 0)
    2413           0 :     s = Flx_nbfactff(FlxX_to_Flx(u), T, p);
    2414             :   else
    2415           0 :     s = ddf_to_nbfact(FlxqX_ddf_Shoup(S, Xq, T, p,
    2416           0 :                                       SMALL_ULONG(p)? 0: get_Fl_red(p)));
    2417           0 :   return gc_long(av,s);
    2418             : }
    2419             : 
    2420             : long
    2421        7084 : FlxqX_nbfact(GEN S, GEN T, ulong p)
    2422             : {
    2423        7084 :   pari_sp av = avma;
    2424        7084 :   GEN u = get_FlxqX_mod(S);
    2425             :   long s;
    2426        7084 :   if (FlxY_degreex(u) <= 0)
    2427        7084 :     s = Flx_nbfactff(FlxX_to_Flx(u), T, p);
    2428             :   else
    2429           0 :     s = ddf_to_nbfact(FlxqX_ddf_Shoup(S, FlxqX_Frobenius(S, T, p), T, p,
    2430           0 :                                       SMALL_ULONG(p)? 0: get_Fl_red(p)));
    2431        7084 :   return gc_long(av,s);
    2432             : }
    2433             : 
    2434             : GEN
    2435         187 : FlxqX_factor(GEN x, GEN T, ulong p)
    2436             : {
    2437         187 :   pari_sp av = avma;
    2438         187 :   return gerepilecopy(av, FlxqX_factor_Cantor(x, T, p));
    2439             : }
    2440             : 
    2441             : GEN
    2442         133 : F2xqX_factor(GEN x, GEN T)
    2443             : {
    2444         133 :   pari_sp av = avma;
    2445         133 :   return gerepilecopy(av, F2xqX_factor_Cantor(x, T));
    2446             : }
    2447             : 
    2448             : long
    2449         187 : FpXQX_ddf_degree(GEN S, GEN XP, GEN T, GEN p)
    2450             : {
    2451         187 :   pari_sp av = avma;
    2452             :   GEN X, b, g, xq, q;
    2453             :   long i, j, n, v, B, l, m, bo, ro;
    2454             :   pari_timer ti;
    2455             :   hashtable h;
    2456             : 
    2457         187 :   n = get_FpXQX_degree(S); v = get_FpXQX_var(S);
    2458         187 :   X = pol_x(v);
    2459         187 :   if (gequal(X,XP)) return 1;
    2460         187 :   B = n/2;
    2461         187 :   l = usqrt(B);
    2462         187 :   m = (B+l-1)/l;
    2463         187 :   T = FpX_get_red(T, p);
    2464         187 :   S = FpXQX_get_red(S, T, p);
    2465         187 :   hash_init_GEN(&h, l+2, gequal, 1);
    2466         187 :   hash_insert_long(&h, X,  0);
    2467         187 :   hash_insert_long(&h, simplify_shallow(XP), 1);
    2468         187 :   bo = brent_kung_optpow(n, l-1, 1);
    2469         187 :   ro = l<=1 ? 0: (bo-1)/(l-1) + ((n-1)/bo);
    2470         187 :   q = powiu(p, get_FpX_degree(T));
    2471         187 :   if (DEBUGLEVEL>=7) timer_start(&ti);
    2472         187 :   b = XP;
    2473         187 :   if (expi(q) > ro)
    2474             :   {
    2475         187 :     xq = FpXQXQ_powers(b, brent_kung_optpow(n, l-1, 1),  S, T, p);
    2476         187 :     if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_degree: xq baby");
    2477           0 :   } else xq = NULL;
    2478         695 :   for (i = 3; i <= l+1; i++)
    2479             :   {
    2480         523 :     b = xq ? FpXQX_FpXQXQV_eval(b, xq, S, T, p)
    2481         523 :            : FpXQXQ_pow(b, q, S, T, p);
    2482         523 :     if (gequal(b,X)) return gc_long(av,i-1);
    2483         508 :     hash_insert_long(&h, simplify_shallow(b), i-1);
    2484             :   }
    2485         172 :   if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_degree: baby");
    2486         172 :   g = b;
    2487         172 :   xq = FpXQXQ_powers(g, brent_kung_optpow(n, m, 1),  S, T, p);
    2488         172 :   if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_degree: xq giant");
    2489         756 :   for(i = 2; i <= m+1; i++)
    2490             :   {
    2491         691 :     g = FpXQX_FpXQXQV_eval(g, xq, S, T, p);
    2492         691 :     if (hash_haskey_long(&h, simplify_shallow(g), &j)) return gc_long(av,l*i-j);
    2493             :   }
    2494          65 :   return gc_long(av,n);
    2495             : }
    2496             : 
    2497             : static GEN
    2498          71 : FpXQX_ddf_Shoup(GEN S, GEN Xq, GEN T, GEN p)
    2499             : {
    2500          71 :   pari_sp av = avma;
    2501             :   GEN b, g, h, F, f, Sr, xq, q;
    2502             :   long i, j, n, v, bo, ro;
    2503             :   long B, l, m;
    2504             :   pari_timer ti;
    2505          71 :   n = get_FpXQX_degree(S); v = get_FpXQX_var(S);
    2506          71 :   if (n == 0) return cgetg(1, t_VEC);
    2507          71 :   if (n == 1) return mkvec(get_FpXQX_mod(S));
    2508          64 :   B = n/2;
    2509          64 :   l = usqrt(B);
    2510          64 :   m = (B+l-1)/l;
    2511          64 :   S = FpXQX_get_red(S, T, p);
    2512          64 :   b = cgetg(l+2, t_VEC);
    2513          64 :   gel(b, 1) = pol_x(v);
    2514          64 :   gel(b, 2) = Xq;
    2515          64 :   bo = brent_kung_optpow(n, l-1, 1);
    2516          64 :   ro = l<=1 ? 0: (bo-1)/(l-1) + ((n-1)/bo);
    2517          64 :   q = powiu(p, get_FpX_degree(T));
    2518          64 :   if (DEBUGLEVEL>=7) timer_start(&ti);
    2519          64 :   if (expi(q) <= ro)
    2520           0 :     for (i = 3; i <= l+1; i++)
    2521           0 :       gel(b, i) = FpXQXQ_pow(gel(b, i-1), q, S, T, p);
    2522             :   else
    2523             :   {
    2524          64 :     xq = FpXQXQ_powers(gel(b, 2), bo, S, T, p);
    2525          64 :     if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: xq baby");
    2526          85 :     for (i = 3; i <= l+1; i++)
    2527          21 :       gel(b, i) = FpXQX_FpXQXQV_eval(gel(b, i-1), xq, S, T, p);
    2528             :   }
    2529          64 :   if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: baby");
    2530          64 :   xq = FpXQXQ_powers(gel(b, l+1), brent_kung_optpow(n, m-1, 1), S, T, p);
    2531          64 :   if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: xq giant");
    2532          64 :   g = cgetg(m+1, t_VEC);
    2533          64 :   gel(g, 1) = gel(xq, 2);
    2534         108 :   for(i = 2; i <= m; i++)
    2535          44 :     gel(g, i) = FpXQX_FpXQXQV_eval(gel(g, i-1), xq, S, T, p);
    2536          64 :   if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: giant");
    2537          64 :   h = cgetg(m+1, t_VEC);
    2538         172 :   for (j = 1; j <= m; j++)
    2539             :   {
    2540         108 :     pari_sp av = avma;
    2541         108 :     GEN gj = gel(g, j);
    2542         108 :     GEN e = FpXX_sub(gj, gel(b, 1), p);
    2543         171 :     for (i = 2; i <= l; i++)
    2544          63 :       e = FpXQXQ_mul(e, FpXX_sub(gj, gel(b, i), p), S, T, p);
    2545         108 :     gel(h, j) = gerepileupto(av, e);
    2546             :   }
    2547          64 :   if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: diff");
    2548          64 :   Sr = get_FpXQX_mod(S);
    2549          64 :   F = cgetg(m+1, t_VEC);
    2550         172 :   for (j = 1; j <= m; j++)
    2551             :   {
    2552         108 :     GEN u = FpXQX_gcd(Sr, gel(h,j), T, p);
    2553         108 :     if (degpol(u))
    2554             :     {
    2555          78 :       u = FpXQX_normalize(u, T, p);
    2556          78 :       Sr = FpXQX_div(Sr, u, T, p);
    2557             :     }
    2558         108 :     gel(F,j) = u;
    2559             :   }
    2560          64 :   if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: F");
    2561          64 :   f = const_vec(n, pol_1(v));
    2562         172 :   for (j = 1; j <= m; j++)
    2563             :   {
    2564         108 :     GEN e = gel(F, j);
    2565         150 :     for (i=l-1; i >= 0; i--)
    2566             :     {
    2567         150 :       GEN u = FpXQX_gcd(e, FpXX_sub(gel(g, j), gel(b, i+1), p), T, p);
    2568         150 :       if (degpol(u))
    2569             :       {
    2570          99 :         gel(f, l*j-i) = u = FpXQX_normalize(u, T, p);
    2571          99 :         e = FpXQX_div(e, u, T, p);
    2572             :       }
    2573         150 :       if (!degpol(e)) break;
    2574             :     }
    2575             :   }
    2576          64 :   if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: f");
    2577          64 :   if (degpol(Sr)) gel(f, degpol(Sr)) = Sr;
    2578          64 :   return gerepilecopy(av, f);
    2579             : }
    2580             : 
    2581             : static GEN
    2582          49 : FpXQX_ddf_i(GEN f, GEN T, GEN p)
    2583             : {
    2584             :   GEN Xq;
    2585          49 :   if (!get_FpXQX_degree(f)) return cgetg(1,t_VEC);
    2586          49 :   f = FpXQX_get_red(f, T, p);
    2587          49 :   Xq = FpXQX_Frobenius(f, T, p);
    2588          49 :   return FpXQX_ddf_Shoup(f, Xq, T, p);
    2589             : }
    2590             : 
    2591             : static GEN
    2592           7 : FpXQX_ddf_raw(GEN f, GEN T, GEN p)
    2593             : {
    2594           7 :   if (lgefint(p)==3)
    2595             :   {
    2596           0 :     ulong pp = p[2];
    2597             :     GEN M;
    2598           0 :     long vT = get_FpX_var(T);
    2599           0 :     if (pp==2)
    2600             :     {
    2601           0 :       M = F2xqX_ddf(ZXX_to_F2xX(f, vT),  ZX_to_F2x(get_FpX_mod(T)));
    2602           0 :       return mkvec2(F2xXC_to_ZXXC(gel(M,1)), gel(M,2));
    2603             :     }
    2604           0 :     M = FlxqX_ddf(ZXX_to_FlxX(f, pp, vT),  ZXT_to_FlxT(T, pp), pp);
    2605           0 :     return mkvec2(FlxXC_to_ZXXC(gel(M,1)), gel(M,2));
    2606             :   }
    2607           7 :   T = FpX_get_red(T, p);
    2608           7 :   f = FpXQX_normalize(get_FpXQX_mod(f), T, p);
    2609           7 :   return ddf_to_ddf2( FpXQX_ddf_i(f, T, p) );
    2610             : }
    2611             : 
    2612             : GEN
    2613           7 : FpXQX_ddf(GEN x, GEN T, GEN p)
    2614           7 : { pari_sp av = avma; return gerepilecopy(av, FpXQX_ddf_raw(x,T,p)); }
    2615             : 
    2616             : static GEN
    2617          42 : FpXQX_degfact_raw(GEN f, GEN T, GEN p)
    2618             : {
    2619             :   GEN V;
    2620             :   long i,l;
    2621          42 :   if (lgefint(p)==3)
    2622             :   {
    2623           0 :     ulong pp = p[2];
    2624           0 :     long vT = get_FpX_var(T);
    2625           0 :     if (pp==2)
    2626           0 :       return F2xqX_degfact(ZXX_to_F2xX(f, vT),  ZX_to_F2x(get_FpX_mod(T)));
    2627             :     else
    2628           0 :       return FlxqX_degfact(ZXX_to_FlxX(f, pp, vT),  ZXT_to_FlxT(T, pp), pp);
    2629             :   }
    2630          42 :   T = FpX_get_red(T, p);
    2631          42 :   f = FpXQX_normalize(get_FpXQX_mod(f), T, p);
    2632          42 :   V = FpXQX_factor_Yun(f, T, p); l = lg(V);
    2633          84 :   for (i=1; i < l; i++) gel(V,i) = FpXQX_ddf_i(gel(V,i), T, p);
    2634          42 :   return vddf_to_simplefact(V, degpol(f));
    2635             : }
    2636             : 
    2637             : GEN
    2638          42 : FpXQX_degfact(GEN x, GEN T, GEN p)
    2639          42 : { pari_sp av = avma; return gerepilecopy(av, FpXQX_degfact_raw(x,T,p)); }
    2640             : 
    2641             : static void
    2642          23 : FpXQX_edf_rec(GEN S, GEN xp, GEN Xp, GEN hp, GEN t, long d, GEN T, GEN p, GEN V, long idx)
    2643             : {
    2644          23 :   GEN Sp = get_FpXQX_mod(S);
    2645             :   GEN u1, u2, f1, f2;
    2646             :   GEN h;
    2647          23 :   h = FpXQX_get_red(hp, T, p);
    2648          23 :   t = FpXQX_rem(t, S, T, p);
    2649          23 :   Xp = FpXQX_rem(Xp, h, T, p);
    2650          23 :   u1 = FpXQX_roots_split(hp, xp, Xp, h, T, p);
    2651          23 :   f1 = FpXQX_gcd(FpXQX_FpXQXQ_eval(u1, t, S, T, p), Sp, T, p);
    2652          23 :   f1 = FpXQX_normalize(f1, T, p);
    2653          23 :   u2 = FpXQX_div(hp, u1, T, p);
    2654          23 :   f2 = FpXQX_div(Sp, f1, T, p);
    2655          23 :   if (degpol(u1)==1)
    2656          15 :     gel(V, idx) = f1;
    2657             :   else
    2658           8 :     FpXQX_edf_rec(FpXQX_get_red(f1, T, p), xp, Xp, u1, t, d, T, p, V, idx);
    2659          23 :   idx += degpol(f1)/d;
    2660          23 :   if (degpol(u2)==1)
    2661          16 :     gel(V, idx) = f2;
    2662             :   else
    2663           7 :     FpXQX_edf_rec(FpXQX_get_red(f2, T, p), xp, Xp, u2, t, d, T, p, V, idx);
    2664          23 : }
    2665             : 
    2666             : static void
    2667           8 : FpXQX_edf(GEN Sp, GEN xp, GEN Xp, GEN Xq, long d, GEN T, GEN p, GEN V, long idx)
    2668             : {
    2669           8 :   long n = degpol(Sp), r = n/d, vS = varn(Sp);
    2670             :   GEN S, h, t;
    2671             :   pari_timer ti;
    2672           8 :   if (r==1) { gel(V, idx) = Sp; return; }
    2673           8 :   S = FpXQX_get_red(Sp, T, p);
    2674           8 :   Xp = FpXQX_rem(Xp, S, T, p);
    2675           8 :   Xq = FpXQX_rem(Xq, S, T, p);
    2676           8 :   if (DEBUGLEVEL>=7) timer_start(&ti);
    2677             :   do
    2678             :   {
    2679           8 :     GEN g = random_FpXQX(n, vS, T, p);
    2680           8 :     t = gel(FpXQXQ_auttrace(mkvec2(Xq, g), d, S, T, p), 2);
    2681           8 :     if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_edf: FpXQXQ_auttrace");
    2682           8 :     h = FpXQXQ_minpoly(t, S, T, p);
    2683           8 :     if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_edf: FpXQXQ_minpoly");
    2684           8 :   } while (degpol(h) != r);
    2685           8 :   Xp = FpXQXQ_pow(pol_x(vS), p, h, T, p);
    2686           8 :   FpXQX_edf_rec(S, xp, Xp, h, t, d, T, p, V, idx);
    2687             : }
    2688             : 
    2689             : static void
    2690           0 : FpXQX_edf_simple(GEN Sp, GEN xp, GEN Xp, GEN Xq, long d, GEN T, GEN p, GEN V, long idx)
    2691             : {
    2692           0 :   long v = varn(Sp), n = degpol(Sp), r = n/d;
    2693             :   GEN S, f, ff;
    2694           0 :   long vT = get_FpX_var(T), dT = get_FpX_degree(T);
    2695           0 :   if (r==1) { gel(V, idx) = Sp; return; }
    2696           0 :   S = FpXQX_get_red(Sp, T, p);
    2697           0 :   Xp = FpXQX_rem(Xp, S, T, p);
    2698           0 :   Xq = FpXQX_rem(Xq, S, T, p);
    2699             :   while (1)
    2700           0 :   {
    2701           0 :     pari_sp btop = avma;
    2702             :     long i;
    2703           0 :     GEN g = random_FpXQX(n, v, T, p);
    2704           0 :     GEN t = gel(FpXQXQ_auttrace(mkvec2(Xq, g), d, S, T, p), 2);
    2705           0 :     if (lgpol(t) == 0) continue;
    2706           0 :     for(i=1; i<=10; i++)
    2707             :     {
    2708           0 :       pari_sp btop2 = avma;
    2709           0 :       GEN r = random_FpX(dT, vT, p);
    2710           0 :       GEN R = FpXQXQ_halfFrobenius_i(FqX_Fq_add(t, r, T, p), xp, Xp, S, T, p);
    2711           0 :       f = FpXQX_gcd(FqX_Fq_add(R, gen_m1, T, p), Sp, T, p);
    2712           0 :       if (degpol(f) > 0 && degpol(f) < n) break;
    2713           0 :       set_avma(btop2);
    2714             :     }
    2715           0 :     if (degpol(f) > 0 && degpol(f) < n) break;
    2716           0 :     set_avma(btop);
    2717             :   }
    2718           0 :   f = FpXQX_normalize(f, T, p);
    2719           0 :   ff = FpXQX_div(Sp, f , T, p);
    2720           0 :   FpXQX_edf_simple(f,  xp, Xp, Xq, d, T, p, V, idx);
    2721           0 :   FpXQX_edf_simple(ff, xp, Xp, Xq, d, T, p, V, idx+degpol(f)/d);
    2722             : }
    2723             : 
    2724             : static GEN
    2725          22 : FpXQX_factor_Shoup(GEN S, GEN xp, GEN T, GEN p)
    2726             : {
    2727          22 :   long i, n, s = 0, dT = get_FpX_degree(T), e = expi(powiu(p, dT));
    2728             :   GEN X, Xp, Xq, D, V;
    2729             :   pari_timer ti;
    2730          22 :   n = get_FpXQX_degree(S);
    2731          22 :   S = FpXQX_get_red(S, T, p);
    2732          22 :   if (DEBUGLEVEL>=6) timer_start(&ti);
    2733          22 :   X  = pol_x(get_FpXQX_var(S));
    2734          22 :   Xp = FpXQXQ_pow(X, p, S, T, p);
    2735          22 :   Xq = FpXQXQ_Frobenius(xp, Xp, S, T, p);
    2736          22 :   if (DEBUGLEVEL>=6) timer_printf(&ti,"FpXQX_Frobenius");
    2737          22 :   D = FpXQX_ddf_Shoup(S, Xq, T, p);
    2738          22 :   if (DEBUGLEVEL>=6) timer_printf(&ti,"FpXQX_ddf_Shoup");
    2739          22 :   s = ddf_to_nbfact(D);
    2740          22 :   V = cgetg(s+1, t_COL);
    2741         140 :   for (i = 1, s = 1; i <= n; i++)
    2742             :   {
    2743         118 :     GEN Di = gel(D,i);
    2744         118 :     long ni = degpol(Di), ri = ni/i;
    2745         118 :     if (ni == 0) continue;
    2746          50 :     Di = FpXQX_normalize(Di, T, p);
    2747          50 :     if (ni == i) { gel(V, s++) = Di; continue; }
    2748           8 :     if (ri <= e*expu(e))
    2749           8 :       FpXQX_edf(Di, xp, Xp, Xq, i, T, p, V, s);
    2750             :     else
    2751           0 :       FpXQX_edf_simple(Di, xp, Xp, Xq, i, T, p, V, s);
    2752           8 :     if (DEBUGLEVEL>=6) timer_printf(&ti,"FpXQX_edf(%ld)",i);
    2753           8 :     s += ri;
    2754             :   }
    2755          22 :   return V;
    2756             : }
    2757             : 
    2758             : static GEN
    2759         177 : FpXQX_factor_Cantor(GEN f, GEN T, GEN p)
    2760             : {
    2761             :   GEN xp, E, F, V;
    2762             :   long i, j, l;
    2763         177 :   T = FpX_get_red(T, p);
    2764         177 :   f = FpXQX_normalize(f, T, p);
    2765         177 :   switch(degpol(f))
    2766             :   {
    2767          14 :     case -1: retmkmat2(mkcol(f), mkvecsmall(1));
    2768          14 :     case 0: return trivial_fact();
    2769          21 :     case 1: retmkmat2(mkcol(f), mkvecsmall(1));
    2770          43 :     case 2: return FpXQX_factor_2(f, T, p);
    2771             :   }
    2772          85 :   if (isabsolutepol(f)) return FpX_factorff_i(simplify_shallow(f), T, p);
    2773          22 :   xp = FpX_Frobenius(T, p);
    2774          22 :   V = FpXQX_factor_Yun(f, T, p);
    2775          22 :   l = lg(V);
    2776          22 :   F = cgetg(l, t_VEC);
    2777          22 :   E = cgetg(l, t_VEC);
    2778          44 :   for (i=1, j=1; i < l; i++)
    2779          22 :     if (degpol(gel(V,i)))
    2780             :     {
    2781          22 :       GEN Fj = FpXQX_factor_Shoup(gel(V,i), xp, T, p);
    2782          22 :       gel(E,j) = const_vecsmall(lg(Fj)-1, i);
    2783          22 :       gel(F,j) = Fj; j++;
    2784             :     }
    2785          22 :   return sort_factor_pol(FE_concat(F,E,j), cmp_RgX);
    2786             : }
    2787             : 
    2788             : long
    2789           0 : FpXQX_nbfact_Frobenius(GEN S, GEN Xq, GEN T, GEN p)
    2790             : {
    2791           0 :   pari_sp av = avma;
    2792           0 :   GEN u = get_FpXQX_mod(S);
    2793             :   long s;
    2794           0 :   if (lgefint(p)==3)
    2795             :   {
    2796           0 :     ulong pp = p[2];
    2797           0 :     long vT = get_FpX_var(T);
    2798           0 :     GEN Sp = ZXXT_to_FlxXT(S,pp,vT), Xqp = ZXX_to_FlxX(Xq,pp,vT);
    2799           0 :     s = FlxqX_nbfact_Frobenius(Sp, Xqp, ZXT_to_FlxT(T,pp), pp);
    2800             :   }
    2801           0 :   else if (isabsolutepol(u))
    2802           0 :     s = FpX_nbfactff(simplify_shallow(u), T, p);
    2803             :   else
    2804           0 :     s = ddf_to_nbfact(FpXQX_ddf_Shoup(S, Xq, T, p));
    2805           0 :   return gc_long(av,s);
    2806             : }
    2807             : 
    2808             : long
    2809           0 : FpXQX_nbfact(GEN S, GEN T, GEN p)
    2810             : {
    2811           0 :   pari_sp av = avma;
    2812           0 :   GEN u = get_FpXQX_mod(S);
    2813             :   long s;
    2814           0 :   if (lgefint(p)==3)
    2815             :   {
    2816           0 :     ulong pp = p[2];
    2817           0 :     long vT = get_FpX_var(T);
    2818           0 :     s = FlxqX_nbfact(ZXXT_to_FlxXT(S,pp,vT), ZXT_to_FlxT(T,pp), pp);
    2819             :   }
    2820           0 :   else if (isabsolutepol(u))
    2821           0 :     s = FpX_nbfactff(simplify_shallow(u), T, p);
    2822             :   else
    2823           0 :     s = ddf_to_nbfact(FpXQX_ddf_Shoup(S, FpXQX_Frobenius(S, T, p), T, p));
    2824           0 :   return gc_long(av,s);
    2825             : }
    2826             : long
    2827           0 : FqX_nbfact(GEN u, GEN T, GEN p)
    2828           0 : { return T ? FpXQX_nbfact(u, T, p): FpX_nbfact(u, p); }
    2829             : 
    2830             : static GEN
    2831           0 : FpXQX_factor_Berlekamp_i(GEN f, GEN T, GEN p)
    2832             : {
    2833           0 :   if (lgefint(p)==3)
    2834             :   {
    2835           0 :     ulong pp = p[2];
    2836             :     GEN M;
    2837           0 :     long vT = get_FpX_var(T);
    2838           0 :     if (pp==2)
    2839             :     {
    2840           0 :       M = F2xqX_factor_Cantor(ZXX_to_F2xX(f, vT),  ZX_to_F2x(get_FpX_mod(T)));
    2841           0 :       return mkvec2(F2xXC_to_ZXXC(gel(M,1)), gel(M,2));
    2842             :     }
    2843           0 :     M = FlxqX_Berlekamp_i(ZXX_to_FlxX(f, pp, vT),  ZXT_to_FlxT(T, pp), pp);
    2844           0 :     return mkvec2(FlxXC_to_ZXXC(gel(M,1)), gel(M,2));
    2845             :   }
    2846           0 :   return FpXQX_Berlekamp_i(f, T, p);
    2847             : }
    2848             : GEN
    2849           0 : FpXQX_factor_Berlekamp(GEN x, GEN T, GEN p)
    2850           0 : { pari_sp av = avma; return gerepilecopy(av, FpXQX_factor_Berlekamp_i(x,T,p)); }
    2851             : 
    2852             : static GEN
    2853       14009 : FpXQX_factor_i(GEN f, GEN T, GEN p)
    2854             : {
    2855       14009 :   if (lgefint(p)==3)
    2856             :   {
    2857       13832 :     ulong pp = p[2];
    2858             :     GEN M;
    2859       13832 :     long vT = get_FpX_var(T);
    2860       13832 :     if (pp==2)
    2861             :     {
    2862        1274 :       M = F2xqX_factor_Cantor(ZXX_to_F2xX(f, vT),  ZX_to_F2x(get_FpX_mod(T)));
    2863        1267 :       return mkvec2(F2xXC_to_ZXXC(gel(M,1)), gel(M,2));
    2864             :     }
    2865       12558 :     M = FlxqX_factor_Cantor(ZXX_to_FlxX(f, pp, vT),  ZXT_to_FlxT(T, pp), pp);
    2866       12551 :     return mkvec2(FlxXC_to_ZXXC(gel(M,1)), gel(M,2));
    2867             :   }
    2868         177 :   return FpXQX_factor_Cantor(f, T, p);
    2869             : }
    2870             : GEN
    2871       14009 : FpXQX_factor(GEN x, GEN T, GEN p)
    2872       14009 : { pari_sp av = avma; return gerepilecopy(av, FpXQX_factor_i(x,T,p)); }
    2873             : 
    2874             : long
    2875       10679 : FlxqX_is_squarefree(GEN P, GEN T, ulong p)
    2876             : {
    2877       10679 :   pari_sp av = avma;
    2878       10679 :   GEN z = FlxqX_gcd(P, FlxX_deriv(P, p), T, p);
    2879       10679 :   return gc_long(av, degpol(z)==0);
    2880             : }
    2881             : 
    2882             : long
    2883      683620 : FqX_is_squarefree(GEN P, GEN T, GEN p)
    2884             : {
    2885      683620 :   pari_sp av = avma;
    2886      683620 :   GEN z = FqX_gcd(P, FqX_deriv(P, T, p), T, p);
    2887      683620 :   return gc_long(av, degpol(z)==0);
    2888             : }
    2889             : 
    2890             : /* as RgX_to_FpXQ(FqX_to_FFX), leaving alone t_FFELT */
    2891             : static GEN
    2892         350 : RgX_to_FFX(GEN x, GEN ff)
    2893             : {
    2894             :   long i, lx;
    2895         350 :   GEN p = FF_p_i(ff), T = FF_mod(ff), y =  cgetg_copy(x,&lx);
    2896         350 :   y[1] = x[1]; if (degpol(T) == 1) T = NULL;
    2897        1120 :   for (i = 2; i < lx; i++)
    2898             :   {
    2899         770 :     GEN c = gel(x,i);
    2900         770 :     gel(y,i) = typ(c) == t_FFELT? c: Fq_to_FF(Rg_to_Fq(c,T,p), ff);
    2901             :   }
    2902         350 :   return y;
    2903             : }
    2904             : 
    2905             : #define code(t1,t2) ((t1 << 6) | t2)
    2906             : /* Check types and replace F by a monic normalized FpX having the same roots
    2907             :  * Don't bother to make constant polynomials monic */
    2908             : static GEN
    2909      152625 : factmod_init(GEN f, GEN *pD, GEN *pT, GEN *pp)
    2910             : {
    2911      152625 :   const char *s = "factormod";
    2912      152625 :   GEN T, p, D = *pD;
    2913      152625 :   if (typ(f) != t_POL) pari_err_TYPE(s,f);
    2914      152625 :   if (!D)
    2915             :   {
    2916      103439 :     long pa, t = RgX_type(f, pp, pT, &pa);
    2917      103439 :     if (t == t_FFELT) return f;
    2918           0 :     *pD = gen_0;
    2919           0 :     if (t != t_INTMOD && t != code(t_POLMOD,t_INTMOD)) pari_err_TYPE(s,f);
    2920           0 :     return RgX_to_FqX(f, *pT, *pp);
    2921             :   }
    2922       49186 :   if (typ(D) == t_FFELT) { *pD = NULL; *pT = D; return RgX_to_FFX(f,D); }
    2923       48836 :   if (!ff_parse_Tp(D, &T, &p, 1)) pari_err_TYPE(s,D);
    2924       48822 :   if (T && varncmp(varn(T), varn(f)) <= 0)
    2925           0 :     pari_err_PRIORITY(s, T, "<=", varn(f));
    2926       48822 :   *pT = T; *pp = p; return RgX_to_FqX(f, T, p);
    2927             : }
    2928             : #undef code
    2929             : 
    2930             : int
    2931       49515 : ff_parse_Tp(GEN Tp, GEN *T, GEN *p, long red)
    2932             : {
    2933       49515 :   long t = typ(Tp);
    2934       49515 :   *T = *p = NULL;
    2935       49515 :   if (t == t_INT) { *p = Tp; return cmpiu(*p, 1) > 0; }
    2936         462 :   if (t != t_VEC || lg(Tp) != 3) return 0;
    2937         455 :   *T = gel(Tp,1);
    2938         455 :   *p = gel(Tp,2);
    2939         455 :   if (typ(*p) != t_INT)
    2940             :   {
    2941         420 :     if (typ(*T) != t_INT) return 0;
    2942         420 :     swap(*T, *p); /* support both [T,p] and [p,T] */
    2943             :   }
    2944         455 :   if (red) *T = RgX_to_FpX(*T, *p);
    2945         455 :   return cmpiu(*p, 1) > 0 && typ(*T) == t_POL && RgX_is_ZX(*T);
    2946             : }
    2947             : 
    2948             : static GEN
    2949        4851 : to_Fq(GEN x, GEN T, GEN p)
    2950             : {
    2951        4851 :   long i, lx, tx = typ(x);
    2952             :   GEN y;
    2953             : 
    2954        4851 :   if (tx == t_INT)
    2955         273 :     y = mkintmod(x,p);
    2956             :   else
    2957             :   {
    2958        4578 :     if (tx != t_POL) pari_err_TYPE("to_Fq",x);
    2959        4578 :     y = cgetg_copy(x,&lx); y[1] = x[1];
    2960      134204 :     for (i=2; i<lx; i++) gel(y,i) = mkintmod(gel(x,i), p);
    2961             :   }
    2962        4851 :   return mkpolmod(y, T);
    2963             : }
    2964             : static GEN
    2965         252 : to_Fq_pol(GEN x, GEN T, GEN p)
    2966             : {
    2967         252 :   long i, lx = lg(x);
    2968         252 :   if (lx == 2)
    2969             :   {
    2970          21 :     GEN y = cgetg(3,t_POL); y[1]=x[1];
    2971          21 :     gel(y,2) = mkintmod(gen_0,p); return y;
    2972             :   }
    2973         749 :   for (i = 2; i < lx; i++) gel(x,i) = to_Fq(gel(x,i),T,p);
    2974         231 :   return x;
    2975             : }
    2976             : static GEN
    2977         189 : to_Fq_fact(GEN fa, GEN T, GEN p)
    2978             : {
    2979         189 :   GEN P = gel(fa,1);
    2980         189 :   long j, l = lg(P);
    2981         189 :   p = icopy(p); T = FpX_to_mod(T, p);
    2982         441 :   for (j=1; j<l; j++) gel(P,j) = to_Fq_pol(gel(P,j), T,p);
    2983         189 :   return fa;
    2984             : }
    2985             : static GEN
    2986         224 : to_FqC(GEN P, GEN T, GEN p)
    2987             : {
    2988         224 :   long j, l = lg(P);
    2989         224 :   p = icopy(p); T = FpX_to_mod(T, p);
    2990        4557 :   for (j=1; j<l; j++) gel(P,j) = to_Fq(gel(P,j), T,p);
    2991         224 :   return P;
    2992             : }
    2993             : 
    2994             : GEN
    2995         910 : factmod(GEN f, GEN D)
    2996             : {
    2997             :   pari_sp av;
    2998             :   GEN y, F, P, E, T, p;
    2999         910 :   f = factmod_init(f, &D, &T,&p);
    3000         903 :   if (!D) return FFX_factor(f, T);
    3001         686 :   av = avma;
    3002         686 :   F = FqX_factor(f, T, p); P = gel(F,1); E = gel(F,2);
    3003         672 :   if (!T)
    3004             :   {
    3005         483 :     y = cgetg(3, t_MAT);
    3006         483 :     gel(y,1) = FpXC_to_mod(P, p);
    3007         483 :     gel(y,2) = Flc_to_ZC(E); return gerepileupto(av, y);
    3008             :   }
    3009         189 :   F = gerepilecopy(av, mkmat2(simplify_shallow(P), Flc_to_ZC(E)));
    3010         189 :   return to_Fq_fact(F, T, p);
    3011             : }
    3012             : GEN
    3013       47975 : simplefactmod(GEN f, GEN D)
    3014             : {
    3015       47975 :   pari_sp av = avma;
    3016             :   GEN T, p;
    3017       47975 :   f = factmod_init(f, &D, &T,&p);
    3018       47975 :   if (lg(f) <= 3) { set_avma(av); return trivial_fact(); }
    3019       47912 :   f = D? FqX_degfact(f, T, p): FFX_degfact(f, T);
    3020       47912 :   return gerepileupto(av, Flm_to_ZM(f));
    3021             : }
    3022             : static GEN
    3023          14 : sqf_to_fact(GEN f)
    3024             : {
    3025          14 :   long i, j, l = lg(f);
    3026          14 :   GEN P = cgetg(l, t_COL), E = cgetg(l, t_COL);
    3027          35 :   for (i = j = 1; i < l; i++)
    3028          21 :     if (degpol(gel(f,i)))
    3029             :     {
    3030          21 :       gel(P,j) = gel(f,i);
    3031          21 :       gel(E,j) = utoi(i); j++;
    3032             :     }
    3033          14 :   setlg(P,j);
    3034          14 :   setlg(E,j); return mkvec2(P,E);
    3035             : }
    3036             : 
    3037             : GEN
    3038          35 : factormodSQF(GEN f, GEN D)
    3039             : {
    3040          35 :   pari_sp av = avma;
    3041             :   GEN F, T, p;
    3042          35 :   f = factmod_init(f, &D, &T,&p);
    3043          35 :   if (lg(f) <= 3) { set_avma(av); return trivial_fact(); }
    3044          14 :   if (!D)
    3045           7 :     F = sqf_to_fact(FFX_factor_squarefree(f, T));
    3046             :   else
    3047             :   {
    3048           7 :     F = sqf_to_fact(FqX_factor_squarefree(f,T,p));
    3049           7 :     gel(F,1) = FqXC_to_mod(gel(F,1), T,p);
    3050             :   }
    3051          14 :   settyp(F,t_MAT); return gerepilecopy(av, F);
    3052             : }
    3053             : GEN
    3054          28 : factormodDDF(GEN f, GEN D)
    3055             : {
    3056          28 :   pari_sp av = avma;
    3057             :   GEN F, T, p;
    3058          28 :   f = factmod_init(f, &D, &T,&p);
    3059          28 :   if (lg(f) <= 3) { set_avma(av); return trivial_fact(); }
    3060          14 :   if (!D) return FFX_ddf(f, T);
    3061           7 :   F = FqX_ddf(f,T,p);
    3062           7 :   gel(F,1) = FqXC_to_mod(gel(F,1), T,p);
    3063           7 :   gel(F,2) = Flc_to_ZC(gel(F,2));
    3064           7 :   settyp(F, t_MAT); return gerepilecopy(av, F);
    3065             : }
    3066             : 
    3067             : GEN
    3068       48451 : factormod0(GEN f, GEN p, long flag)
    3069             : {
    3070       48451 :   if (flag == 0) return factmod(f,p);
    3071       47975 :   if (flag != 1) pari_err_FLAG("factormod");
    3072       47975 :   return simplefactmod(f,p);
    3073             : }
    3074             : GEN
    3075      103677 : polrootsmod(GEN f, GEN D)
    3076             : {
    3077             :   pari_sp av;
    3078             :   GEN y, T, p;
    3079      103677 :   f = factmod_init(f, &D, &T,&p);
    3080      103670 :   if (!D) return FFX_roots(f, T);
    3081         308 :   av = avma; y = FqX_roots(f, T, p);
    3082         280 :   if (!T) return gerepileupto(av, FpC_to_mod(y,p));
    3083         224 :   y = gerepilecopy(av, simplify_shallow(y));
    3084         224 :   return to_FqC(y, T, p);
    3085             : }
    3086             : 
    3087             : GEN /* OBSOLETE */
    3088           0 : rootmod0(GEN f, GEN p, long flag) { (void)flag; return polrootsmod(f,p); }
    3089             : GEN /* OBSOLETE */
    3090           0 : factorff(GEN f, GEN p, GEN T)
    3091             : {
    3092           0 :   pari_sp av = avma;
    3093           0 :   GEN D = (p && T)? mkvec2(T,p): NULL;
    3094           0 :   return gerepileupto(av, factmod(f,D));
    3095             : }
    3096             : GEN /* OBSOLETE */
    3097           0 : polrootsff(GEN f, GEN p, GEN T)
    3098             : {
    3099           0 :   pari_sp av = avma;
    3100           0 :   GEN D = (p && T)? mkvec2(T,p): NULL;
    3101           0 :   return gerepileupto(av, polrootsmod(f, D));
    3102             : }

Generated by: LCOV version 1.16