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 - FpX.c (source / functions) Coverage Total Hit
Test: PARI/GP v2.18.1 lcov report (development 31042-0fbe168e69) Lines: 91.8 % 2164 1986
Test Date: 2026-07-23 17:04:59 Functions: 93.5 % 230 215
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Copyright (C) 2007  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              : /* Not so fast arithmetic with polynomials over Fp */
      19              : 
      20              : static GEN
      21     87086178 : get_FpX_red(GEN T, GEN *B)
      22              : {
      23     87086178 :   if (typ(T)!=t_VEC) { *B=NULL; return T; }
      24       863925 :   *B = gel(T,1); return gel(T,2);
      25              : }
      26              : 
      27              : /***********************************************************************/
      28              : /**                                                                   **/
      29              : /**                              FpX                                  **/
      30              : /**                                                                   **/
      31              : /***********************************************************************/
      32              : 
      33              : /* FpX are polynomials over Z/pZ represented as t_POL with
      34              :  * t_INT coefficients.
      35              :  * 1) Coefficients should belong to {0,...,p-1}, though nonreduced
      36              :  * coefficients should work but be slower.
      37              :  *
      38              :  * 2) p is not assumed to be prime, but it is assumed that impossible divisions
      39              :  *    will not happen.
      40              :  * 3) Theses functions let some garbage on the stack, but are gc_upto
      41              :  * compatible.
      42              :  */
      43              : 
      44              : static ulong
      45     44208429 : to_Flx(GEN *P, GEN *Q, GEN p)
      46              : {
      47     44208429 :   ulong pp = uel(p,2);
      48     44208429 :   *P = ZX_to_Flx(*P, pp);
      49     44208429 :   if(Q) *Q = ZX_to_Flx(*Q, pp);
      50     44208429 :   return pp;
      51              : }
      52              : 
      53              : static ulong
      54      2166345 : to_Flxq(GEN *P, GEN *T, GEN p)
      55              : {
      56      2166345 :   ulong pp = uel(p,2);
      57      2166345 :   if (P) *P = ZX_to_Flx(*P, pp);
      58      2166345 :   *T = ZXT_to_FlxT(*T, pp); return pp;
      59              : }
      60              : 
      61              : GEN
      62         1726 : Z_to_FpX(GEN a, GEN p, long v)
      63              : {
      64         1726 :   pari_sp av = avma;
      65         1726 :   GEN z = cgetg(3, t_POL);
      66         1726 :   GEN x = modii(a, p);
      67         1726 :   if (!signe(x)) { set_avma(av); return pol_0(v); }
      68         1726 :   z[1] = evalsigne(1) | evalvarn(v);
      69         1726 :   gel(z,2) = x; return z;
      70              : }
      71              : 
      72              : /* z in Z[X], return lift(z * Mod(1,p)), normalized*/
      73              : GEN
      74     97496371 : FpX_red(GEN z, GEN p)
      75              : {
      76     97496371 :   long i, l = lg(z);
      77     97496371 :   GEN x = cgetg(l, t_POL);
      78   1397265230 :   for (i=2; i<l; i++) gel(x,i) = modii(gel(z,i),p);
      79     97496371 :   x[1] = z[1]; return FpX_renormalize(x,l);
      80              : }
      81              : 
      82              : GEN
      83       404894 : FpXV_red(GEN x, GEN p)
      84      1920038 : { pari_APPLY_type(t_VEC, FpX_red(gel(x,i), p)) }
      85              : 
      86              : GEN
      87      1660178 : FpXT_red(GEN x, GEN p)
      88              : {
      89      1660178 :   if (typ(x) == t_POL)
      90      1570900 :     return FpX_red(x, p);
      91              :   else
      92       388437 :     pari_APPLY_type(t_VEC, FpXT_red(gel(x,i), p))
      93              : }
      94              : 
      95              : GEN
      96      1866107 : FpX_normalize(GEN z, GEN p)
      97              : {
      98      1866107 :   GEN p1 = leading_coeff(z);
      99      1866107 :   if (lg(z) == 2 || equali1(p1)) return z;
     100       134821 :   return FpX_Fp_mul_to_monic(z, Fp_inv(p1,p), p);
     101              : }
     102              : 
     103              : GEN
     104       314532 : FpX_center(GEN T, GEN p, GEN pov2)
     105              : {
     106       314532 :   long i, l = lg(T);
     107       314532 :   GEN P = cgetg(l,t_POL);
     108      1423921 :   for(i=2; i<l; i++) gel(P,i) = Fp_center(gel(T,i), p, pov2);
     109       314532 :   P[1] = T[1]; return P;
     110              : }
     111              : GEN
     112      2250523 : FpX_center_i(GEN T, GEN p, GEN pov2)
     113              : {
     114      2250523 :   long i, l = lg(T);
     115      2250523 :   GEN P = cgetg(l,t_POL);
     116     10479258 :   for(i=2; i<l; i++) gel(P,i) = Fp_center_i(gel(T,i), p, pov2);
     117      2250523 :   P[1] = T[1]; return P;
     118              : }
     119              : 
     120              : GEN
     121     18327855 : FpX_add(GEN x,GEN y,GEN p)
     122              : {
     123     18327855 :   long lx = lg(x), ly = lg(y), i;
     124              :   GEN z;
     125     18327855 :   if (lx < ly) swapspec(x,y, lx,ly);
     126     18327855 :   z = cgetg(lx,t_POL); z[1] = x[1];
     127    161354209 :   for (i=2; i<ly; i++) gel(z,i) = Fp_add(gel(x,i),gel(y,i), p);
     128     43155478 :   for (   ; i<lx; i++) gel(z,i) = modii(gel(x,i), p);
     129     18327855 :   z = ZX_renormalize(z, lx);
     130     18327855 :   if (!lgpol(z)) { set_avma((pari_sp)(z + lx)); return pol_0(varn(x)); }
     131     17596774 :   return z;
     132              : }
     133              : 
     134              : static GEN
     135        21769 : Fp_red_FpX(GEN x, GEN p, long v)
     136              : {
     137              :   GEN z;
     138        21769 :   if (!signe(x)) return pol_0(v);
     139        14858 :   z = cgetg(3, t_POL);
     140        14858 :   gel(z,2) = Fp_red(x,p);
     141        14858 :   z[1] = evalvarn(v);
     142        14858 :   return FpX_renormalize(z, 3);
     143              : }
     144              : 
     145              : static GEN
     146         1025 : Fp_neg_FpX(GEN x, GEN p, long v)
     147              : {
     148              :   GEN z;
     149         1025 :   if (!signe(x)) return pol_0(v);
     150          884 :   z = cgetg(3, t_POL);
     151          884 :   gel(z,2) = Fp_neg(x,p);
     152          884 :   z[1] = evalvarn(v);
     153          884 :   return FpX_renormalize(z, 3);
     154              : }
     155              : 
     156              : GEN
     157       882326 : FpX_Fp_add(GEN y,GEN x,GEN p)
     158              : {
     159       882326 :   long i, lz = lg(y);
     160              :   GEN z;
     161       882326 :   if (lz == 2) return Fp_red_FpX(x,p,varn(y));
     162       860557 :   z = cgetg(lz,t_POL); z[1] = y[1];
     163       860557 :   gel(z,2) = Fp_add(gel(y,2),x, p);
     164       860557 :   if (lz == 3) z = FpX_renormalize(z,lz);
     165              :   else
     166      2118940 :     for(i=3;i<lz;i++) gel(z,i) = icopy(gel(y,i));
     167       860557 :   return z;
     168              : }
     169              : GEN
     170            0 : FpX_Fp_add_shallow(GEN y,GEN x,GEN p)
     171              : {
     172            0 :   long i, lz = lg(y);
     173              :   GEN z;
     174            0 :   if (lz == 2) return scalar_ZX_shallow(x,varn(y));
     175            0 :   z = cgetg(lz,t_POL); z[1] = y[1];
     176            0 :   gel(z,2) = Fp_add(gel(y,2),x, p);
     177            0 :   if (lz == 3) z = FpX_renormalize(z,lz);
     178              :   else
     179            0 :     for(i=3;i<lz;i++) gel(z,i) = gel(y,i);
     180            0 :   return z;
     181              : }
     182              : GEN
     183       587735 : FpX_Fp_sub(GEN y,GEN x,GEN p)
     184              : {
     185       587735 :   long i, lz = lg(y);
     186              :   GEN z;
     187       587735 :   if (lz == 2) return Fp_neg_FpX(x,p,varn(y));
     188       586710 :   z = cgetg(lz,t_POL); z[1] = y[1];
     189       586710 :   gel(z,2) = Fp_sub(gel(y,2),x, p);
     190       586710 :   if (lz == 3) z = FpX_renormalize(z,lz);
     191              :   else
     192      1348765 :     for(i=3;i<lz;i++) gel(z,i) = icopy(gel(y,i));
     193       586710 :   return z;
     194              : }
     195              : GEN
     196        11146 : FpX_Fp_sub_shallow(GEN y,GEN x,GEN p)
     197              : {
     198        11146 :   long i, lz = lg(y);
     199              :   GEN z;
     200        11146 :   if (lz == 2) return Fp_neg_FpX(x,p,varn(y));
     201        11146 :   z = cgetg(lz,t_POL); z[1] = y[1];
     202        11146 :   gel(z,2) = Fp_sub(gel(y,2),x, p);
     203        11146 :   if (lz == 3) z = FpX_renormalize(z,lz);
     204              :   else
     205        37357 :     for(i=3;i<lz;i++) gel(z,i) = gel(y,i);
     206        11146 :   return z;
     207              : }
     208              : 
     209              : GEN
     210       688585 : FpX_neg(GEN x,GEN p)
     211      6388371 : { pari_APPLY_ZX(Fp_neg(gel(x,i), p)); }
     212              : 
     213              : static GEN
     214     15422353 : FpX_subspec(GEN x,GEN y,GEN p, long nx, long ny)
     215              : {
     216              :   long i, lz;
     217              :   GEN z;
     218     15422353 :   if (nx >= ny)
     219              :   {
     220     10928818 :     lz = nx+2;
     221     10928818 :     z = cgetg(lz,t_POL); z[1] = 0; z += 2;
     222    117452014 :     for (i=0; i<ny; i++) gel(z,i) = Fp_sub(gel(x,i),gel(y,i), p);
     223     11982711 :     for (   ; i<nx; i++) gel(z,i) = modii(gel(x,i), p);
     224              :   }
     225              :   else
     226              :   {
     227      4493535 :     lz = ny+2;
     228      4493535 :     z = cgetg(lz,t_POL); z[1] = 0; z += 2;
     229     23476458 :     for (i=0; i<nx; i++) gel(z,i) = Fp_sub(gel(x,i),gel(y,i), p);
     230     14802630 :     for (   ; i<ny; i++) gel(z,i) = Fp_neg(gel(y,i), p);
     231              :   }
     232     15422353 :   z = FpX_renormalize(z-2, lz);
     233     15422353 :   if (!lgpol(z)) { set_avma((pari_sp)(z + lz)); return pol_0(0); }
     234     15114735 :   return z;
     235              : }
     236              : 
     237              : GEN
     238     14606365 : FpX_sub(GEN x,GEN y,GEN p)
     239              : {
     240     14606365 :   GEN z = FpX_subspec(x+2,y+2,p,lgpol(x),lgpol(y));
     241     14606365 :   setvarn(z, varn(x));
     242     14606365 :   return z;
     243              : }
     244              : 
     245              : GEN
     246        25643 : Fp_FpX_sub(GEN x, GEN y, GEN p)
     247              : {
     248        25643 :   long ly = lg(y), i;
     249              :   GEN z;
     250        25643 :   if (ly <= 3) {
     251          482 :     z = cgetg(3, t_POL);
     252          482 :     x = (ly == 3)? Fp_sub(x, gel(y,2), p): modii(x, p);
     253          482 :     if (!signe(x)) { set_avma((pari_sp)(z + 3)); return pol_0(varn(y)); }
     254          399 :     z[1] = evalsigne(1)|y[1]; gel(z,2) = x; return z;
     255              :   }
     256        25161 :   z = cgetg(ly,t_POL);
     257        25161 :   gel(z,2) = Fp_sub(x, gel(y,2), p);
     258        93406 :   for (i = 3; i < ly; i++) gel(z,i) = Fp_neg(gel(y,i), p);
     259        25161 :   z = ZX_renormalize(z, ly);
     260        25161 :   if (!lgpol(z)) { set_avma((pari_sp)(z + ly)); return pol_0(varn(x)); }
     261        25161 :   z[1] = y[1]; return z;
     262              : }
     263              : 
     264              : GEN
     265         1008 : FpX_convol(GEN x, GEN y, GEN p)
     266              : {
     267         1008 :   long lx = lg(x), ly = lg(y), i;
     268              :   GEN z;
     269         1008 :   if (lx < ly) swapspec(x,y, lx,ly);
     270         1008 :   z = cgetg(ly,t_POL); z[1] = x[1];
     271        66395 :   for (i=2; i<ly; i++) gel(z,i) = Fp_mul(gel(x,i),gel(y,i), p);
     272         1008 :   z = ZX_renormalize(z, ly);
     273         1008 :   if (!lgpol(z)) { set_avma((pari_sp)(z + lx)); return pol_0(varn(x)); }
     274         1008 :   return z;
     275              : }
     276              : 
     277              : GEN
     278     28629016 : FpX_mul(GEN x,GEN y,GEN p)
     279              : {
     280     28629016 :   if (lgefint(p) == 3)
     281              :   {
     282     13738366 :     ulong pp = to_Flx(&x, &y, p);
     283     13738366 :     return Flx_to_ZX(Flx_mul(x, y, pp));
     284              :   }
     285     14890650 :   return FpX_red(ZX_mul(x, y), p);
     286              : }
     287              : 
     288              : GEN
     289      9196350 : FpX_mulspec(GEN a, GEN b, GEN p, long na, long nb)
     290      9196350 : { return FpX_red(ZX_mulspec(a, b, na, nb), p); }
     291              : 
     292              : GEN
     293      6554974 : FpX_sqr(GEN x,GEN p)
     294              : {
     295      6554974 :   if (lgefint(p) == 3)
     296              :   {
     297       377322 :     ulong pp = to_Flx(&x, NULL, p);
     298       377322 :     return Flx_to_ZX(Flx_sqr(x, pp));
     299              :   }
     300      6177652 :   return FpX_red(ZX_sqr(x), p);
     301              : }
     302              : 
     303              : GEN
     304       479337 : FpX_mulu(GEN x, ulong t,GEN p)
     305              : {
     306       479337 :   t = umodui(t, p); if (!t) return zeropol(varn(x));
     307      2919109 :   pari_APPLY_ZX(Fp_mulu(gel(x,i), t, p));
     308              : }
     309              : 
     310              : GEN
     311         8099 : FpX_divu(GEN y, ulong x, GEN p)
     312         8099 : { return FpX_Fp_div(y, utoi(umodui(x, p)), p); }
     313              : 
     314              : GEN
     315      6230450 : FpX_Fp_mulspec(GEN y,GEN x,GEN p,long ly)
     316              : {
     317              :   GEN z;
     318              :   long i;
     319      6230450 :   if (!signe(x)) return pol_0(0);
     320      6200914 :   z = cgetg(ly+2,t_POL); z[1] = evalsigne(1);
     321     36132063 :   for(i=0; i<ly; i++) gel(z,i+2) = Fp_mul(gel(y,i), x, p);
     322      6200914 :   return ZX_renormalize(z, ly+2);
     323              : }
     324              : 
     325              : GEN
     326      6215923 : FpX_Fp_mul(GEN y,GEN x,GEN p)
     327              : {
     328      6215923 :   GEN z = FpX_Fp_mulspec(y+2,x,p,lgpol(y));
     329      6215923 :   setvarn(z, varn(y)); return z;
     330              : }
     331              : 
     332              : GEN
     333       611559 : FpX_Fp_div(GEN y, GEN x, GEN p)
     334              : {
     335       611559 :   return FpX_Fp_mul(y, Fp_inv(x, p), p);
     336              : }
     337              : 
     338              : GEN
     339       143048 : FpX_Fp_mul_to_monic(GEN y,GEN x,GEN p)
     340              : {
     341              :   GEN z;
     342              :   long i, l;
     343       143048 :   z = cgetg_copy(y, &l); z[1] = y[1];
     344       676634 :   for(i=2; i<l-1; i++) gel(z,i) = Fp_mul(gel(y,i), x, p);
     345       143048 :   gel(z,l-1) = gen_1; return z;
     346              : }
     347              : 
     348              : struct _FpXQ {
     349              :   GEN T, p, aut;
     350              : };
     351              : 
     352              : struct _FpX
     353              : {
     354              :   GEN p;
     355              :   long v;
     356              : };
     357              : 
     358              : static GEN
     359       373941 : _FpX_mul(void* E, GEN x, GEN y)
     360       373941 : { struct _FpX *D = (struct _FpX *)E; return FpX_mul(x, y, D->p); }
     361              : static GEN
     362        86674 : _FpX_sqr(void *E, GEN x)
     363        86674 : { struct _FpX *D = (struct _FpX *)E; return FpX_sqr(x, D->p); }
     364              : 
     365              : GEN
     366       318412 : FpX_powu(GEN x, ulong n, GEN p)
     367              : {
     368              :   struct _FpX D;
     369       318412 :   if (n==0) return pol_1(varn(x));
     370        61624 :   D.p = p;
     371        61624 :   return gen_powu(x, n, (void *)&D, _FpX_sqr, _FpX_mul);
     372              : }
     373              : 
     374              : GEN
     375       311844 : FpXV_prod(GEN V, GEN p)
     376              : {
     377              :   struct _FpX D;
     378       311844 :   D.p = p;
     379       311844 :   return gen_product(V, (void *)&D, &_FpX_mul);
     380              : }
     381              : 
     382              : static GEN
     383        35563 : _FpX_pow(void* E, GEN x, GEN y)
     384        35563 : { struct _FpX *D = (struct _FpX *)E; return FpX_powu(x, itou(y), D->p); }
     385              : static GEN
     386            0 : _FpX_one(void *E)
     387            0 : { struct _FpX *D = (struct _FpX *)E; return pol_1(D->v); }
     388              : 
     389              : GEN
     390        23314 : FpXV_factorback(GEN f, GEN e, GEN p, long v)
     391              : {
     392              :   struct _FpX D;
     393        23314 :   D.p = p; D.v = v;
     394        23314 :   return gen_factorback(f, e, (void *)&D, &_FpX_mul, &_FpX_pow, &_FpX_one);
     395              : }
     396              : 
     397              : GEN
     398        92260 : FpX_halve(GEN x, GEN p)
     399       270710 : { pari_APPLY_pol_normalized(Fp_halve(gel(x,i), p)); }
     400              : 
     401              : static GEN
     402     66827448 : FpX_divrem_basecase(GEN x, GEN y, GEN p, GEN *pr)
     403              : {
     404              :   long vx, dx, dy, dy1, dz, i, j, sx, lr;
     405              :   pari_sp av0, av;
     406              :   GEN z,p1,rem,lead;
     407              : 
     408     66827448 :   if (!signe(y)) pari_err_INV("FpX_divrem",y);
     409     66827448 :   vx = varn(x);
     410     66827448 :   dy = degpol(y);
     411     66827448 :   dx = degpol(x);
     412     66827448 :   if (dx < dy)
     413              :   {
     414       126333 :     if (pr)
     415              :     {
     416       125774 :       av0 = avma; x = FpX_red(x, p);
     417       125774 :       if (pr == ONLY_DIVIDES) { set_avma(av0); return signe(x)? NULL: pol_0(vx); }
     418       125774 :       if (pr == ONLY_REM) return x;
     419       125774 :       *pr = x;
     420              :     }
     421       126333 :     return pol_0(vx);
     422              :   }
     423     66701115 :   lead = leading_coeff(y);
     424     66701115 :   if (!dy) /* y is constant */
     425              :   {
     426       620825 :     if (pr && pr != ONLY_DIVIDES)
     427              :     {
     428       603528 :       if (pr == ONLY_REM) return pol_0(vx);
     429       585094 :       *pr = pol_0(vx);
     430              :     }
     431       602391 :     av0 = avma;
     432       602391 :     if (equali1(lead)) return FpX_red(x, p);
     433       584259 :     else return gc_upto(av0, FpX_Fp_div(x, lead, p));
     434              :   }
     435     66080290 :   av0 = avma; dz = dx-dy;
     436     66080290 :   if (lgefint(p) == 3)
     437              :   { /* assume ab != 0 mod p */
     438     27824013 :     ulong pp = to_Flx(&x, &y, p);
     439     27824013 :     z = Flx_divrem(x, y, pp, pr);
     440     27824013 :     set_avma(av0); /* HACK: assume pr last on stack, then z */
     441     27824013 :     if (!z) return NULL;
     442     27823866 :     z = leafcopy(z);
     443     27823866 :     if (pr && pr != ONLY_DIVIDES && pr != ONLY_REM)
     444              :     {
     445      5608233 :       *pr = leafcopy(*pr);
     446      5608233 :       *pr = Flx_to_ZX_inplace(*pr);
     447              :     }
     448     27823866 :     return Flx_to_ZX_inplace(z);
     449              :   }
     450     38256277 :   lead = equali1(lead)? NULL: gclone(Fp_inv(lead,p));
     451     38255989 :   set_avma(av0);
     452     38255989 :   z=cgetg(dz+3,t_POL); z[1] = x[1];
     453     38255989 :   x += 2; y += 2; z += 2;
     454     42852101 :   for (dy1=dy-1; dy1>=0 && !signe(gel(y, dy1)); dy1--);
     455              : 
     456     38255989 :   p1 = gel(x,dx); av = avma;
     457     38255989 :   gel(z,dz) = lead? gc_INT(av, Fp_mul(p1,lead, p)): icopy(p1);
     458    113565091 :   for (i=dx-1; i>=dy; i--)
     459              :   {
     460     75309102 :     av=avma; p1=gel(x,i);
     461    962109823 :     for (j=i-dy1; j<=i && j<=dz; j++)
     462    886800721 :       p1 = subii(p1, mulii(gel(z,j),gel(y,i-j)));
     463     75309102 :     if (lead) p1 = mulii(p1,lead);
     464     75309102 :     gel(z,i-dy) = gc_INT(av,modii(p1, p));
     465              :   }
     466     38255989 :   if (!pr) { guncloneNULL(lead); return z-2; }
     467              : 
     468     38175369 :   rem = (GEN)avma; av = (pari_sp)new_chunk(dx+3);
     469     42084163 :   for (sx=0; ; i--)
     470              :   {
     471     42084163 :     p1 = gel(x,i);
     472    226279911 :     for (j=maxss(0,i-dy1); j<=i && j<=dz; j++)
     473    184195748 :       p1 = subii(p1, mulii(gel(z,j),gel(y,i-j)));
     474     42084163 :     p1 = modii(p1,p); if (signe(p1)) { sx = 1; break; }
     475      4056792 :     if (!i) break;
     476      3908794 :     set_avma(av);
     477              :   }
     478     38175369 :   if (pr == ONLY_DIVIDES)
     479              :   {
     480            0 :     guncloneNULL(lead);
     481            0 :     if (sx) return gc_NULL(av0);
     482            0 :     return gc_const((pari_sp)rem, z-2);
     483              :   }
     484     38175369 :   lr=i+3; rem -= lr;
     485     38175369 :   rem[0] = evaltyp(t_POL) | _evallg(lr);
     486     38175369 :   rem[1] = z[-1];
     487     38175369 :   p1 = gc_INT((pari_sp)rem, p1);
     488     38175369 :   rem += 2; gel(rem,i) = p1;
     489    169132510 :   for (i--; i>=0; i--)
     490              :   {
     491    130957141 :     av=avma; p1 = gel(x,i);
     492   1094219882 :     for (j=maxss(0,i-dy1); j<=i && j<=dz; j++)
     493    963262741 :       p1 = subii(p1, mulii(gel(z,j),gel(y,i-j)));
     494    130957141 :     gel(rem,i) = gc_INT(av, modii(p1,p));
     495              :   }
     496     38175369 :   rem -= 2;
     497     38175369 :   guncloneNULL(lead);
     498     38175369 :   if (!sx) (void)FpX_renormalize(rem, lr);
     499     38175369 :   if (pr == ONLY_REM) return gc_upto(av0,rem);
     500      2540609 :   *pr = rem; return z-2;
     501              : }
     502              : 
     503              : GEN
     504       167227 : FpX_div_by_X_x(GEN a, GEN x, GEN p, GEN *r)
     505              : {
     506       167227 :   long l = lg(a), i;
     507              :   GEN z;
     508       167227 :   if (l <= 3)
     509              :   {
     510            0 :     if (r) *r = l == 2? gen_0: icopy(gel(a,2));
     511            0 :     return pol_0(varn(a));
     512              :   }
     513       167227 :   l--; z = cgetg(l, t_POL); z[1] = a[1];
     514       167227 :   gel(z, l-1) = gel(a,l);
     515      2548401 :   for (i = l-2; i > 1; i--) /* z[i] = a[i+1] + x*z[i+1] */
     516      2381174 :     gel(z,i) = Fp_addmul(gel(a,i+1), x, gel(z,i+1), p);
     517       167227 :   if (r) *r = Fp_addmul(gel(a,2), x, gel(z,2), p);
     518       167227 :   return z;
     519              : }
     520              : 
     521              : static GEN
     522       134778 : _FpX_divrem(void * E, GEN x, GEN y, GEN *r)
     523              : {
     524       134778 :   struct _FpX *D = (struct _FpX*) E;
     525       134778 :   return FpX_divrem(x, y, D->p, r);
     526              : }
     527              : static GEN
     528        20062 : _FpX_add(void * E, GEN x, GEN y) {
     529        20062 :   struct _FpX *D = (struct _FpX*) E;
     530        20062 :   return FpX_add(x, y, D->p);
     531              : }
     532              : 
     533              : static struct bb_ring FpX_ring = { _FpX_add,_FpX_mul,_FpX_sqr };
     534              : 
     535              : GEN
     536        11403 : FpX_digits(GEN x, GEN T, GEN p)
     537              : {
     538              :   struct _FpX D;
     539        11403 :   long d = get_FpX_degree(T), n = (lgpol(x)+d-1)/d;
     540        11403 :   D.p = p;
     541        11403 :   return gen_digits(x,T,n,(void *)&D, &FpX_ring, _FpX_divrem);
     542              : }
     543              : 
     544              : GEN
     545         4564 : FpXV_FpX_fromdigits(GEN x, GEN T, GEN p)
     546              : {
     547              :   struct _FpX D;
     548         4564 :   D.p = p;
     549         4564 :   return gen_fromdigits(x,T,(void *)&D, &FpX_ring);
     550              : }
     551              : 
     552              : long
     553       255254 : FpX_valrem(GEN x, GEN t, GEN p, GEN *py)
     554              : {
     555       255254 :   pari_sp av=avma;
     556              :   long k;
     557              :   GEN r, y;
     558              : 
     559       255254 :   for (k=0; ; k++)
     560              :   {
     561       652545 :     y = FpX_divrem(x, t, p, &r);
     562       652545 :     if (signe(r)) break;
     563       397291 :     x = y;
     564              :   }
     565       255254 :   *py = gc_GEN(av,x);
     566       255254 :   return k;
     567              : }
     568              : 
     569              : static GEN
     570        87873 : FpX_addmulmul(GEN u, GEN v, GEN x, GEN y, GEN p)
     571              : {
     572        87873 :   return FpX_add(FpX_mul(u, x, p),FpX_mul(v, y, p), p);
     573              : }
     574              : 
     575              : static GEN
     576        36106 : FpXM_FpX_mul2(GEN M, GEN x, GEN y, GEN p)
     577              : {
     578        36106 :   GEN res = cgetg(3, t_COL);
     579        36106 :   gel(res, 1) = FpX_addmulmul(gcoeff(M,1,1), gcoeff(M,1,2), x, y, p);
     580        36106 :   gel(res, 2) = FpX_addmulmul(gcoeff(M,2,1), gcoeff(M,2,2), x, y, p);
     581        36106 :   return res;
     582              : }
     583              : 
     584              : static GEN
     585        17253 : FpXM_mul2(GEN A, GEN B, GEN p)
     586              : {
     587        17253 :   GEN A11=gcoeff(A,1,1),A12=gcoeff(A,1,2), B11=gcoeff(B,1,1),B12=gcoeff(B,1,2);
     588        17253 :   GEN A21=gcoeff(A,2,1),A22=gcoeff(A,2,2), B21=gcoeff(B,2,1),B22=gcoeff(B,2,2);
     589        17253 :   GEN M1 = FpX_mul(FpX_add(A11,A22, p), FpX_add(B11,B22, p), p);
     590        17253 :   GEN M2 = FpX_mul(FpX_add(A21,A22, p), B11, p);
     591        17253 :   GEN M3 = FpX_mul(A11, FpX_sub(B12,B22, p), p);
     592        17253 :   GEN M4 = FpX_mul(A22, FpX_sub(B21,B11, p), p);
     593        17253 :   GEN M5 = FpX_mul(FpX_add(A11,A12, p), B22, p);
     594        17253 :   GEN M6 = FpX_mul(FpX_sub(A21,A11, p), FpX_add(B11,B12, p), p);
     595        17253 :   GEN M7 = FpX_mul(FpX_sub(A12,A22, p), FpX_add(B21,B22, p), p);
     596        17253 :   GEN T1 = FpX_add(M1,M4, p), T2 = FpX_sub(M7,M5, p);
     597        17253 :   GEN T3 = FpX_sub(M1,M2, p), T4 = FpX_add(M3,M6, p);
     598        17253 :   retmkmat22(FpX_add(T1,T2, p), FpX_add(M3,M5, p),
     599              :              FpX_add(M2,M4, p), FpX_add(T3,T4, p));
     600              : }
     601              : 
     602              : /* Return [0,1;1,-q]*M */
     603              : static GEN
     604        17162 : FpX_FpXM_qmul(GEN q, GEN M, GEN p)
     605              : {
     606        17162 :   GEN u = FpX_mul(gcoeff(M,2,1), q, p);
     607        17162 :   GEN v = FpX_mul(gcoeff(M,2,2), q, p);
     608        17162 :   retmkmat22(gcoeff(M,2,1), gcoeff(M,2,2),
     609              :     FpX_sub(gcoeff(M,1,1), u, p), FpX_sub(gcoeff(M,1,2), v, p));
     610              : }
     611              : 
     612              : static GEN
     613           24 : matid2_FpXM(long v)
     614           24 : { retmkmat22(pol_1(v), pol_0(v), pol_0(v), pol_1(v)); }
     615              : 
     616              : static GEN
     617            8 : matJ2_FpXM(long v)
     618            8 : { retmkmat22(pol_0(v), pol_1(v), pol_1(v), pol_0(v)); }
     619              : 
     620              : INLINE GEN
     621       986400 : FpX_shift(GEN a, long n) { return RgX_shift_shallow(a, n); }
     622              : 
     623              : INLINE GEN
     624       204530 : FpXn_red(GEN a, long n) { return RgXn_red_shallow(a, n); }
     625              : 
     626              : /* Fast resultant formula from William Hart in Flint <http://flintlib.org/> */
     627              : 
     628              : struct FpX_res
     629              : {
     630              :    GEN res, lc;
     631              :    long deg0, deg1, off;
     632              : };
     633              : 
     634              : INLINE void
     635         3749 : FpX_halfres_update(long da, long db, long dr, GEN p, struct FpX_res *res)
     636              : {
     637         3749 :   if (dr >= 0)
     638              :   {
     639         3749 :     if (!equali1(res->lc))
     640              :     {
     641         3749 :       res->lc  = Fp_powu(res->lc, da - dr, p);
     642         3749 :       res->res = Fp_mul(res->res, res->lc, p);
     643              :     }
     644         3749 :     if (both_odd(da + res->off, db + res->off))
     645            0 :       res->res = Fp_neg(res->res, p);
     646              :   } else
     647              :   {
     648            0 :     if (db == 0)
     649              :     {
     650            0 :       if (!equali1(res->lc))
     651              :       {
     652            0 :           res->lc  = Fp_powu(res->lc, da, p);
     653            0 :           res->res = Fp_mul(res->res, res->lc, p);
     654              :       }
     655              :     } else
     656            0 :       res->res = gen_0;
     657              :   }
     658         3749 : }
     659              : 
     660              : static GEN
     661        33812 : FpX_halfres_basecase(GEN a, GEN b, GEN p, GEN *pa, GEN *pb, struct FpX_res *res)
     662              : {
     663        33812 :   pari_sp av=avma;
     664              :   GEN u,u1,v,v1, M;
     665        33812 :   long vx = varn(a), n = lgpol(a)>>1;
     666        33812 :   u1 = v = pol_0(vx);
     667        33812 :   u = v1 = pol_1(vx);
     668       473665 :   while (lgpol(b)>n)
     669              :   {
     670              :     GEN r, q;
     671       439853 :     q = FpX_divrem(a,b,p, &r);
     672       439853 :     if (res)
     673              :     {
     674         3625 :       long da = degpol(a), db=degpol(b), dr = degpol(r);
     675         3625 :       res->lc = leading_coeff(b);
     676         3625 :       if (dr >= n)
     677         3403 :         FpX_halfres_update(da,db,dr,p,res);
     678              :       else
     679              :       {
     680          222 :         res->deg0 = da;
     681          222 :         res->deg1 = db;
     682              :       }
     683              :     }
     684       439853 :     a = b; b = r; swap(u,u1); swap(v,v1);
     685       439853 :     u1 = FpX_sub(u1, FpX_mul(u, q, p), p);
     686       439853 :     v1 = FpX_sub(v1, FpX_mul(v, q, p), p);
     687       439853 :     if (gc_needed(av,2))
     688              :     {
     689            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FpX_halfgcd (d = %ld)",degpol(b));
     690            0 :       if (res)
     691            0 :         (void)gc_all(av, 8, &a,&b,&u1,&v1,&u,&v,&res->res,&res->lc);
     692              :       else
     693            0 :         (void)gc_all(av, 6, &a,&b,&u1,&v1,&u,&v);
     694              :     }
     695              :   }
     696        33812 :   M = mkmat22(u,v,u1,v1); *pa = a; *pb = b;
     697          222 :   return res ? gc_all(av, 5, &M, pa, pb, &res->res, &res->lc)
     698        34034 :              : gc_all(av, 3, &M, pa, pb);
     699              : }
     700              : 
     701              : static GEN FpX_halfres_i(GEN x, GEN y, GEN p, GEN *a, GEN *b, struct FpX_res *res);
     702              : 
     703              : static GEN
     704        18960 : FpX_halfres_split(GEN x, GEN y, GEN p, GEN *a, GEN *b, struct FpX_res *res)
     705              : {
     706        18960 :   pari_sp av = avma;
     707              :   GEN R, S, T, V1, V2;
     708              :   GEN x1, y1, r, q;
     709        18960 :   long l = lgpol(x), n = l>>1, k;
     710        18960 :   if (lgpol(y) <= n)
     711            8 :     { *a = RgX_copy(x); *b = RgX_copy(y); return matid2_FpXM(varn(x)); }
     712        18952 :   if (res)
     713              :   {
     714          166 :      res->lc = leading_coeff(y);
     715          166 :      res->deg0 -= n;
     716          166 :      res->deg1 -= n;
     717          166 :      res->off += n;
     718              :   }
     719        18952 :   R = FpX_halfres_i(FpX_shift(x,-n), FpX_shift(y,-n), p, a, b, res);
     720        18952 :   if (res)
     721              :   {
     722          166 :     res->off -= n;
     723          166 :     res->deg0 += n;
     724          166 :     res->deg1 += n;
     725              :   }
     726        18952 :   V1 = FpXM_FpX_mul2(R, FpXn_red(x,n), FpXn_red(y,n), p);
     727        18952 :   x1 = FpX_add(FpX_shift(*a,n), gel(V1,1), p);
     728        18952 :   y1 = FpX_add(FpX_shift(*b,n), gel(V1,2), p);
     729        18952 :   if (lgpol(y1) <= n)
     730              :   {
     731         1798 :     *a = x1; *b = y1;
     732           42 :     return res ? gc_all(av, 5, &R, a, b, &res->res, &res->lc)
     733         1840 :                : gc_all(av, 3, &R, a, b);
     734              :   }
     735        17154 :   k = 2*n-degpol(y1);
     736        17154 :   q = FpX_divrem(x1, y1, p, &r);
     737        17154 :   if (res)
     738              :   {
     739          124 :     long dx1 = degpol(x1), dy1 = degpol(y1), dr = degpol(r);
     740          124 :     if (dy1 < degpol(y))
     741          116 :       FpX_halfres_update(res->deg0, res->deg1, dy1, p,res);
     742          124 :     res->lc = gel(y1, dy1+2);
     743          124 :     res->deg0 = dx1;
     744          124 :     res->deg1 = dy1;
     745          124 :     if (dr >= n)
     746              :     {
     747          124 :       FpX_halfres_update(dx1, dy1, dr, p,res);
     748          124 :       res->deg0 = dy1;
     749          124 :       res->deg1 = dr;
     750              :     }
     751          124 :     res->deg0 -= k;
     752          124 :     res->deg1 -= k;
     753          124 :     res->off += k;
     754              :   }
     755        17154 :   S = FpX_halfres_i(FpX_shift(y1,-k), FpX_shift(r,-k), p, a, b, res);
     756        17154 :   if (res)
     757              :   {
     758          124 :     res->deg0 += k;
     759          124 :     res->deg1 += k;
     760          124 :     res->off -= k;
     761              :   }
     762        17154 :   T = FpXM_mul2(S, FpX_FpXM_qmul(q, R, p), p);
     763        17154 :   V2 = FpXM_FpX_mul2(S, FpXn_red(y1,k), FpXn_red(r,k), p);
     764        17154 :   *a = FpX_add(FpX_shift(*a,k), gel(V2,1), p);
     765        17154 :   *b = FpX_add(FpX_shift(*b,k), gel(V2,2), p);
     766          124 :   return res ? gc_all(av, 5, &T, a, b, &res->res, &res->lc)
     767        17278 :              : gc_all(av, 3, &T, a, b);
     768              : }
     769              : 
     770              : static GEN
     771        52772 : FpX_halfres_i(GEN x, GEN y, GEN p, GEN *a, GEN *b, struct FpX_res *res)
     772              : {
     773        52772 :   if (lgpol(x) < FpX_HALFGCD_LIMIT)
     774        33812 :     return FpX_halfres_basecase(x, y, p, a, b, res);
     775        18960 :   return FpX_halfres_split(x, y, p, a, b, res);
     776              : }
     777              : 
     778              : static GEN
     779        16560 : FpX_halfgcd_all_i(GEN x, GEN y, GEN p, GEN *pa, GEN *pb)
     780              : {
     781              :   GEN a, b;
     782        16560 :   GEN R = FpX_halfres_i(x, y, p, &a, &b, NULL);
     783        16560 :   if (pa) *pa = a;
     784        16560 :   if (pb) *pb = b;
     785        16560 :   return R;
     786              : }
     787              : 
     788              : /* Return M in GL_2(Fp[X]) such that:
     789              : if [a',b']~=M*[a,b]~ then degpol(a')>= (lgpol(a)>>1) >degpol(b')
     790              : */
     791              : 
     792              : GEN
     793        16700 : FpX_halfgcd_all(GEN x, GEN y, GEN p, GEN *a, GEN *b)
     794              : {
     795        16700 :   pari_sp av = avma;
     796              :   GEN R, q, r;
     797        16700 :   if (lgefint(p)==3)
     798              :   {
     799          140 :     ulong pp = to_Flx(&x, &y, p);
     800          140 :     R = Flx_halfgcd_all(x, y, pp, a, b);
     801          140 :     R = FlxM_to_ZXM(R);
     802          140 :     if (a) *a = Flx_to_ZX(*a);
     803          140 :     if (b) *b = Flx_to_ZX(*b);
     804          140 :     return !a && b ? gc_all(av, 2, &R, b): gc_all(av, 1+!!a+!!b, &R, a, b);
     805              :   }
     806        16560 :   if (!signe(x))
     807              :   {
     808            0 :     if (a) *a = RgX_copy(y);
     809            0 :     if (b) *b = RgX_copy(x);
     810            0 :     return matJ2_FpXM(varn(x));
     811              :   }
     812        16560 :   if (degpol(y)<degpol(x)) return FpX_halfgcd_all_i(x, y, p, a, b);
     813          389 :   q = FpX_divrem(y,x,p,&r);
     814          389 :   R = FpX_halfgcd_all_i(x, r, p, a, b);
     815          389 :   gcoeff(R,1,1) = FpX_sub(gcoeff(R,1,1), FpX_mul(q, gcoeff(R,1,2), p), p);
     816          389 :   gcoeff(R,2,1) = FpX_sub(gcoeff(R,2,1), FpX_mul(q, gcoeff(R,2,2), p), p);
     817          389 :   return !a && b ? gc_all(av, 2, &R, b): gc_all(av, 1+!!a+!!b, &R, a, b);
     818              : }
     819              : 
     820              : GEN
     821          977 : FpX_halfgcd(GEN x, GEN y, GEN p)
     822          977 : { return FpX_halfgcd_all(x, y, p, NULL, NULL); }
     823              : 
     824              : static GEN
     825        53082 : FpX_gcd_basecase(GEN a, GEN b, GEN p)
     826              : {
     827        53082 :   pari_sp av = avma, av0=avma;
     828       452653 :   while (signe(b))
     829              :   {
     830              :     GEN c;
     831       399859 :     if (gc_needed(av0,2))
     832              :     {
     833            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FpX_gcd (d = %ld)",degpol(b));
     834            0 :       (void)gc_all(av0,2, &a,&b);
     835              :     }
     836       399859 :     av = avma; c = FpX_rem(a,b,p); a=b; b=c;
     837              :   }
     838        52794 :   return gc_const(av, a);
     839              : }
     840              : 
     841              : GEN
     842      1048329 : FpX_gcd(GEN x, GEN y, GEN p)
     843              : {
     844      1048329 :   pari_sp av = avma;
     845      1048329 :   if (lgefint(p)==3)
     846              :   {
     847              :     ulong pp;
     848       994787 :     (void)new_chunk((lg(x) + lg(y)) << 2); /* scratch space */
     849       994787 :     pp = to_Flx(&x, &y, p);
     850       994787 :     x = Flx_gcd(x, y, pp);
     851       994787 :     set_avma(av); return Flx_to_ZX(x);
     852              :   }
     853        53542 :   x = FpX_red(x, p);
     854        53542 :   y = FpX_red(y, p);
     855        53542 :   if (!signe(x)) return gc_upto(av, y);
     856        54129 :   while (lgpol(y) >= FpX_GCD_LIMIT)
     857              :   {
     858         1047 :     if (lgpol(y)<=(lgpol(x)>>1))
     859              :     {
     860            0 :       GEN r = FpX_rem(x, y, p);
     861            0 :       x = y; y = r;
     862              :     }
     863         1047 :     (void) FpX_halfgcd_all(x, y, p, &x, &y);
     864         1047 :     if (gc_needed(av,2))
     865              :     {
     866            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FpX_gcd (y = %ld)",degpol(y));
     867            0 :       (void)gc_all(av,2,&x,&y);
     868              :     }
     869              :   }
     870        53082 :   return gc_upto(av, FpX_gcd_basecase(x,y,p));
     871              : }
     872              : 
     873              : /* Return NULL if gcd can be computed else return a factor of p */
     874              : GEN
     875          818 : FpX_gcd_check(GEN x, GEN y, GEN p)
     876              : {
     877          818 :   pari_sp av = avma;
     878              :   GEN a,b,c;
     879              : 
     880          818 :   a = FpX_red(x, p);
     881          818 :   b = FpX_red(y, p);
     882         9045 :   while (signe(b))
     883              :   {
     884              :     GEN g;
     885         8290 :     if (!invmod(leading_coeff(b), p, &g)) return gc_INT(av,g);
     886         8227 :     b = FpX_Fp_mul_to_monic(b, g, p);
     887         8227 :     c = FpX_rem(a, b, p); a = b; b = c;
     888         8227 :     if (gc_needed(av,1))
     889              :     {
     890            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FpX_gcd_check (d = %ld)",degpol(b));
     891            0 :       (void)gc_all(av,2,&a,&b);
     892              :     }
     893              :   }
     894          755 :   return gc_NULL(av);
     895              : }
     896              : 
     897              : static GEN
     898       585091 : FpX_extgcd_basecase(GEN a, GEN b, GEN p, GEN *ptu, GEN *ptv)
     899              : {
     900       585091 :   pari_sp av=avma;
     901       585091 :   GEN v,v1, A = a, B = b;
     902       585091 :   long vx = varn(a);
     903       585091 :   if (!lgpol(b))
     904              :   {
     905            0 :     if (ptu) *ptu = pol_1(vx);
     906            0 :     *ptv = pol_0(vx);
     907            0 :     return RgX_copy(a);
     908              :   }
     909       585091 :   v = pol_0(vx); v1 = pol_1(vx);
     910              :   while (1)
     911      1555662 :   {
     912      2140753 :     GEN r, q = FpX_divrem(a,b,p, &r);
     913      2140753 :     a = b; b = r;
     914      2140753 :     swap(v,v1);
     915      2140753 :     if (!lgpol(b)) break;
     916      1555662 :     v1 = FpX_sub(v1, FpX_mul(v, q, p), p);
     917      1555662 :     if (gc_needed(av,2))
     918              :     {
     919            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FpX_extgcd (d = %ld)",degpol(a));
     920            0 :       (void)gc_all(av,4,&a,&b,&v,&v1);
     921              :     }
     922              :   }
     923       585091 :   if (ptu) *ptu = FpX_div(FpX_sub(a,FpX_mul(B,v,p),p),A,p);
     924       585091 :   *ptv = v;
     925       585091 :   return a;
     926              : }
     927              : 
     928              : static GEN
     929        13767 : FpX_extgcd_halfgcd(GEN x, GEN y, GEN p, GEN *ptu, GEN *ptv)
     930              : {
     931              :   GEN u, v;
     932        13767 :   GEN V = cgetg(expu(lgpol(y))+2,t_VEC);
     933        13767 :   long i, n = 0, vs = varn(x);
     934        28437 :   while (lgpol(y) >= FpX_EXTGCD_LIMIT)
     935              :   {
     936        14670 :     if (lgpol(y)<=(lgpol(x)>>1))
     937              :     {
     938            8 :       GEN r, q = FpX_divrem(x, y, p, &r);
     939            8 :       x = y; y = r;
     940            8 :       gel(V,++n) = mkmat22(pol_0(vs),pol_1(vs),pol_1(vs),FpX_neg(q,p));
     941              :     } else
     942        14662 :       gel(V,++n) = FpX_halfgcd_all(x, y, p, &x, &y);
     943              :   }
     944        13767 :   y = FpX_extgcd_basecase(x, y, p, &u, &v);
     945        14670 :   for (i = n; i>1; i--)
     946              :   {
     947          903 :     GEN R = gel(V,i);
     948          903 :     GEN u1 = FpX_addmulmul(u, v, gcoeff(R,1,1), gcoeff(R,2,1), p);
     949          903 :     GEN v1 = FpX_addmulmul(u, v, gcoeff(R,1,2), gcoeff(R,2,2), p);
     950          903 :     u = u1; v = v1;
     951              :   }
     952              :   {
     953        13767 :     GEN R = gel(V,1);
     954        13767 :     if (ptu)
     955           40 :       *ptu = FpX_addmulmul(u, v, gcoeff(R,1,1), gcoeff(R,2,1), p);
     956        13767 :     *ptv   = FpX_addmulmul(u, v, gcoeff(R,1,2), gcoeff(R,2,2), p);
     957              :   }
     958        13767 :   return y;
     959              : }
     960              : 
     961              : /* x and y in Z[X], return lift(gcd(x mod p, y mod p)). Set u and v st
     962              :  * ux + vy = gcd (mod p) */
     963              : GEN
     964      1446620 : FpX_extgcd(GEN x, GEN y, GEN p, GEN *ptu, GEN *ptv)
     965              : {
     966      1446620 :   pari_sp av = avma;
     967              :   GEN d;
     968      1446620 :   if (lgefint(p)==3)
     969              :   {
     970       861529 :     ulong pp = to_Flx(&x, &y, p);
     971       861529 :     d = Flx_extgcd(x,y, pp, ptu,ptv);
     972       861529 :     d = Flx_to_ZX(d);
     973       861529 :     if (ptu) *ptu = Flx_to_ZX(*ptu);
     974       861529 :     *ptv = Flx_to_ZX(*ptv);
     975              :   }
     976              :   else
     977              :   {
     978       585091 :     x = FpX_red(x, p);
     979       585091 :     y = FpX_red(y, p);
     980       585091 :     if (lgpol(y) >= FpX_EXTGCD_LIMIT)
     981        13767 :       d = FpX_extgcd_halfgcd(x, y, p, ptu, ptv);
     982              :     else
     983       571324 :       d = FpX_extgcd_basecase(x, y, p, ptu, ptv);
     984              :   }
     985      1446620 :   return gc_all(av, ptu?3:2, &d, ptv, ptu);
     986              : }
     987              : 
     988              : static GEN
     989          106 : FpX_halfres(GEN x, GEN y, GEN p, GEN *a, GEN *b, GEN *r)
     990              : {
     991              :   struct FpX_res res;
     992              :   GEN V;
     993              :   long dB;
     994              : 
     995          106 :   res.res  = *r;
     996          106 :   res.lc   = leading_coeff(y);
     997          106 :   res.deg0 = degpol(x);
     998          106 :   res.deg1 = degpol(y);
     999          106 :   res.off = 0;
    1000          106 :   V = FpX_halfres_i(x, y, p, a, b, &res);
    1001          106 :   dB = degpol(*b);
    1002          106 :   if (dB < degpol(y))
    1003          106 :     FpX_halfres_update(res.deg0, res.deg1, dB, p, &res);
    1004          106 :   *r = res.res;
    1005          106 :   return V;
    1006              : }
    1007              : 
    1008              : static GEN
    1009         3896 : FpX_resultant_basecase(GEN a, GEN b, GEN p)
    1010              : {
    1011         3896 :   pari_sp av = avma;
    1012              :   long da,db,dc;
    1013         3896 :   GEN c, lb, res = gen_1;
    1014              : 
    1015         3896 :   if (!signe(a) || !signe(b)) return pol_0(varn(a));
    1016              : 
    1017         3896 :   da = degpol(a);
    1018         3896 :   db = degpol(b);
    1019         3896 :   if (db > da)
    1020              :   {
    1021            0 :     swapspec(a,b, da,db);
    1022            0 :     if (both_odd(da,db)) res = subii(p, res);
    1023              :   }
    1024         3896 :   if (!da) return gc_const(av, gen_1); /* = res * a[2] ^ db, since 0 <= db <= da = 0 */
    1025        10980 :   while (db)
    1026              :   {
    1027         7084 :     lb = gel(b,db+2);
    1028         7084 :     c = FpX_rem(a,b, p);
    1029         7084 :     a = b; b = c; dc = degpol(c);
    1030         7084 :     if (dc < 0) return gc_const(av, gen_0);
    1031              : 
    1032         7084 :     if (both_odd(da,db)) res = subii(p, res);
    1033         7084 :     if (!equali1(lb)) res = Fp_mul(res, Fp_powu(lb, da - dc, p), p);
    1034         7084 :     if (gc_needed(av,2))
    1035              :     {
    1036            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FpX_resultant (da = %ld)",da);
    1037            0 :       (void)gc_all(av,3, &a,&b,&res);
    1038              :     }
    1039         7084 :     da = db; /* = degpol(a) */
    1040         7084 :     db = dc; /* = degpol(b) */
    1041              :   }
    1042         3896 :   return gc_INT(av, Fp_mul(res, Fp_powu(gel(b,2), da, p), p));
    1043              : }
    1044              : 
    1045              : GEN
    1046       416115 : FpX_resultant(GEN x, GEN y, GEN p)
    1047              : {
    1048       416115 :   pari_sp av = avma;
    1049              :   long dx, dy;
    1050       416115 :   GEN res = gen_1;
    1051       416115 :   if (!signe(x) || !signe(y)) return gen_0;
    1052       416115 :   if (lgefint(p) == 3)
    1053              :   {
    1054       412219 :     pari_sp av = avma;
    1055       412219 :     ulong pp = to_Flx(&x, &y, p);
    1056       412219 :     ulong res = Flx_resultant(x, y, pp);
    1057       412219 :     return gc_utoi(av, res);
    1058              :   }
    1059         3896 :   dx = degpol(x); dy = degpol(y);
    1060         3896 :   if (dx < dy)
    1061              :   {
    1062            0 :     swap(x,y);
    1063            0 :     if (both_odd(dx, dy))
    1064            0 :       res = Fp_neg(res, p);
    1065              :   }
    1066         3903 :   while (lgpol(y) >= FpX_GCD_LIMIT)
    1067              :   {
    1068            7 :     if (lgpol(y)<=(lgpol(x)>>1))
    1069              :     {
    1070            0 :       GEN r = FpX_rem(x, y, p);
    1071            0 :       long dx = degpol(x), dy = degpol(y), dr = degpol(r);
    1072            0 :       GEN ly = gel(y,dy+2);
    1073            0 :       if (!equali1(ly)) res = Fp_mul(res, Fp_powu(ly, dx - dr, p), p);
    1074            0 :       if (both_odd(dx, dy))
    1075            0 :         res = Fp_neg(res, p);
    1076            0 :       x = y; y = r;
    1077              :     }
    1078            7 :     (void) FpX_halfres(x, y, p, &x, &y, &res);
    1079            7 :     if (gc_needed(av,2))
    1080              :     {
    1081            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FpX_res (y = %ld)",degpol(y));
    1082            0 :       (void)gc_all(av,3,&x,&y,&res);
    1083              :     }
    1084              :   }
    1085         3896 :   return gc_INT(av, Fp_mul(res, FpX_resultant_basecase(x, y, p), p));
    1086              : }
    1087              : 
    1088              : /* If resultant is 0, *ptU and *ptV are not set */
    1089              : static GEN
    1090           24 : FpX_extresultant_basecase(GEN a, GEN b, GEN p, GEN *ptU, GEN *ptV)
    1091              : {
    1092           24 :   pari_sp av = avma;
    1093           24 :   GEN z,q,u,v, x = a, y = b;
    1094           24 :   GEN lb, res = gen_1;
    1095              :   long dx, dy, dz;
    1096           24 :   long vs = varn(a);
    1097              : 
    1098           24 :   u = pol_0(vs);
    1099           24 :   v = pol_1(vs); /* v = 1 */
    1100           24 :   dx = degpol(x);
    1101           24 :   dy = degpol(y);
    1102          281 :   while (dy)
    1103              :   { /* b u = x (a), b v = y (a) */
    1104          257 :     lb = gel(y,dy+2);
    1105          257 :     q = FpX_divrem(x,y, p, &z);
    1106          257 :     x = y; y = z; /* (x,y) = (y, x - q y) */
    1107          257 :     dz = degpol(z); if (dz < 0) return gc_const(av,gen_0);
    1108          257 :     z = FpX_sub(u, FpX_mul(q,v, p), p);
    1109          257 :     u = v; v = z; /* (u,v) = (v, u - q v) */
    1110              : 
    1111          257 :     if (both_odd(dx,dy)) res = Fp_neg(res, p);
    1112          257 :     if (!equali1(lb)) res = Fp_mul(res, Fp_powu(lb, dx-dz, p), p);
    1113          257 :     dx = dy; /* = degpol(x) */
    1114          257 :     dy = dz; /* = degpol(y) */
    1115              :   }
    1116           24 :   res = Fp_mul(res, Fp_powu(gel(y,2), dx, p), p);
    1117           24 :   lb = Fp_mul(res, Fp_inv(gel(y,2),p), p);
    1118           24 :   v = FpX_Fp_mul(v, lb, p);
    1119           24 :   u = Fp_FpX_sub(res, FpX_mul(b,v,p), p);
    1120           24 :   u = FpX_div(u,a,p); /* = (res - b v) / a */
    1121           24 :   *ptU = u;
    1122           24 :   *ptV = v;
    1123           24 :   return res;
    1124              : }
    1125              : 
    1126              : GEN
    1127           77 : FpX_extresultant(GEN x, GEN y, GEN p, GEN *ptU, GEN *ptV)
    1128              : {
    1129           77 :   pari_sp av=avma;
    1130              :   GEN u, v, R;
    1131           77 :   GEN res = gen_1, res1;
    1132           77 :   long dx = degpol(x), dy = degpol(y);
    1133           77 :   if (lgefint(p) == 3)
    1134              :   {
    1135           53 :     pari_sp av = avma;
    1136           53 :     ulong pp = to_Flx(&x, &y, p);
    1137           53 :     ulong resp = Flx_extresultant(x, y, pp, &u, &v);
    1138           53 :     if (!resp) return gc_const(av, gen_0);
    1139           53 :     res = utoi(resp);
    1140           53 :     *ptU = Flx_to_ZX(u); *ptV = Flx_to_ZX(v);
    1141           53 :     return gc_all(av, 3, &res, ptU, ptV);
    1142              :   }
    1143           24 :   if (dy > dx)
    1144              :   {
    1145            8 :     swap(x,y); lswap(dx,dy);
    1146            8 :     if (both_odd(dx,dy)) res = Fp_neg(res,p);
    1147            8 :     R = matJ2_FpXM(x[1]);
    1148           16 :   } else R = matid2_FpXM(x[1]);
    1149           24 :   if (dy < 0) return gen_0;
    1150          123 :   while (lgpol(y) >= FpX_EXTGCD_LIMIT)
    1151              :   {
    1152              :     GEN M;
    1153           99 :     if (lgpol(y)<=(lgpol(x)>>1))
    1154              :     {
    1155            8 :       GEN r, q = FpX_divrem(x, y, p, &r);
    1156            8 :       long dx = degpol(x), dy = degpol(y), dr = degpol(r);
    1157            8 :       GEN ly = gel(y,dy+2);
    1158            8 :       if (!equali1(ly)) res = Fp_mul(res, Fp_powu(ly, dx - dr, p), p);
    1159            8 :       if (both_odd(dx, dy))
    1160            0 :         res = Fp_neg(res, p);
    1161            8 :       x = y; y = r;
    1162            8 :       R = FpX_FpXM_qmul(q, R, p);
    1163              :     }
    1164           99 :     M = FpX_halfres(x, y, p, &x, &y, &res);
    1165           99 :     if (!signe(res)) return gc_const(av, gen_0);
    1166           99 :     R = FpXM_mul2(M, R, p);
    1167           99 :     (void)gc_all(av,4,&x,&y,&R,&res);
    1168              :   }
    1169           24 :   res1 = FpX_extresultant_basecase(x,y,p,&u,&v);
    1170           24 :   if (!signe(res1)) return gc_const(av, gen_0);
    1171           24 :   *ptU = FpX_Fp_mul(FpX_addmulmul(u, v, gcoeff(R,1,1), gcoeff(R,2,1), p), res, p);
    1172           24 :   *ptV = FpX_Fp_mul(FpX_addmulmul(u, v, gcoeff(R,1,2), gcoeff(R,2,2), p), res, p);
    1173           24 :   res = Fp_mul(res1,res,p);
    1174           24 :   return gc_all(av, 3, &res, ptU, ptV);
    1175              : }
    1176              : 
    1177              : GEN
    1178       179122 : FpX_rescale(GEN P, GEN h, GEN p)
    1179              : {
    1180       179122 :   long i, l = lg(P);
    1181       179122 :   GEN Q = cgetg(l,t_POL), hi = h;
    1182       179122 :   gel(Q,l-1) = gel(P,l-1);
    1183       366808 :   for (i=l-2; i>=2; i--)
    1184              :   {
    1185       366808 :     gel(Q,i) = Fp_mul(gel(P,i), hi, p);
    1186       366808 :     if (i == 2) break;
    1187       187686 :     hi = Fp_mul(hi,h, p);
    1188              :   }
    1189       179122 :   Q[1] = P[1]; return Q;
    1190              : }
    1191              : 
    1192              : GEN
    1193      1642150 : FpX_deriv(GEN x, GEN p) { return FpX_red(ZX_deriv(x), p); }
    1194              : 
    1195              : /* Compute intformal(x^n*S)/x^(n+1) */
    1196              : static GEN
    1197        55575 : FpX_integXn(GEN x, long n, GEN p)
    1198              : {
    1199        55575 :   long i, lx = lg(x);
    1200              :   GEN y;
    1201        55575 :   if (lx == 2) return ZX_copy(x);
    1202        54310 :   y = cgetg(lx, t_POL); y[1] = x[1];
    1203       193811 :   for (i=2; i<lx; i++)
    1204              :   {
    1205       139501 :     GEN xi = gel(x,i);
    1206       139501 :     if (!signe(xi))
    1207            0 :       gel(y,i) = gen_0;
    1208              :     else
    1209              :     {
    1210       139501 :       ulong j = n+i-1, d = ugcdiu(xi, j);
    1211       139501 :       if (d==1)
    1212        90022 :         gel(y,i) = Fp_divu(xi, j, p);
    1213              :       else
    1214        49479 :         gel(y,i) = Fp_divu(diviuexact(xi, d), j/d, p);
    1215              :     }
    1216              :   }
    1217        54310 :   return ZX_renormalize(y, lx);;
    1218              : }
    1219              : 
    1220              : GEN
    1221            0 : FpX_integ(GEN x, GEN p)
    1222              : {
    1223            0 :   long i, lx = lg(x);
    1224              :   GEN y;
    1225            0 :   if (lx == 2) return ZX_copy(x);
    1226            0 :   y = cgetg(lx+1, t_POL); y[1] = x[1];
    1227            0 :   gel(y,2) = gen_0;
    1228            0 :   for (i=3; i<=lx; i++)
    1229            0 :     gel(y,i) = signe(gel(x,i-1))? Fp_divu(gel(x,i-1), i-2, p): gen_0;
    1230            0 :   return ZX_renormalize(y, lx+1);;
    1231              : }
    1232              : 
    1233              : INLINE GEN
    1234       535515 : FpXn_recip(GEN P, long n)
    1235       535515 : { return RgXn_recip_shallow(P, n); }
    1236              : 
    1237              : GEN
    1238       524664 : FpX_Newton(GEN P, long n, GEN p)
    1239              : {
    1240       524664 :   pari_sp av = avma;
    1241       524664 :   GEN dP = FpX_deriv(P, p);
    1242       524664 :   GEN Q = FpXn_recip(FpX_div(FpX_shift(dP,n), P, p), n);
    1243       524664 :   return gc_GEN(av, Q);
    1244              : }
    1245              : 
    1246              : GEN
    1247        11355 : FpX_fromNewton(GEN P, GEN p)
    1248              : {
    1249        11355 :   pari_sp av = avma;
    1250        11355 :   if (lgefint(p)==3)
    1251              :   {
    1252          504 :     ulong pp = p[2];
    1253          504 :     GEN Q = Flx_fromNewton(ZX_to_Flx(P, pp), pp);
    1254          504 :     return gc_upto(av, Flx_to_ZX(Q));
    1255              :   } else
    1256              :   {
    1257        10851 :     long n = itos(modii(constant_coeff(P), p))+1;
    1258        10851 :     GEN z = FpX_neg(FpX_shift(P,-1),p);
    1259        10851 :     GEN Q = FpXn_recip(FpXn_expint(z, n, p), n);
    1260        10851 :     return gc_GEN(av, Q);
    1261              :   }
    1262              : }
    1263              : 
    1264              : GEN
    1265          186 : FpX_invLaplace(GEN x, GEN p)
    1266              : {
    1267          186 :   pari_sp av = avma;
    1268          186 :   long i, d = degpol(x);
    1269              :   GEN t, y;
    1270          186 :   if (d <= 1) return gcopy(x);
    1271          186 :   t = Fp_inv(factorial_Fp(d, p), p);
    1272          186 :   y = cgetg(d+3, t_POL);
    1273          186 :   y[1] = x[1];
    1274         2840 :   for (i=d; i>=2; i--)
    1275              :   {
    1276         2654 :     gel(y,i+2) = Fp_mul(gel(x,i+2), t, p);
    1277         2654 :     t = Fp_mulu(t, i, p);
    1278              :   }
    1279          186 :   gel(y,3) = gel(x,3);
    1280          186 :   gel(y,2) = gel(x,2);
    1281          186 :   return gc_GEN(av, y);
    1282              : }
    1283              : 
    1284              : GEN
    1285          597 : FpX_Laplace(GEN x, GEN p)
    1286              : {
    1287          597 :   pari_sp av = avma;
    1288          597 :   long i, d = degpol(x);
    1289          597 :   GEN t = gen_1;
    1290              :   GEN y;
    1291          597 :   if (d <= 1) return gcopy(x);
    1292          597 :   y = cgetg(d+3, t_POL);
    1293          597 :   y[1] = x[1];
    1294          597 :   gel(y,2) = gel(x,2);
    1295          597 :   gel(y,3) = gel(x,3);
    1296        33613 :   for (i=2; i<=d; i++)
    1297              :   {
    1298        33016 :     t = Fp_mulu(t, i, p);
    1299        33016 :     gel(y,i+2) = Fp_mul(gel(x,i+2), t, p);
    1300              :   }
    1301          597 :   return gc_GEN(av, y);
    1302              : }
    1303              : 
    1304              : int
    1305       716131 : FpX_is_squarefree(GEN f, GEN p)
    1306              : {
    1307       716131 :   pari_sp av = avma;
    1308       716131 :   GEN z = FpX_gcd(f,FpX_deriv(f,p),p);
    1309       716131 :   set_avma(av);
    1310       716131 :   return degpol(z)==0;
    1311              : }
    1312              : 
    1313              : GEN
    1314       257443 : random_FpX(long d1, long v, GEN p)
    1315              : {
    1316       257443 :   long i, d = d1+2;
    1317       257443 :   GEN y = cgetg(d,t_POL); y[1] = evalsigne(1) | evalvarn(v);
    1318       938772 :   for (i=2; i<d; i++) gel(y,i) = randomi(p);
    1319       257443 :   return FpX_renormalize(y,d);
    1320              : }
    1321              : 
    1322              : GEN
    1323        61210 : FpX_dotproduct(GEN x, GEN y, GEN p)
    1324              : {
    1325        61210 :   long i, l = minss(lg(x), lg(y));
    1326              :   pari_sp av;
    1327              :   GEN c;
    1328        61210 :   if (l == 2) return gen_0;
    1329        61133 :   av = avma; c = mulii(gel(x,2),gel(y,2));
    1330      5010527 :   for (i=3; i<l; i++) c = addii(c, mulii(gel(x,i),gel(y,i)));
    1331        61133 :   return gc_INT(av, modii(c,p));
    1332              : }
    1333              : 
    1334              : /* Evaluation in Fp
    1335              :  * x a ZX and y an Fp, return x(y) mod p
    1336              :  *
    1337              :  * If p is very large (several longs) and x has small coefficients(<<p),
    1338              :  * then Brent & Kung algorithm is faster. */
    1339              : GEN
    1340       968760 : FpX_eval(GEN x,GEN y,GEN p)
    1341              : {
    1342              :   pari_sp av;
    1343              :   GEN p1,r,res;
    1344       968760 :   long j, i=lg(x)-1;
    1345       968760 :   if (i<=2 || !signe(y))
    1346       182009 :     return (i==1)? gen_0: modii(gel(x,2),p);
    1347       786751 :   res=cgeti(lgefint(p));
    1348       786751 :   av=avma; p1=gel(x,i);
    1349              :   /* specific attention to sparse polynomials (see poleval)*/
    1350              :   /*You've guessed it! It's a copy-paste(tm)*/
    1351      3425885 :   for (i--; i>=2; i=j-1)
    1352              :   {
    1353      3717351 :     for (j=i; !signe(gel(x,j)); j--)
    1354      1078217 :       if (j==2)
    1355              :       {
    1356       162408 :         if (i!=j) y = Fp_powu(y,i-j+1,p);
    1357       162408 :         p1=mulii(p1,y);
    1358       162408 :         goto fppoleval;/*sorry break(2) no implemented*/
    1359              :       }
    1360      2639134 :     r = (i==j)? y: Fp_powu(y,i-j+1,p);
    1361      2639134 :     p1 = Fp_addmul(gel(x,j), p1, r, p);
    1362      2639134 :     if ((i & 7) == 0) { affii(p1, res); p1 = res; set_avma(av); }
    1363              :   }
    1364       624343 :  fppoleval:
    1365       786751 :   affii(modii(p1,p), res); return gc_const(av, res);
    1366              : }
    1367              : 
    1368              : /* Tz=Tx*Ty where Tx and Ty coprime
    1369              :  * return lift(chinese(Mod(x*Mod(1,p),Tx*Mod(1,p)),Mod(y*Mod(1,p),Ty*Mod(1,p))))
    1370              :  * if Tz is NULL it is computed
    1371              :  * As we do not return it, and the caller will frequently need it,
    1372              :  * it must compute it and pass it.
    1373              :  */
    1374              : GEN
    1375            0 : FpX_chinese_coprime(GEN x,GEN y,GEN Tx,GEN Ty,GEN Tz,GEN p)
    1376              : {
    1377            0 :   pari_sp av = avma;
    1378              :   GEN ax,p1;
    1379            0 :   ax = FpX_mul(FpXQ_inv(Tx,Ty,p), Tx,p);
    1380            0 :   p1 = FpX_mul(ax, FpX_sub(y,x,p),p);
    1381            0 :   p1 = FpX_add(x,p1,p);
    1382            0 :   if (!Tz) Tz=FpX_mul(Tx,Ty,p);
    1383            0 :   p1 = FpX_rem(p1,Tz,p);
    1384            0 :   return gc_upto(av,p1);
    1385              : }
    1386              : 
    1387              : /* disc P = (-1)^(n(n-1)/2) lc(P)^(n - deg P' - 2) Res(P,P'), n = deg P */
    1388              : GEN
    1389           42 : FpX_disc(GEN P, GEN p)
    1390              : {
    1391           42 :   pari_sp av = avma;
    1392           42 :   GEN L, dP = FpX_deriv(P,p), D = FpX_resultant(P, dP, p);
    1393              :   long dd;
    1394           42 :   if (!signe(D)) return gen_0;
    1395           35 :   dd = degpol(P) - 2 - degpol(dP); /* >= -1; > -1 iff p | deg(P) */
    1396           35 :   L = leading_coeff(P);
    1397           35 :   if (dd && !equali1(L))
    1398            7 :     D = (dd == -1)? Fp_div(D,L,p): Fp_mul(D, Fp_powu(L, dd, p), p);
    1399           35 :   if (degpol(P) & 2) D = Fp_neg(D, p);
    1400           35 :   return gc_INT(av, D);
    1401              : }
    1402              : 
    1403              : GEN
    1404        93571 : FpV_roots_to_pol(GEN V, GEN p, long v)
    1405              : {
    1406        93571 :   pari_sp ltop=avma;
    1407              :   long i;
    1408        93571 :   GEN g=cgetg(lg(V),t_VEC);
    1409       404737 :   for(i=1;i<lg(V);i++)
    1410       311166 :     gel(g,i) = deg1pol_shallow(gen_1,modii(negi(gel(V,i)),p),v);
    1411        93571 :   return gc_upto(ltop,FpXV_prod(g,p));
    1412              : }
    1413              : 
    1414              : /* invert all elements of x mod p using Montgomery's multi-inverse trick.
    1415              :  * Not stack-clean. */
    1416              : GEN
    1417        34342 : FpV_inv(GEN x, GEN p)
    1418              : {
    1419        34342 :   long i, lx = lg(x);
    1420        34342 :   GEN u, y = cgetg(lx, t_VEC);
    1421              : 
    1422        34342 :   gel(y,1) = gel(x,1);
    1423       473678 :   for (i=2; i<lx; i++) gel(y,i) = Fp_mul(gel(y,i-1), gel(x,i), p);
    1424              : 
    1425        34342 :   u = Fp_inv(gel(y,--i), p);
    1426       473678 :   for ( ; i > 1; i--)
    1427              :   {
    1428       439336 :     gel(y,i) = Fp_mul(u, gel(y,i-1), p);
    1429       439336 :     u = Fp_mul(u, gel(x,i), p); /* u = 1 / (x[1] ... x[i-1]) */
    1430              :   }
    1431        34342 :   gel(y,1) = u; return y;
    1432              : }
    1433              : GEN
    1434            0 : FqV_inv(GEN x, GEN T, GEN p)
    1435              : {
    1436            0 :   long i, lx = lg(x);
    1437            0 :   GEN u, y = cgetg(lx, t_VEC);
    1438              : 
    1439            0 :   gel(y,1) = gel(x,1);
    1440            0 :   for (i=2; i<lx; i++) gel(y,i) = Fq_mul(gel(y,i-1), gel(x,i), T,p);
    1441              : 
    1442            0 :   u = Fq_inv(gel(y,--i), T,p);
    1443            0 :   for ( ; i > 1; i--)
    1444              :   {
    1445            0 :     gel(y,i) = Fq_mul(u, gel(y,i-1), T,p);
    1446            0 :     u = Fq_mul(u, gel(x,i), T,p); /* u = 1 / (x[1] ... x[i-1]) */
    1447              :   }
    1448            0 :   gel(y,1) = u; return y;
    1449              : }
    1450              : 
    1451              : /***********************************************************************/
    1452              : /**                                                                   **/
    1453              : /**                      Barrett reduction                            **/
    1454              : /**                                                                   **/
    1455              : /***********************************************************************/
    1456              : 
    1457              : static GEN
    1458         4068 : FpX_invBarrett_basecase(GEN T, GEN p)
    1459              : {
    1460         4068 :   long i, l=lg(T)-1, lr = l-1, k;
    1461         4068 :   GEN r=cgetg(lr, t_POL); r[1]=T[1];
    1462         4068 :   gel(r,2) = gen_1;
    1463       231222 :   for (i=3; i<lr; i++)
    1464              :   {
    1465       227154 :     pari_sp av = avma;
    1466       227154 :     GEN u = gel(T,l-i+2);
    1467      7205610 :     for (k=3; k<i; k++)
    1468      6978456 :       u = addii(u, mulii(gel(T,l-i+k), gel(r,k)));
    1469       227154 :     gel(r,i) = gc_upto(av, modii(negi(u), p));
    1470              :   }
    1471         4068 :   return FpX_renormalize(r,lr);
    1472              : }
    1473              : 
    1474              : /* Return new lgpol */
    1475              : static long
    1476      1663019 : ZX_lgrenormalizespec(GEN x, long lx)
    1477              : {
    1478              :   long i;
    1479      2030927 :   for (i = lx-1; i>=0; i--)
    1480      2030927 :     if (signe(gel(x,i))) break;
    1481      1663019 :   return i+1;
    1482              : }
    1483              : 
    1484              : INLINE GEN
    1485      1637874 : FpX_recipspec(GEN x, long l, long n)
    1486              : {
    1487      1637874 :   return RgX_recipspec_shallow(x, l, n);
    1488              : }
    1489              : 
    1490              : static GEN
    1491         1520 : FpX_invBarrett_Newton(GEN T, GEN p)
    1492              : {
    1493         1520 :   pari_sp av = avma;
    1494         1520 :   long nold, lx, lz, lq, l = degpol(T), i, lQ;
    1495         1520 :   GEN q, y, z, x = cgetg(l+2, t_POL) + 2;
    1496         1520 :   ulong mask = quadratic_prec_mask(l-2); /* assume l > 2 */
    1497       599872 :   for (i=0;i<l;i++) gel(x,i) = gen_0;
    1498         1520 :   q = FpX_recipspec(T+2,l+1,l+1); lQ = lgpol(q); q+=2;
    1499              :   /* We work on _spec_ FpX's, all the l[xzq] below are lgpol's */
    1500              : 
    1501              :   /* initialize */
    1502         1520 :   gel(x,0) = Fp_inv(gel(q,0), p);
    1503         1520 :   if (lQ>1) gel(q,1) = Fp_red(gel(q,1), p);
    1504         1520 :   if (lQ>1 && signe(gel(q,1)))
    1505         1133 :   {
    1506         1133 :     GEN u = gel(q, 1);
    1507         1133 :     if (!equali1(gel(x,0))) u = Fp_mul(u, Fp_sqr(gel(x,0), p), p);
    1508         1133 :     gel(x,1) = Fp_neg(u, p); lx = 2;
    1509              :   }
    1510              :   else
    1511          387 :     lx = 1;
    1512         1520 :   nold = 1;
    1513        13692 :   for (; mask > 1; )
    1514              :   { /* set x -= x(x*q - 1) + O(t^(nnew + 1)), knowing x*q = 1 + O(t^(nold+1)) */
    1515        12172 :     long i, lnew, nnew = nold << 1;
    1516              : 
    1517        12172 :     if (mask & 1) nnew--;
    1518        12172 :     mask >>= 1;
    1519              : 
    1520        12172 :     lnew = nnew + 1;
    1521        12172 :     lq = ZX_lgrenormalizespec(q, minss(lQ,lnew));
    1522        12172 :     z = FpX_mulspec(x, q, p, lx, lq); /* FIXME: high product */
    1523        12172 :     lz = lgpol(z); if (lz > lnew) lz = lnew;
    1524        12172 :     z += 2;
    1525              :     /* subtract 1 [=>first nold words are 0]: renormalize so that z(0) != 0 */
    1526        84347 :     for (i = nold; i < lz; i++) if (signe(gel(z,i))) break;
    1527        12172 :     nold = nnew;
    1528        12172 :     if (i >= lz) continue; /* z-1 = 0(t^(nnew + 1)) */
    1529              : 
    1530              :     /* z + i represents (x*q - 1) / t^i */
    1531         9629 :     lz = ZX_lgrenormalizespec (z+i, lz-i);
    1532         9629 :     z = FpX_mulspec(x, z+i, p, lx, lz); /* FIXME: low product */
    1533         9629 :     lz = lgpol(z); z += 2;
    1534         9629 :     if (lz > lnew-i) lz = ZX_lgrenormalizespec(z, lnew-i);
    1535              : 
    1536         9629 :     lx = lz+ i;
    1537         9629 :     y  = x + i; /* x -= z * t^i, in place */
    1538       433611 :     for (i = 0; i < lz; i++) gel(y,i) = Fp_neg(gel(z,i), p);
    1539              :   }
    1540         1520 :   x -= 2; setlg(x, lx + 2); x[1] = T[1];
    1541         1520 :   return gc_GEN(av, x);
    1542              : }
    1543              : 
    1544              : /* 1/polrecip(T)+O(x^(deg(T)-1)) */
    1545              : GEN
    1546         5641 : FpX_invBarrett(GEN T, GEN p)
    1547              : {
    1548         5641 :   pari_sp ltop = avma;
    1549         5641 :   long l = lg(T);
    1550              :   GEN r;
    1551         5641 :   if (l<5) return pol_0(varn(T));
    1552         5588 :   if (l<=FpX_INVBARRETT_LIMIT)
    1553              :   {
    1554         4068 :     GEN c = gel(T,l-1), ci=gen_1;
    1555         4068 :     if (!equali1(c))
    1556              :     {
    1557           14 :       ci = Fp_inv(c, p);
    1558           14 :       T = FpX_Fp_mul(T, ci, p);
    1559           14 :       r = FpX_invBarrett_basecase(T, p);
    1560           14 :       r = FpX_Fp_mul(r, ci, p);
    1561              :     } else
    1562         4054 :       r = FpX_invBarrett_basecase(T, p);
    1563              :   }
    1564              :   else
    1565         1520 :     r = FpX_invBarrett_Newton(T, p);
    1566         5588 :   return gc_upto(ltop, r);
    1567              : }
    1568              : 
    1569              : GEN
    1570      1647055 : FpX_get_red(GEN T, GEN p)
    1571              : {
    1572      1647055 :   if (typ(T)==t_POL && lg(T)>FpX_BARRETT_LIMIT)
    1573         4765 :     retmkvec2(FpX_invBarrett(T,p),T);
    1574      1642290 :   return T;
    1575              : }
    1576              : 
    1577              : /* Compute x mod T where 2 <= degpol(T) <= l+1 <= 2*(degpol(T)-1)
    1578              :  * and mg is the Barrett inverse of T. */
    1579              : static GEN
    1580       815988 : FpX_divrem_Barrettspec(GEN x, long l, GEN mg, GEN T, GEN p, GEN *pr)
    1581              : {
    1582              :   GEN q, r;
    1583       815988 :   long lt = degpol(T); /*We discard the leading term*/
    1584              :   long ld, lm, lT, lmg;
    1585       815988 :   ld = l-lt;
    1586       815988 :   lm = minss(ld, lgpol(mg));
    1587       815988 :   lT  = ZX_lgrenormalizespec(T+2,lt);
    1588       815988 :   lmg = ZX_lgrenormalizespec(mg+2,lm);
    1589       815988 :   q = FpX_recipspec(x+lt,ld,ld);              /* q = rec(x)     lq<=ld*/
    1590       815988 :   q = FpX_mulspec(q+2,mg+2,p,lgpol(q),lmg);    /* q = rec(x) * mg lq<=ld+lm*/
    1591       815988 :   q = FpX_recipspec(q+2,minss(ld,lgpol(q)),ld);/* q = rec (rec(x) * mg) lq<=ld*/
    1592       815988 :   if (!pr) return q;
    1593       815988 :   r = FpX_mulspec(q+2,T+2,p,lgpol(q),lT);      /* r = q*pol        lr<=ld+lt*/
    1594       815988 :   r = FpX_subspec(x,r+2,p,lt,minss(lt,lgpol(r)));/* r = x - r   lr<=lt */
    1595       815988 :   if (pr == ONLY_REM) return r;
    1596         1418 :   *pr = r; return q;
    1597              : }
    1598              : 
    1599              : static GEN
    1600       815167 : FpX_divrem_Barrett(GEN x, GEN mg, GEN T, GEN p, GEN *pr)
    1601              : {
    1602       815167 :   GEN q = NULL, r = FpX_red(x, p);
    1603       815167 :   long l = lgpol(r), lt = degpol(T), lm = 2*lt-1, v = varn(T);
    1604              :   long i;
    1605       815167 :   if (l <= lt)
    1606              :   {
    1607            0 :     if (pr == ONLY_REM) return r;
    1608            0 :     if (pr == ONLY_DIVIDES) return signe(r)? NULL: pol_0(v);
    1609            0 :     if (pr) *pr = r;
    1610            0 :     return pol_0(v);
    1611              :   }
    1612       815167 :   if (lt <= 1)
    1613           53 :     return FpX_divrem_basecase(r,T,p,pr);
    1614       815114 :   if (pr != ONLY_REM && l>lm)
    1615              :   {
    1616          510 :     q = cgetg(l-lt+2, t_POL); q[1] = T[1];
    1617       905606 :     for (i=0;i<l-lt;i++) gel(q+2,i) = gen_0;
    1618              :   }
    1619       815989 :   while (l>lm)
    1620              :   {
    1621          875 :     GEN zr, zq = FpX_divrem_Barrettspec(r+2+l-lm,lm,mg,T,p,&zr);
    1622          875 :     long lz = lgpol(zr);
    1623          875 :     if (pr != ONLY_REM)
    1624              :     {
    1625          639 :       long lq = lgpol(zq);
    1626       465354 :       for(i=0; i<lq; i++) gel(q+2+l-lm,i) = gel(zq,2+i);
    1627              :     }
    1628       481431 :     for(i=0; i<lz; i++) gel(r+2+l-lm,i) = gel(zr,2+i);
    1629          875 :     l = l-lm+lz;
    1630              :   }
    1631       815114 :   if (pr == ONLY_REM)
    1632              :   {
    1633       814570 :     if (l > lt)
    1634       814570 :       r = FpX_divrem_Barrettspec(r+2, l, mg, T, p, ONLY_REM);
    1635              :     else
    1636            0 :       r = FpX_renormalize(r, l+2);
    1637       814570 :     setvarn(r, v); return r;
    1638              :   }
    1639          544 :   if (l > lt)
    1640              :   {
    1641          543 :     GEN zq = FpX_divrem_Barrettspec(r+2,l,mg,T,p, pr? &r: NULL);
    1642          543 :     if (!q) q = zq;
    1643              :     else
    1644              :     {
    1645          509 :       long lq = lgpol(zq);
    1646       440509 :       for(i=0; i<lq; i++) gel(q+2,i) = gel(zq,2+i);
    1647              :     }
    1648              :   }
    1649            1 :   else if (pr)
    1650            1 :     r = FpX_renormalize(r, l+2);
    1651          544 :   setvarn(q, v); q = FpX_renormalize(q, lg(q));
    1652          544 :   if (pr == ONLY_DIVIDES) return signe(r)? NULL: q;
    1653          544 :   if (pr) { setvarn(r, v); *pr = r; }
    1654          544 :   return q;
    1655              : }
    1656              : 
    1657              : GEN
    1658     14545170 : FpX_divrem(GEN x, GEN T, GEN p, GEN *pr)
    1659              : {
    1660              :   GEN B, y;
    1661              :   long dy, dx, d;
    1662     14545170 :   if (pr==ONLY_REM) return FpX_rem(x, T, p);
    1663     14545170 :   y = get_FpX_red(T, &B);
    1664     14545170 :   dy = degpol(y); dx = degpol(x); d = dx-dy;
    1665     14545170 :   if (!B && d+3 < FpX_DIVREM_BARRETT_LIMIT)
    1666     14543068 :     return FpX_divrem_basecase(x,y,p,pr);
    1667         2102 :   else if (lgefint(p)==3)
    1668              :   {
    1669         1525 :     pari_sp av = avma;
    1670         1525 :     ulong pp = to_Flxq(&x, &T, p);
    1671         1525 :     GEN z = Flx_divrem(x, T, pp, pr);
    1672         1525 :     if (!z) return gc_NULL(av);
    1673         1525 :     if (!pr || pr == ONLY_DIVIDES)
    1674          209 :       return Flx_to_ZX_inplace(gc_leaf(av, z));
    1675         1316 :     z = Flx_to_ZX(z);
    1676         1316 :     *pr = Flx_to_ZX(*pr);
    1677         1316 :     return gc_all(av, 2, &z, pr);
    1678              :   } else
    1679              :   {
    1680          577 :     pari_sp av = avma;
    1681          577 :     GEN mg = B? B: FpX_invBarrett(y, p);
    1682          577 :     GEN z = FpX_divrem_Barrett(x,mg,y,p,pr);
    1683          577 :     if (!z) return gc_NULL(av);
    1684          577 :     if (!pr || pr==ONLY_DIVIDES) return gc_GEN(av, z);
    1685          577 :     return gc_all(av, 2, &z, pr);
    1686              :   }
    1687              : }
    1688              : 
    1689              : GEN
    1690     72539348 : FpX_rem(GEN x, GEN T, GEN p)
    1691              : {
    1692     72539348 :   GEN B, y = get_FpX_red(T, &B);
    1693     72539348 :   long dy = degpol(y), dx = degpol(x), d = dx-dy;
    1694     72539348 :   if (d < 0) return FpX_red(x,p);
    1695     53140120 :   if (!B && d+3 < FpX_REM_BARRETT_LIMIT)
    1696     52284327 :     return FpX_divrem_basecase(x,y,p,ONLY_REM);
    1697       855793 :   else if (lgefint(p)==3)
    1698              :   {
    1699        41203 :     pari_sp av = avma;
    1700        41203 :     ulong pp = to_Flxq(&x, &T, p);
    1701        41203 :     return Flx_to_ZX_inplace(gc_leaf(av, Flx_rem(x, T, pp)));
    1702              :   } else
    1703              :   {
    1704       814590 :     pari_sp av = avma;
    1705       814590 :     GEN mg = B? B: FpX_invBarrett(y, p);
    1706       814590 :     return gc_upto(av, FpX_divrem_Barrett(x, mg, y, p, ONLY_REM));
    1707              :   }
    1708              : }
    1709              : 
    1710              : static GEN
    1711        32503 : FpXV_producttree_dbl(GEN t, long n, GEN p)
    1712              : {
    1713        32503 :   long i, j, k, m = n==1 ? 1: expu(n-1)+1;
    1714        32503 :   GEN T = cgetg(m+1, t_VEC);
    1715        32503 :   gel(T,1) = t;
    1716        64215 :   for (i=2; i<=m; i++)
    1717              :   {
    1718        31712 :     GEN u = gel(T, i-1);
    1719        31712 :     long n = lg(u)-1;
    1720        31712 :     GEN t = cgetg(((n+1)>>1)+1, t_VEC);
    1721       103576 :     for (j=1, k=1; k<n; j++, k+=2)
    1722        71864 :       gel(t, j) = FpX_mul(gel(u, k), gel(u, k+1), p);
    1723        31712 :     gel(T, i) = t;
    1724              :   }
    1725        32503 :   return T;
    1726              : }
    1727              : 
    1728              : static GEN
    1729        31915 : FpV_producttree(GEN xa, GEN s, GEN p, long vs)
    1730              : {
    1731        31915 :   long n = lg(xa)-1;
    1732        31915 :   long j, k, ls = lg(s);
    1733        31915 :   GEN t = cgetg(ls, t_VEC);
    1734       133426 :   for (j=1, k=1; j<ls; k+=s[j++])
    1735       101511 :     gel(t, j) = s[j] == 1 ?
    1736       101511 :              deg1pol_shallow(gen_1, Fp_neg(gel(xa,k), p), vs):
    1737        62787 :              deg2pol_shallow(gen_1,
    1738        62787 :                Fp_neg(Fp_add(gel(xa,k), gel(xa,k+1), p), p),
    1739        62787 :                Fp_mul(gel(xa,k), gel(xa,k+1), p), vs);
    1740        31915 :   return FpXV_producttree_dbl(t, n, p);
    1741              : }
    1742              : 
    1743              : static GEN
    1744        32503 : FpX_FpXV_multirem_dbl_tree(GEN P, GEN T, GEN p)
    1745              : {
    1746              :   long i,j,k;
    1747        32503 :   long m = lg(T)-1;
    1748              :   GEN t;
    1749        32503 :   GEN Tp = cgetg(m+1, t_VEC);
    1750        32503 :   gel(Tp, m) = mkvec(P);
    1751        64215 :   for (i=m-1; i>=1; i--)
    1752              :   {
    1753        31712 :     GEN u = gel(T, i);
    1754        31712 :     GEN v = gel(Tp, i+1);
    1755        31712 :     long n = lg(u)-1;
    1756        31712 :     t = cgetg(n+1, t_VEC);
    1757       103576 :     for (j=1, k=1; k<n; j++, k+=2)
    1758              :     {
    1759        71864 :       gel(t, k)   = FpX_rem(gel(v, j), gel(u, k), p);
    1760        71864 :       gel(t, k+1) = FpX_rem(gel(v, j), gel(u, k+1), p);
    1761              :     }
    1762        31712 :     gel(Tp, i) = t;
    1763              :   }
    1764        32503 :   return Tp;
    1765              : }
    1766              : 
    1767              : static GEN
    1768        31915 : FpX_FpV_multieval_tree(GEN P, GEN xa, GEN T, GEN p)
    1769              : {
    1770        31915 :   pari_sp av = avma;
    1771              :   long j,k;
    1772        31915 :   GEN Tp = FpX_FpXV_multirem_dbl_tree(P, T, p);
    1773        31915 :   GEN R = cgetg(lg(xa), t_VEC);
    1774        31915 :   GEN u = gel(T, 1);
    1775        31915 :   GEN v = gel(Tp, 1);
    1776        31915 :   long n = lg(u)-1;
    1777       133426 :   for (j=1, k=1; j<=n; j++)
    1778              :   {
    1779       101511 :     long c, d = degpol(gel(u,j));
    1780       265809 :     for (c=1; c<=d; c++, k++)
    1781       164298 :       gel(R,k) = FpX_eval(gel(v, j), gel(xa,k), p);
    1782              :   }
    1783        31915 :   return gc_upto(av, R);
    1784              : }
    1785              : 
    1786              : static GEN
    1787           15 : FpVV_polint_tree(GEN T, GEN R, GEN s, GEN xa, GEN ya, GEN p, long vs)
    1788              : {
    1789           15 :   pari_sp av = avma;
    1790           15 :   long m = lg(T)-1;
    1791           15 :   long i, j, k, ls = lg(s);
    1792           15 :   GEN Tp = cgetg(m+1, t_VEC);
    1793           15 :   GEN t = cgetg(ls, t_VEC);
    1794          241 :   for (j=1, k=1; j<ls; k+=s[j++])
    1795          226 :     if (s[j]==2)
    1796              :     {
    1797           58 :       GEN a = Fp_mul(gel(ya,k), gel(R,k), p);
    1798           58 :       GEN b = Fp_mul(gel(ya,k+1), gel(R,k+1), p);
    1799           58 :       gel(t, j) = deg1pol_shallow(Fp_add(a, b, p),
    1800           58 :               Fp_neg(Fp_add(Fp_mul(gel(xa,k), b, p ),
    1801           58 :               Fp_mul(gel(xa,k+1), a, p), p), p), vs);
    1802              :     }
    1803              :     else
    1804          168 :       gel(t, j) = scalarpol(Fp_mul(gel(ya,k), gel(R,k), p), vs);
    1805           15 :   gel(Tp, 1) = t;
    1806           72 :   for (i=2; i<=m; i++)
    1807              :   {
    1808           57 :     GEN u = gel(T, i-1);
    1809           57 :     GEN t = cgetg(lg(gel(T,i)), t_VEC);
    1810           57 :     GEN v = gel(Tp, i-1);
    1811           57 :     long n = lg(v)-1;
    1812          268 :     for (j=1, k=1; k<n; j++, k+=2)
    1813          211 :       gel(t, j) = FpX_add(ZX_mul(gel(u, k), gel(v, k+1)),
    1814          211 :                           ZX_mul(gel(u, k+1), gel(v, k)), p);
    1815           57 :     gel(Tp, i) = t;
    1816              :   }
    1817           15 :   return gc_GEN(av, gmael(Tp,m,1));
    1818              : }
    1819              : 
    1820              : GEN
    1821            0 : FpX_FpV_multieval(GEN P, GEN xa, GEN p)
    1822              : {
    1823            0 :   pari_sp av = avma;
    1824            0 :   GEN s = producttree_scheme(lg(xa)-1);
    1825            0 :   GEN T = FpV_producttree(xa, s, p, varn(P));
    1826            0 :   return gc_upto(av, FpX_FpV_multieval_tree(P, xa, T, p));
    1827              : }
    1828              : 
    1829              : GEN
    1830           22 : FpV_polint(GEN xa, GEN ya, GEN p, long vs)
    1831              : {
    1832           22 :   pari_sp av = avma;
    1833              :   GEN s, T, P, R;
    1834              :   long m;
    1835           22 :   if (lgefint(p) == 3)
    1836              :   {
    1837            7 :     ulong pp = p[2];
    1838            7 :     P = Flv_polint(ZV_to_Flv(xa, pp), ZV_to_Flv(ya, pp), pp, evalvarn(vs));
    1839            7 :     return gc_upto(av, Flx_to_ZX(P));
    1840              :   }
    1841           15 :   s = producttree_scheme(lg(xa)-1);
    1842           15 :   T = FpV_producttree(xa, s, p, vs);
    1843           15 :   m = lg(T)-1;
    1844           15 :   P = FpX_deriv(gmael(T, m, 1), p);
    1845           15 :   R = FpV_inv(FpX_FpV_multieval_tree(P, xa, T, p), p);
    1846           15 :   return gc_upto(av, FpVV_polint_tree(T, R, s, xa, ya, p, vs));
    1847              : }
    1848              : 
    1849              : GEN
    1850            0 : FpV_FpM_polint(GEN xa, GEN ya, GEN p, long vs)
    1851              : {
    1852            0 :   pari_sp av = avma;
    1853            0 :   GEN s = producttree_scheme(lg(xa)-1);
    1854            0 :   GEN T = FpV_producttree(xa, s, p, vs);
    1855            0 :   long i, m = lg(T)-1, l = lg(ya)-1;
    1856            0 :   GEN P = FpX_deriv(gmael(T, m, 1), p);
    1857            0 :   GEN R = FpV_inv(FpX_FpV_multieval_tree(P, xa, T, p), p);
    1858            0 :   GEN M = cgetg(l+1, t_VEC);
    1859            0 :   for (i=1; i<=l; i++)
    1860            0 :     gel(M,i) = FpVV_polint_tree(T, R, s, xa, gel(ya,i), p, vs);
    1861            0 :   return gc_upto(av, M);
    1862              : }
    1863              : 
    1864              : GEN
    1865        31900 : FpV_invVandermonde(GEN L, GEN den, GEN p)
    1866              : {
    1867        31900 :   pari_sp av = avma;
    1868        31900 :   long i, n = lg(L);
    1869              :   GEN M, R;
    1870        31900 :   GEN s = producttree_scheme(n-1);
    1871        31900 :   GEN tree = FpV_producttree(L, s, p, 0);
    1872        31900 :   long m = lg(tree)-1;
    1873        31900 :   GEN T = gmael(tree, m, 1);
    1874        31900 :   R = FpV_inv(FpX_FpV_multieval_tree(FpX_deriv(T, p), L, tree, p), p);
    1875        31900 :   if (den) R = FpC_Fp_mul(R, den, p);
    1876        31900 :   M = cgetg(n, t_MAT);
    1877       195914 :   for (i = 1; i < n; i++)
    1878              :   {
    1879       164014 :     GEN P = FpX_Fp_mul(FpX_div_by_X_x(T, gel(L,i), p, NULL), gel(R,i), p);
    1880       164014 :     gel(M,i) = RgX_to_RgC(P, n-1);
    1881              :   }
    1882        31900 :   return gc_GEN(av, M);
    1883              : }
    1884              : 
    1885              : static GEN
    1886          588 : FpXV_producttree(GEN xa, GEN s, GEN p)
    1887              : {
    1888          588 :   long n = lg(xa)-1;
    1889          588 :   long j, k, ls = lg(s);
    1890          588 :   GEN t = cgetg(ls, t_VEC);
    1891         3444 :   for (j=1, k=1; j<ls; k+=s[j++])
    1892         2856 :     gel(t, j) = s[j] == 1 ?
    1893         2856 :              gel(xa,k): FpX_mul(gel(xa,k),gel(xa,k+1),p);
    1894          588 :   return FpXV_producttree_dbl(t, n, p);
    1895              : }
    1896              : 
    1897              : static GEN
    1898          588 : FpX_FpXV_multirem_tree(GEN P, GEN xa, GEN T, GEN s, GEN p)
    1899              : {
    1900          588 :   pari_sp av = avma;
    1901          588 :   long j, k, ls = lg(s);
    1902          588 :   GEN Tp = FpX_FpXV_multirem_dbl_tree(P, T, p);
    1903          588 :   GEN R = cgetg(lg(xa), t_VEC);
    1904          588 :   GEN v = gel(Tp, 1);
    1905         3444 :   for (j=1, k=1; j<ls; k+=s[j++])
    1906              :   {
    1907         2856 :     gel(R,k) = FpX_rem(gel(v, j), gel(xa,k), p);
    1908         2856 :     if (s[j] == 2)
    1909         1050 :       gel(R,k+1) = FpX_rem(gel(v, j), gel(xa,k+1), p);
    1910              :   }
    1911          588 :   return gc_upto(av, R);
    1912              : }
    1913              : 
    1914              : GEN
    1915            0 : FpX_FpXV_multirem(GEN P, GEN xa, GEN p)
    1916              : {
    1917            0 :   pari_sp av = avma;
    1918            0 :   GEN s = producttree_scheme(lg(xa)-1);
    1919            0 :   GEN T = FpXV_producttree(xa, s, p);
    1920            0 :   return gc_upto(av, FpX_FpXV_multirem_tree(P, xa, T, s, p));
    1921              : }
    1922              : 
    1923              : /* T = ZV_producttree(P), R = ZV_chinesetree(P,T) */
    1924              : static GEN
    1925          588 : FpXV_chinese_tree(GEN A, GEN P, GEN T, GEN R, GEN s, GEN p)
    1926              : {
    1927          588 :   long m = lg(T)-1, ls = lg(s);
    1928              :   long i,j,k;
    1929          588 :   GEN Tp = cgetg(m+1, t_VEC);
    1930          588 :   GEN M = gel(T, 1);
    1931          588 :   GEN t = cgetg(lg(M), t_VEC);
    1932         3444 :   for (j=1, k=1; j<ls; k+=s[j++])
    1933         2856 :     if (s[j] == 2)
    1934              :     {
    1935         1050 :       pari_sp av = avma;
    1936         1050 :       GEN a = FpX_mul(gel(A,k), gel(R,k), p), b = FpX_mul(gel(A,k+1), gel(R,k+1), p);
    1937         1050 :       GEN tj = FpX_rem(FpX_add(FpX_mul(gel(P,k), b, p),
    1938         1050 :             FpX_mul(gel(P,k+1), a, p), p), gel(M,j), p);
    1939         1050 :       gel(t, j) = gc_upto(av, tj);
    1940              :     }
    1941              :     else
    1942         1806 :       gel(t, j) = FpX_rem(FpX_mul(gel(A,k), gel(R,k), p), gel(M, j), p);
    1943          588 :   gel(Tp, 1) = t;
    1944         1890 :   for (i=2; i<=m; i++)
    1945              :   {
    1946         1302 :     GEN u = gel(T, i-1), M = gel(T, i);
    1947         1302 :     GEN t = cgetg(lg(M), t_VEC);
    1948         1302 :     GEN v = gel(Tp, i-1);
    1949         1302 :     long n = lg(v)-1;
    1950         3570 :     for (j=1, k=1; k<n; j++, k+=2)
    1951              :     {
    1952         2268 :       pari_sp av = avma;
    1953         2268 :       gel(t, j) = gc_upto(av, FpX_rem(FpX_add(FpX_mul(gel(u, k), gel(v, k+1), p),
    1954         2268 :               FpX_mul(gel(u, k+1), gel(v, k), p), p), gel(M, j), p));
    1955              :     }
    1956         1302 :     if (k==n) gel(t, j) = gel(v, k);
    1957         1302 :     gel(Tp, i) = t;
    1958              :   }
    1959          588 :   return gmael(Tp,m,1);
    1960              : }
    1961              : 
    1962              : static GEN
    1963          588 : FpXV_sqr(GEN x, GEN p)
    1964         4494 : { pari_APPLY_type(t_VEC, FpX_sqr(gel(x,i), p)) }
    1965              : 
    1966              : static GEN
    1967         7602 : FpXT_sqr(GEN x, GEN p)
    1968              : {
    1969         7602 :   if (typ(x) == t_POL)
    1970         5124 :     return FpX_sqr(x, p);
    1971         9492 :   pari_APPLY_type(t_VEC, FpXT_sqr(gel(x,i), p))
    1972              : }
    1973              : 
    1974              : static GEN
    1975          588 : FpXV_invdivexact(GEN x, GEN y, GEN p)
    1976         4494 : { pari_APPLY_type(t_VEC, FpXQ_inv(FpX_div(gel(x,i), gel(y,i),p), gel(y,i),p)) }
    1977              : 
    1978              : static GEN
    1979          588 : FpXV_chinesetree(GEN P, GEN T, GEN s, GEN p)
    1980              : {
    1981          588 :   GEN T2 = FpXT_sqr(T, p), P2 = FpXV_sqr(P, p);
    1982          588 :   GEN mod = gmael(T,lg(T)-1,1);
    1983          588 :   return FpXV_invdivexact(FpX_FpXV_multirem_tree(mod, P2, T2, s, p), P, p);
    1984              : }
    1985              : 
    1986              : static GEN
    1987          588 : gc_chinese(pari_sp av, GEN T, GEN a, GEN *pt_mod)
    1988              : {
    1989          588 :   if (!pt_mod)
    1990          588 :     return gc_upto(av, a);
    1991              :   else
    1992              :   {
    1993            0 :     GEN mod = gmael(T, lg(T)-1, 1);
    1994            0 :     (void)gc_all(av, 2, &a, &mod);
    1995            0 :     *pt_mod = mod;
    1996            0 :     return a;
    1997              :   }
    1998              : }
    1999              : 
    2000              : GEN
    2001          588 : FpXV_chinese(GEN A, GEN P, GEN p, GEN *pt_mod)
    2002              : {
    2003          588 :   pari_sp av = avma;
    2004          588 :   GEN s = producttree_scheme(lg(P)-1);
    2005          588 :   GEN T = FpXV_producttree(P, s, p);
    2006          588 :   GEN R = FpXV_chinesetree(P, T, s, p);
    2007          588 :   GEN a = FpXV_chinese_tree(A, P, T, R, s, p);
    2008          588 :   return gc_chinese(av, T, a, pt_mod);
    2009              : }
    2010              : 
    2011              : /***********************************************************************/
    2012              : /**                                                                   **/
    2013              : /**                              FpXQ                                 **/
    2014              : /**                                                                   **/
    2015              : /***********************************************************************/
    2016              : 
    2017              : /* FpXQ are elements of Fp[X]/(T), represented by FpX*/
    2018              : 
    2019              : GEN
    2020     17465980 : FpXQ_red(GEN x, GEN T, GEN p)
    2021              : {
    2022     17465980 :   GEN z = FpX_red(x,p);
    2023     17465980 :   return FpX_rem(z, T,p);
    2024              : }
    2025              : 
    2026              : GEN
    2027     13217252 : FpXQ_mul(GEN x,GEN y,GEN T,GEN p)
    2028              : {
    2029     13217252 :   GEN z = FpX_mul(x,y,p);
    2030     13217252 :   return FpX_rem(z, T, p);
    2031              : }
    2032              : 
    2033              : GEN
    2034      6339090 : FpXQ_sqr(GEN x, GEN T, GEN p)
    2035              : {
    2036      6339090 :   GEN z = FpX_sqr(x,p);
    2037      6339090 :   return FpX_rem(z, T, p);
    2038              : }
    2039              : 
    2040              : /* Inverse of x in Z/pZ[X]/(pol) or NULL if inverse doesn't exist
    2041              :  * return lift(1 / (x mod (p,pol))) */
    2042              : GEN
    2043      1098685 : FpXQ_invsafe(GEN x, GEN y, GEN p)
    2044              : {
    2045      1098685 :   GEN V, z = FpX_extgcd(get_FpX_mod(y), x, p, NULL, &V);
    2046      1098685 :   if (degpol(z)) return NULL;
    2047      1098685 :   z = Fp_invsafe(gel(z,2), p);
    2048      1098685 :   if (!z) return NULL;
    2049      1098685 :   return FpX_Fp_mul(V, z, p);
    2050              : }
    2051              : 
    2052              : GEN
    2053      1098685 : FpXQ_inv(GEN x,GEN T,GEN p)
    2054              : {
    2055      1098685 :   pari_sp av = avma;
    2056      1098685 :   GEN U = FpXQ_invsafe(x, T, p);
    2057      1098685 :   if (!U) pari_err_INV("FpXQ_inv",x);
    2058      1098685 :   return gc_upto(av, U);
    2059              : }
    2060              : 
    2061              : GEN
    2062       530672 : FpXQ_div(GEN x,GEN y,GEN T,GEN p)
    2063              : {
    2064       530672 :   pari_sp av = avma;
    2065       530672 :   return gc_upto(av, FpXQ_mul(x,FpXQ_inv(y,T,p),T,p));
    2066              : }
    2067              : 
    2068              : static GEN
    2069            0 : _FpXQ_add(void *data, GEN x, GEN y)
    2070              : {
    2071              :   (void) data;
    2072            0 :   return ZX_add(x, y);
    2073              : }
    2074              : static GEN
    2075        52941 : _FpXQ_sub(void *data, GEN x, GEN y)
    2076              : {
    2077              :   (void) data;
    2078        52941 :   return ZX_sub(x, y);
    2079              : }
    2080              : static GEN
    2081      5842719 : _FpXQ_sqr(void *data, GEN x)
    2082              : {
    2083      5842719 :   struct _FpXQ *D = (struct _FpXQ*)data;
    2084      5842719 :   return FpXQ_sqr(x, D->T, D->p);
    2085              : }
    2086              : static GEN
    2087      2714559 : _FpXQ_mul(void *data, GEN x, GEN y)
    2088              : {
    2089      2714559 :   struct _FpXQ *D = (struct _FpXQ*)data;
    2090      2714559 :   return FpXQ_mul(x,y, D->T, D->p);
    2091              : }
    2092              : static GEN
    2093         3360 : _FpXQ_zero(void *data)
    2094              : {
    2095         3360 :   struct _FpXQ *D = (struct _FpXQ*)data;
    2096         3360 :   return pol_0(get_FpX_var(D->T));
    2097              : }
    2098              : static GEN
    2099       219417 : _FpXQ_one(void *data)
    2100              : {
    2101       219417 :   struct _FpXQ *D = (struct _FpXQ*)data;
    2102       219417 :   return pol_1(get_FpX_var(D->T));
    2103              : }
    2104              : static GEN
    2105        16233 : _FpXQ_red(void *data, GEN x)
    2106              : {
    2107        16233 :   struct _FpXQ *D = (struct _FpXQ*)data;
    2108        16233 :   return FpX_red(x,D->p);
    2109              : }
    2110              : 
    2111              : static struct bb_algebra FpXQ_algebra = { _FpXQ_red, _FpXQ_add, _FpXQ_sub,
    2112              :        _FpXQ_mul, _FpXQ_sqr, _FpXQ_one, _FpXQ_zero };
    2113              : 
    2114              : const struct bb_algebra *
    2115        10199 : get_FpXQ_algebra(void **E, GEN T, GEN p)
    2116              : {
    2117        10199 :   GEN z = new_chunk(sizeof(struct _FpXQ));
    2118        10199 :   struct _FpXQ *e = (struct _FpXQ *) z;
    2119        10199 :   e->T = FpX_get_red(T, p);
    2120        10199 :   e->p  = p; *E = (void*)e;
    2121        10199 :   return &FpXQ_algebra;
    2122              : }
    2123              : 
    2124              : static GEN
    2125            0 : _FpX_red(void *E, GEN x)
    2126            0 : { struct _FpX *D = (struct _FpX*)E; return FpX_red(x,D->p); }
    2127              : 
    2128              : static GEN
    2129            0 : _FpX_zero(void *E)
    2130            0 : { struct _FpX *D = (struct _FpX *)E; return pol_0(D->v); }
    2131              : 
    2132              : 
    2133              : static struct bb_algebra FpX_algebra = { _FpX_red, _FpXQ_add, _FpXQ_sub,
    2134              :        _FpX_mul, _FpX_sqr, _FpX_one, _FpX_zero };
    2135              : 
    2136              : const struct bb_algebra *
    2137            0 : get_FpX_algebra(void **E, GEN p, long v)
    2138              : {
    2139            0 :   GEN z = new_chunk(sizeof(struct _FpX));
    2140            0 :   struct _FpX *e = (struct _FpX *) z;
    2141            0 :   e->p  = p; e->v = v; *E = (void*)e;
    2142            0 :   return &FpX_algebra;
    2143              : }
    2144              : 
    2145              : /* x,pol in Z[X], p in Z, n in Z, compute lift(x^n mod (p, pol)) */
    2146              : GEN
    2147      1567002 : FpXQ_pow(GEN x, GEN n, GEN T, GEN p)
    2148              : {
    2149              :   struct _FpXQ D;
    2150              :   pari_sp av;
    2151      1567002 :   long s = signe(n);
    2152              :   GEN y;
    2153      1567002 :   if (!s) return pol_1(varn(x));
    2154      1566398 :   if (is_pm1(n)) /* +/- 1 */
    2155        36651 :     return (s < 0)? FpXQ_inv(x,T,p): FpXQ_red(x,T,p);
    2156      1529747 :   av = avma;
    2157      1529747 :   if (!is_bigint(p))
    2158              :   {
    2159       662305 :     ulong pp = to_Flxq(&x, &T, p);
    2160       662305 :     y = Flxq_pow(x, n, T, pp);
    2161       662305 :     return Flx_to_ZX_inplace(gc_leaf(av, y));
    2162              :   }
    2163       867442 :   if (s < 0) x = FpXQ_inv(x,T,p);
    2164       867442 :   D.p = p; D.T = FpX_get_red(T,p);
    2165       867442 :   y = gen_pow_i(x, n, (void*)&D, &_FpXQ_sqr, &_FpXQ_mul);
    2166       867442 :   return gc_GEN(av, y);
    2167              : }
    2168              : 
    2169              : GEN /*Assume n is very small*/
    2170       621980 : FpXQ_powu(GEN x, ulong n, GEN T, GEN p)
    2171              : {
    2172              :   struct _FpXQ D;
    2173              :   pari_sp av;
    2174              :   GEN y;
    2175       621980 :   if (!n) return pol_1(varn(x));
    2176       621980 :   if (n==1) return FpXQ_red(x,T,p);
    2177       219059 :   av = avma;
    2178       219059 :   if (!is_bigint(p))
    2179              :   {
    2180       210570 :     ulong pp = to_Flxq(&x, &T, p);
    2181       210570 :     y = Flxq_powu(x, n, T, pp);
    2182       210570 :     return Flx_to_ZX_inplace(gc_leaf(av, y));
    2183              :   }
    2184         8489 :   D.T = FpX_get_red(T, p); D.p = p;
    2185         8489 :   y = gen_powu_i(x, n, (void*)&D, &_FpXQ_sqr, &_FpXQ_mul);
    2186         8489 :   return gc_GEN(av, y);
    2187              : }
    2188              : 
    2189              : /* generates the list of powers of x of degree 0,1,2,...,l*/
    2190              : GEN
    2191       390829 : FpXQ_powers(GEN x, long l, GEN T, GEN p)
    2192              : {
    2193              :   struct _FpXQ D;
    2194       390829 :   if (l>2 && lgefint(p) == 3) {
    2195       209821 :     pari_sp av = avma;
    2196       209821 :     ulong pp = to_Flxq(&x, &T, p);
    2197       209821 :     GEN z = FlxV_to_ZXV(Flxq_powers(x, l, T, pp));
    2198       209821 :     return gc_upto(av, z);
    2199              :   } else {
    2200       181008 :     long d = degpol(x), dT = get_Flx_degree(T);
    2201       181008 :     D.T = FpX_get_red(T,p); D.p = p;
    2202       181008 :     if (d >= dT) { x = FpXQ_red(x, T, p); d = degpol(x); }
    2203       181008 :     return gen_powers(x, l, 2*d>=dT, (void*)&D, &_FpXQ_sqr, &_FpXQ_mul,&_FpXQ_one);
    2204              :   }
    2205              : }
    2206              : 
    2207              : GEN
    2208        66284 : FpXQ_matrix_pow(GEN y, long n, long m, GEN P, GEN l)
    2209              : {
    2210        66284 :   return RgXV_to_RgM(FpXQ_powers(y,m-1,P,l),n);
    2211              : }
    2212              : 
    2213              : GEN
    2214       463448 : FpX_Frobenius(GEN T, GEN p)
    2215              : {
    2216       463448 :   return FpXQ_pow(pol_x(get_FpX_var(T)), p, T, p);
    2217              : }
    2218              : 
    2219              : GEN
    2220        31494 : FpX_matFrobenius(GEN T, GEN p)
    2221              : {
    2222        31494 :   long n = get_FpX_degree(T);
    2223        31494 :   return FpXQ_matrix_pow(FpX_Frobenius(T, p), n, n, T, p);
    2224              : }
    2225              : 
    2226              : static GEN
    2227       417945 : RgX_blocks_RgM(GEN P, long n, long m)
    2228              : {
    2229       417945 :   GEN z = cgetg(m+1,t_MAT);
    2230       417945 :   long i,j, k=2, l = lg(P);
    2231      1189449 :   for(i=1; i<=m; i++)
    2232              :   {
    2233       771504 :     GEN zi = cgetg(n+1,t_COL);
    2234       771504 :     gel(z,i) = zi;
    2235      4518460 :     for(j=1; j<=n; j++)
    2236      3746956 :       gel(zi, j) = k==l ? gen_0 : gel(P,k++);
    2237              :   }
    2238       417945 :   return z;
    2239              : }
    2240              : 
    2241              : static GEN
    2242       417945 : RgXV_to_RgM_lg(GEN x, long m, long n)
    2243              : {
    2244              :   long i;
    2245       417945 :   GEN y = cgetg(n+1, t_MAT);
    2246      2036842 :   for (i=1; i<=n; i++) gel(y,i) = RgX_to_RgC(gel(x,i), m);
    2247       417945 :   return y;
    2248              : }
    2249              : 
    2250              : GEN
    2251       418659 : FpX_FpXQV_eval(GEN Q, GEN x, GEN T, GEN p)
    2252              : {
    2253       418659 :   pari_sp btop, av = avma;
    2254       418659 :   long v = get_FpX_var(T), m = get_FpX_degree(T);
    2255       418659 :   long i, l = lg(x)-1, lQ = lgpol(Q), n,  d;
    2256              :   GEN A, B, C, S, g;
    2257       418659 :   if (lQ == 0) return pol_0(v);
    2258       417945 :   if (lQ <= l)
    2259              :   {
    2260       252620 :     n = l;
    2261       252620 :     d = 1;
    2262              :   }
    2263              :   else
    2264              :   {
    2265       165325 :     n = l-1;
    2266       165325 :     d = (lQ+n-1)/n;
    2267              :   }
    2268       417945 :   A = RgXV_to_RgM_lg(x, m, n);
    2269       417945 :   B = RgX_blocks_RgM(Q, n, d);
    2270       417945 :   C = gc_upto(av, FpM_mul(A, B, p));
    2271       417945 :   g = gel(x, l);
    2272       417945 :   T = FpX_get_red(T, p);
    2273       417945 :   btop = avma;
    2274       417945 :   S = RgV_to_RgX(gel(C, d), v);
    2275       417945 :   if (d==1) return gc_GEN(av, S);
    2276       518884 :   for (i = d-1; i>0; i--)
    2277              :   {
    2278       353559 :     S = FpX_add(FpXQ_mul(S, g, T, p), RgV_to_RgX(gel(C,i), v), p);
    2279       353559 :     if (gc_needed(btop,1))
    2280            0 :       S = gc_upto(btop, S);
    2281              :   }
    2282       165325 :   return gc_upto(av, S);
    2283              : }
    2284              : 
    2285              : GEN
    2286       809986 : FpX_FpXQ_eval(GEN Q, GEN x, GEN T, GEN p)
    2287              : {
    2288       809986 :   pari_sp av = avma;
    2289              :   GEN z, V;
    2290       809986 :   long d = degpol(Q), rtd;
    2291       809986 :   if (d < 0) return pol_0(get_FpX_var(T));
    2292       809965 :   if (lgefint(p) == 3)
    2293              :   {
    2294       803234 :     pari_sp av = avma;
    2295       803234 :     ulong pp = to_Flxq(&x, &T, p);
    2296       803234 :     GEN z = Flx_Flxq_eval(ZX_to_Flx(Q, pp), x, T, pp);
    2297       803234 :     return Flx_to_ZX_inplace(gc_leaf(av, z));
    2298              :   }
    2299         6731 :   rtd = (long) sqrt((double)d);
    2300         6731 :   T = FpX_get_red(T, p);
    2301         6731 :   V = FpXQ_powers(x, rtd, T, p);
    2302         6731 :   z = FpX_FpXQV_eval(Q, V, T, p);
    2303         6731 :   return gc_upto(av, z);
    2304              : }
    2305              : 
    2306              : GEN
    2307         1470 : FpXC_FpXQV_eval(GEN x, GEN v, GEN T, GEN p)
    2308         8316 : { pari_APPLY_type(t_COL, FpX_FpXQV_eval(gel(x,i), v, T, p)) }
    2309              : 
    2310              : GEN
    2311          315 : FpXM_FpXQV_eval(GEN x, GEN v, GEN T, GEN p)
    2312         1197 : { pari_APPLY_same(FpXC_FpXQV_eval(gel(x,i), v, T, p)) }
    2313              : 
    2314              : GEN
    2315          588 : FpXC_FpXQ_eval(GEN x, GEN F, GEN T, GEN p)
    2316              : {
    2317          588 :   long d = brent_kung_optpow(RgXV_maxdegree(x), lg(x)-1, 1);
    2318          588 :   GEN Fp = FpXQ_powers(F, d, T, p);
    2319          588 :   return FpXC_FpXQV_eval(x, Fp, T, p);
    2320              : }
    2321              : 
    2322              : GEN
    2323         1736 : FpXQ_autpowers(GEN aut, long f, GEN T, GEN p)
    2324              : {
    2325         1736 :   pari_sp av = avma;
    2326         1736 :   long n = get_FpX_degree(T);
    2327         1736 :   long i, nautpow = brent_kung_optpow(n-1,f-2,1);
    2328         1736 :   long v = get_FpX_var(T);
    2329              :   GEN autpow, V;
    2330         1736 :   T = FpX_get_red(T, p);
    2331         1736 :   autpow = FpXQ_powers(aut, nautpow,T,p);
    2332         1736 :   V = cgetg(f + 2, t_VEC);
    2333         1736 :   gel(V,1) = pol_x(v); if (f==0) return gc_upto(av, V);
    2334         1736 :   gel(V,2) = gcopy(aut);
    2335         6202 :   for (i = 3; i <= f+1; i++)
    2336         4466 :     gel(V,i) = FpX_FpXQV_eval(gel(V,i-1),autpow,T,p);
    2337         1736 :   return gc_upto(av, V);
    2338              : }
    2339              : 
    2340              : static GEN
    2341         4669 : FpXQ_autpow_sqr(void *E, GEN x)
    2342              : {
    2343         4669 :   struct _FpXQ *D = (struct _FpXQ*)E;
    2344         4669 :   return FpX_FpXQ_eval(x, x, D->T, D->p);
    2345              : }
    2346              : 
    2347              : static GEN
    2348           42 : FpXQ_autpow_msqr(void *E, GEN x)
    2349              : {
    2350           42 :   struct _FpXQ *D = (struct _FpXQ*)E;
    2351           42 :   return FpX_FpXQV_eval(FpXQ_autpow_sqr(E, x), D->aut, D->T, D->p);
    2352              : }
    2353              : 
    2354              : GEN
    2355         4575 : FpXQ_autpow(GEN x, ulong n, GEN T, GEN p)
    2356              : {
    2357         4575 :   pari_sp av = avma;
    2358              :   struct _FpXQ D;
    2359              :   long d;
    2360         4575 :   if (n==0) return FpX_rem(pol_x(varn(x)), T, p);
    2361         4575 :   if (n==1) return FpX_rem(x, T, p);
    2362         4354 :   D.T = FpX_get_red(T, p); D.p = p;
    2363         4354 :   d = brent_kung_optpow(get_FpX_degree(T), hammingu(n)-1, 1);
    2364         4354 :   D.aut = FpXQ_powers(x, d, T, p);
    2365         4354 :   x = gen_powu_fold(x,n,(void*)&D,FpXQ_autpow_sqr,FpXQ_autpow_msqr);
    2366         4354 :   return gc_GEN(av, x);
    2367              : }
    2368              : 
    2369              : static GEN
    2370          360 : FpXQ_auttrace_mul(void *E, GEN x, GEN y)
    2371              : {
    2372          360 :   struct _FpXQ *D = (struct _FpXQ*)E;
    2373          360 :   GEN T = D->T, p = D->p;
    2374          360 :   GEN phi1 = gel(x,1), a1 = gel(x,2);
    2375          360 :   GEN phi2 = gel(y,1), a2 = gel(y,2);
    2376          360 :   ulong d = brent_kung_optpow(maxss(degpol(phi2),degpol(a2)),2,1);
    2377          360 :   GEN V1 = FpXQ_powers(phi1, d, T, p);
    2378          360 :   GEN phi3 = FpX_FpXQV_eval(phi2, V1, T, p);
    2379          360 :   GEN aphi = FpX_FpXQV_eval(a2, V1, T, p);
    2380          360 :   GEN a3 = FpX_add(a1, aphi, p);
    2381          360 :   return mkvec2(phi3, a3);
    2382              : }
    2383              : 
    2384              : static GEN
    2385          317 : FpXQ_auttrace_sqr(void *E, GEN x)
    2386          317 : { return FpXQ_auttrace_mul(E, x, x); }
    2387              : 
    2388              : GEN
    2389          434 : FpXQ_auttrace(GEN x, ulong n, GEN T, GEN p)
    2390              : {
    2391          434 :   pari_sp av = avma;
    2392              :   struct _FpXQ D;
    2393          434 :   D.T = FpX_get_red(T, p); D.p = p;
    2394          434 :   x = gen_powu_i(x,n,(void*)&D,FpXQ_auttrace_sqr,FpXQ_auttrace_mul);
    2395          434 :   return gc_GEN(av, x);
    2396              : }
    2397              : 
    2398              : static GEN
    2399         3165 : FpXQ_autsum_mul(void *E, GEN x, GEN y)
    2400              : {
    2401         3165 :   struct _FpXQ *D = (struct _FpXQ*)E;
    2402         3165 :   GEN T = D->T, p = D->p;
    2403         3165 :   GEN phi1 = gel(x,1), a1 = gel(x,2);
    2404         3165 :   GEN phi2 = gel(y,1), a2 = gel(y,2);
    2405         3165 :   ulong d = brent_kung_optpow(maxss(degpol(phi2),degpol(a2)),2,1);
    2406         3165 :   GEN V1 = FpXQ_powers(phi1, d, T, p);
    2407         3165 :   GEN phi3 = FpX_FpXQV_eval(phi2, V1, T, p);
    2408         3165 :   GEN aphi = FpX_FpXQV_eval(a2, V1, T, p);
    2409         3165 :   GEN a3 = FpXQ_mul(a1, aphi, T, p);
    2410         3165 :   return mkvec2(phi3, a3);
    2411              : }
    2412              : static GEN
    2413         3005 : FpXQ_autsum_sqr(void *E, GEN x)
    2414         3005 : { return FpXQ_autsum_mul(E, x, x); }
    2415              : 
    2416              : GEN
    2417         2879 : FpXQ_autsum(GEN x, ulong n, GEN T, GEN p)
    2418              : {
    2419         2879 :   pari_sp av = avma;
    2420              :   struct _FpXQ D;
    2421         2879 :   D.T = FpX_get_red(T, p); D.p = p;
    2422         2879 :   x = gen_powu_i(x,n,(void*)&D,FpXQ_autsum_sqr,FpXQ_autsum_mul);
    2423         2879 :   return gc_GEN(av, x);
    2424              : }
    2425              : 
    2426              : static GEN
    2427          315 : FpXQM_autsum_mul(void *E, GEN x, GEN y)
    2428              : {
    2429          315 :   struct _FpXQ *D = (struct _FpXQ*)E;
    2430          315 :   GEN T = D->T, p = D->p;
    2431          315 :   GEN phi1 = gel(x,1), a1 = gel(x,2);
    2432          315 :   GEN phi2 = gel(y,1), a2 = gel(y,2);
    2433          315 :   long g = lg(a2)-1, dT = get_FpX_degree(T);
    2434          315 :   ulong d = brent_kung_optpow(dT-1, g*g+1, 1);
    2435          315 :   GEN V1 = FpXQ_powers(phi1, d, T, p);
    2436          315 :   GEN phi3 = FpX_FpXQV_eval(phi2, V1, T, p);
    2437          315 :   GEN aphi = FpXM_FpXQV_eval(a2, V1, T, p);
    2438          315 :   GEN a3 = FqM_mul(a1, aphi, T, p);
    2439          315 :   return mkvec2(phi3, a3);
    2440              : }
    2441              : static GEN
    2442          217 : FpXQM_autsum_sqr(void *E, GEN x)
    2443          217 : { return FpXQM_autsum_mul(E, x, x); }
    2444              : 
    2445              : GEN
    2446          147 : FpXQM_autsum(GEN x, ulong n, GEN T, GEN p)
    2447              : {
    2448          147 :   pari_sp av = avma;
    2449              :   struct _FpXQ D;
    2450          147 :   D.T = FpX_get_red(T, p); D.p = p;
    2451          147 :   x = gen_powu_i(x, n, (void*)&D, FpXQM_autsum_sqr, FpXQM_autsum_mul);
    2452          147 :   return gc_GEN(av, x);
    2453              : }
    2454              : 
    2455              : static long
    2456         4450 : bounded_order(GEN p, GEN b, long k)
    2457              : {
    2458              :   long i;
    2459         4450 :   GEN a=modii(p,b);
    2460         9626 :   for(i=1;i<k;i++)
    2461              :   {
    2462         8055 :     if (equali1(a))
    2463         2879 :       return i;
    2464         5176 :     a = Fp_mul(a,p,b);
    2465              :   }
    2466         1571 :   return 0;
    2467              : }
    2468              : 
    2469              : /* n = (p^d-a)\b
    2470              :  * b = bb*p^vb
    2471              :  * p^k = 1 [bb]
    2472              :  * d = m*k+r+vb
    2473              :  * u = (p^k-1)/bb;
    2474              :  * v = (p^(r+vb)-a)/b;
    2475              :  * w = (p^(m*k)-1)/(p^k-1)
    2476              :  * n = p^r*w*u+v
    2477              :  * w*u = p^vb*(p^(m*k)-1)/b
    2478              :  * n = p^(r+vb)*(p^(m*k)-1)/b+(p^(r+vb)-a)/b */
    2479              : static GEN
    2480       842156 : FpXQ_pow_Frobenius(GEN x, GEN n, GEN aut, GEN T, GEN p)
    2481              : {
    2482       842156 :   pari_sp av=avma;
    2483       842156 :   long d = get_FpX_degree(T);
    2484       842156 :   GEN an = absi_shallow(n), z, q;
    2485       842156 :   if (cmpii(an,p)<0 || cmpis(an,d)<=0) return FpXQ_pow(x, n, T, p);
    2486         4457 :   q = powiu(p, d);
    2487         4457 :   if (dvdii(q, n))
    2488              :   {
    2489            0 :     long vn = logint(an,p);
    2490            0 :     GEN autvn = vn==1 ? aut: FpXQ_autpow(aut,vn,T,p);
    2491            0 :     z = FpX_FpXQ_eval(x,autvn,T,p);
    2492              :   } else
    2493              :   {
    2494         4457 :     GEN b = diviiround(q, an), a = subii(q, mulii(an,b));
    2495              :     GEN bb, u, v, autk;
    2496         4457 :     long vb = Z_pvalrem(b,p,&bb);
    2497         4457 :     long m, r, k = is_pm1(bb) ? 1 : bounded_order(p,bb,d);
    2498         4457 :     if (!k || d-vb<k) return FpXQ_pow(x,n, T, p);
    2499         2886 :     m = (d-vb)/k; r = (d-vb)%k;
    2500         2886 :     u = diviiexact(subiu(powiu(p,k),1),bb);
    2501         2886 :     v = diviiexact(subii(powiu(p,r+vb),a),b);
    2502         2886 :     autk = k==1 ? aut: FpXQ_autpow(aut,k,T,p);
    2503         2886 :     if (r)
    2504              :     {
    2505           14 :       GEN autr = r==1 ? aut: FpXQ_autpow(aut,r,T,p);
    2506           14 :       z = FpX_FpXQ_eval(x,autr,T,p);
    2507         2872 :     } else z = x;
    2508         2886 :     if (m > 1) z = gel(FpXQ_autsum(mkvec2(autk, z), m, T, p), 2);
    2509         2886 :     if (!is_pm1(u)) z = FpXQ_pow(z, u, T, p);
    2510         2886 :     if (signe(v)) z = FpXQ_mul(z, FpXQ_pow(x, v, T, p), T, p);
    2511              :   }
    2512         2886 :   return gc_upto(av,signe(n)>0 ? z : FpXQ_inv(z,T,p));
    2513              : }
    2514              : 
    2515              : /* assume T irreducible mod p */
    2516              : int
    2517       401609 : FpXQ_issquare(GEN x, GEN T, GEN p)
    2518              : {
    2519              :   pari_sp av;
    2520       401609 :   if (lg(x) == 2 || absequalui(2, p)) return 1;
    2521       401595 :   if (lg(x) == 3) return Fq_issquare(gel(x,2), T, p);
    2522       363679 :   av = avma; /* Ng = g^((q-1)/(p-1)) */
    2523       363679 :   return gc_bool(av, kronecker(FpXQ_norm(x,T,p), p) != -1);
    2524              : }
    2525              : int
    2526      1336383 : Fp_issquare(GEN x, GEN p)
    2527      1336383 : { return absequalui(2, p) || kronecker(x, p) != -1; }
    2528              : /* assume T irreducible mod p */
    2529              : int
    2530      1631319 : Fq_issquare(GEN x, GEN T, GEN p)
    2531              : {
    2532      1631319 :   if (typ(x) != t_INT) return FpXQ_issquare(x, T, p);
    2533      1234027 :   return (T && ! odd(get_FpX_degree(T))) || Fp_issquare(x, p);
    2534              : }
    2535              : 
    2536              : long
    2537           70 : Fq_ispower(GEN x, GEN K, GEN T, GEN p)
    2538              : {
    2539           70 :   pari_sp av = avma;
    2540              :   long d;
    2541              :   GEN Q;
    2542           70 :   if (equaliu(K,2)) return Fq_issquare(x, T, p);
    2543            0 :   if (!T) return Fp_ispower(x, K, p);
    2544            0 :   d = get_FpX_degree(T);
    2545            0 :   if (typ(x) == t_INT && !umodui(d, K)) return 1;
    2546            0 :   Q = subiu(powiu(p,d), 1);
    2547            0 :   Q = diviiexact(Q, gcdii(Q, K));
    2548            0 :   d = gequal1(Fq_pow(x, Q, T,p));
    2549            0 :   return gc_long(av, d);
    2550              : }
    2551              : 
    2552              : /* discrete log in FpXQ for a in Fp^*, g in FpXQ^* of order ord */
    2553              : GEN
    2554       544098 : Fp_FpXQ_log(GEN a, GEN g, GEN o, GEN T, GEN p)
    2555              : {
    2556       544098 :   pari_sp av = avma;
    2557              :   GEN q,n_q,ord,ordp, op;
    2558              : 
    2559       544098 :   if (equali1(a)) return gen_0;
    2560              :   /* p > 2 */
    2561              : 
    2562         6974 :   ordp = subiu(p, 1); /* even */
    2563         6974 :   ord  = get_arith_Z(o);
    2564         6946 :   if (!ord) ord = T? subiu(powiu(p, get_FpX_degree(T)), 1): ordp;
    2565         6946 :   if (equalii(a, ordp)) /* -1 */
    2566         5021 :     return gc_INT(av, shifti(ord,-1));
    2567         1925 :   ordp = gcdii(ordp,ord);
    2568         1925 :   op = typ(o)==t_MAT ? famat_Z_gcd(o,ordp) : ordp;
    2569              : 
    2570         1925 :   q = NULL;
    2571         1925 :   if (T)
    2572              :   { /* we want < g > = Fp^* */
    2573         1925 :     if (!equalii(ord,ordp)) {
    2574         1903 :       q = diviiexact(ord,ordp);
    2575         1903 :       g = FpXQ_pow(g,q,T,p);
    2576              :     }
    2577         1925 :     g = constant_coeff(g);
    2578              :   }
    2579         1925 :   n_q = Fp_log(a,g,op,p);
    2580         1925 :   if (lg(n_q)==1) return gc_leaf(av, n_q);
    2581         1925 :   if (q) n_q = mulii(q, n_q);
    2582         1925 :   return gc_INT(av, n_q);
    2583              : }
    2584              : 
    2585              : static GEN
    2586       826923 : _FpXQ_pow(void *data, GEN x, GEN n)
    2587              : {
    2588       826923 :   struct _FpXQ *D = (struct _FpXQ*)data;
    2589       826923 :   return FpXQ_pow_Frobenius(x,n, D->aut, D->T, D->p);
    2590              : }
    2591              : 
    2592              : static GEN
    2593          679 : _FpXQ_rand(void *data)
    2594              : {
    2595          679 :   pari_sp av=avma;
    2596          679 :   struct _FpXQ *D = (struct _FpXQ*)data;
    2597              :   GEN z;
    2598              :   do
    2599              :   {
    2600          679 :     set_avma(av);
    2601          679 :     z=random_FpX(get_FpX_degree(D->T),get_FpX_var(D->T),D->p);
    2602          679 :   } while (!signe(z));
    2603          679 :   return z;
    2604              : }
    2605              : 
    2606              : static GEN
    2607          469 : _FpXQ_easylog(void *E, GEN a, GEN g, GEN ord)
    2608              : {
    2609          469 :   struct _FpXQ *s=(struct _FpXQ*) E;
    2610          469 :   if (degpol(a)) return NULL;
    2611          193 :   return Fp_FpXQ_log(constant_coeff(a),g,ord,s->T,s->p);
    2612              : }
    2613              : 
    2614              : static const struct bb_group FpXQ_star={_FpXQ_mul,_FpXQ_pow,_FpXQ_rand,hash_GEN,ZX_equal,ZX_equal1,_FpXQ_easylog};
    2615              : 
    2616              : const struct bb_group *
    2617         2807 : get_FpXQ_star(void **E, GEN T, GEN p)
    2618              : {
    2619         2807 :   struct _FpXQ *e = (struct _FpXQ *) stack_malloc(sizeof(struct _FpXQ));
    2620         2807 :   e->T = T; e->p  = p; e->aut =  FpX_Frobenius(T, p);
    2621         2807 :   *E = (void*)e; return &FpXQ_star;
    2622              : }
    2623              : 
    2624              : GEN
    2625         1814 : FpXQ_order(GEN a, GEN ord, GEN T, GEN p)
    2626              : {
    2627         1814 :   if (lgefint(p)==3)
    2628              :   {
    2629            0 :     pari_sp av=avma;
    2630            0 :     ulong pp = to_Flxq(&a, &T, p);
    2631            0 :     GEN z = Flxq_order(a, ord, T, pp);
    2632            0 :     return gc_INT(av,z);
    2633              :   }
    2634              :   else
    2635              :   {
    2636              :     void *E;
    2637         1814 :     const struct bb_group *S = get_FpXQ_star(&E,T,p);
    2638         1814 :     return gen_order(a,ord,E,S);
    2639              :   }
    2640              : }
    2641              : 
    2642              : GEN
    2643       707977 : FpXQ_log(GEN a, GEN g, GEN ord, GEN T, GEN p)
    2644              : {
    2645       707977 :   pari_sp av=avma;
    2646       707977 :   if (lgefint(p)==3)
    2647              :   {
    2648       707842 :     if (uel(p,2) == 2)
    2649              :     {
    2650       543749 :       GEN z = F2xq_log(ZX_to_F2x(a), ZX_to_F2x(g), ord,
    2651              :                                      ZX_to_F2x(get_FpX_mod(T)));
    2652       543749 :       return gc_leaf(av, z);
    2653              :     }
    2654              :     else
    2655              :     {
    2656       164093 :       ulong pp = to_Flxq(&a, &T, p);
    2657       164093 :       GEN z = Flxq_log(a, ZX_to_Flx(g, pp), ord, T, pp);
    2658       164093 :       return gc_leaf(av, z);
    2659              :     }
    2660              :   }
    2661              :   else
    2662              :   {
    2663              :     void *E;
    2664          135 :     const struct bb_group *S = get_FpXQ_star(&E,T,p);
    2665          135 :     GEN z = gen_PH_log(a,g,ord,E,S);
    2666          107 :     return gc_leaf(av, z);
    2667              :   }
    2668              : }
    2669              : 
    2670              : GEN
    2671      2478490 : Fq_log(GEN a, GEN g, GEN ord, GEN T, GEN p)
    2672              : {
    2673      2478490 :   if (!T) return Fp_log(a,g,ord,p);
    2674      1251838 :   if (typ(g) == t_INT)
    2675              :   {
    2676            0 :     if (typ(a) == t_POL)
    2677              :     {
    2678            0 :       if (degpol(a)) return cgetg(1,t_VEC);
    2679            0 :       a = gel(a,2);
    2680              :     }
    2681            0 :     return Fp_log(a,g,ord,p);
    2682              :   }
    2683      1251838 :   return typ(a) == t_INT? Fp_FpXQ_log(a,g,ord,T,p): FpXQ_log(a,g,ord,T,p);
    2684              : }
    2685              : 
    2686              : static GEN
    2687         2264 : FpXQ_sumautsum_sqr(void *E, GEN xzd)
    2688              : {
    2689         2264 :   struct _FpXQ *D = (struct _FpXQ*)E;
    2690         2264 :   pari_sp av = avma;
    2691              :   GEN xi, zeta, delta, xi2, zeta2, delta2, temp, xipow;
    2692         2264 :   GEN T = D->T, p = D-> p;
    2693              :   ulong d;
    2694         2264 :   xi = gel(xzd, 1); zeta = gel(xzd, 2); delta = gel(xzd, 3);
    2695              : 
    2696         2264 :   d = brent_kung_optpow(get_FpX_degree(T)-1,3,1);
    2697         2264 :   xipow = FpXQ_powers(xi, d, T, p);
    2698              : 
    2699         2264 :   xi2 = FpX_FpXQV_eval(xi, xipow, T, p);
    2700         2264 :   zeta2 = FpXQ_mul(zeta, FpX_FpXQV_eval(zeta,  xipow, T, p), T, p);
    2701         2264 :   temp  = FpXQ_mul(zeta, FpX_FpXQV_eval(delta, xipow, T, p), T, p);
    2702         2264 :   delta2 = FpX_add(delta, temp, p);
    2703         2264 :   return gc_GEN(av, mkvec3(xi2, zeta2, delta2));
    2704              : }
    2705              : 
    2706              : static GEN
    2707         1123 : FpXQ_sumautsum_msqr(void *E, GEN xzd)
    2708              : {
    2709         1123 :   struct _FpXQ *D = (struct _FpXQ*)E;
    2710         1123 :   pari_sp av = avma;
    2711              :   GEN xii, zetai, deltai, xzd2;
    2712         1123 :   GEN T = D->T, p = D-> p, xi0pow = gel(D->aut, 1), zeta0 = gel(D->aut, 2);
    2713         1123 :   xzd2 = FpXQ_sumautsum_sqr(E, xzd);
    2714         1123 :   xii = FpX_FpXQV_eval(gel(xzd2, 1), xi0pow, T, p);
    2715         1123 :   zetai = FpXQ_mul(zeta0, FpX_FpXQV_eval(gel(xzd2, 2), xi0pow, T, p), T, p);
    2716         1123 :   deltai = FpX_add(gel(xzd2, 3), zetai, p);
    2717              : 
    2718         1123 :   return gc_GEN(av, mkvec3(xii, zetai, deltai));
    2719              : }
    2720              : 
    2721              : /*returns a + a^(1+s) + a^(1+s+2s) + ... + a^(1+s+...+is)
    2722              :   where ax = [a,s] with s an automorphism */
    2723              : static GEN
    2724         1273 : FpXQ_sumautsum(GEN ax, long i, GEN T, GEN p) {
    2725         1273 :   pari_sp av = avma;
    2726              :   GEN a, xi, zeta, vec, res;
    2727              :   struct _FpXQ D;
    2728              :   ulong d;
    2729         1273 :   D.T = FpX_get_red(T, p); D.p = p;
    2730         1273 :   a = gel(ax, 1); xi = gel(ax,2);
    2731         1273 :   d = brent_kung_optpow(get_FpX_degree(T)-1,2*(hammingu(i)-1),1);
    2732         1273 :   zeta = FpX_FpXQ_eval(a, xi, T, p);
    2733         1273 :   D.aut = mkvec2(FpXQ_powers(xi, d, T, p), zeta);
    2734              : 
    2735         1273 :   vec = gen_powu_fold(mkvec3(xi, zeta, zeta), i, (void *)&D, FpXQ_sumautsum_sqr, FpXQ_sumautsum_msqr);
    2736         1273 :   res = FpXQ_mul(a, FpX_add(pol_1(get_FpX_var(T)), gel(vec, 3), p), T, p);
    2737              : 
    2738         1273 :   return gc_GEN(av, res);
    2739              : }
    2740              : 
    2741              : /*algorithm from
    2742              : Doliskani, J., & Schost, E. (2014).
    2743              : Taking roots over high extensions of finite fields
    2744              : https://arxiv.org/pdf/1110.4350
    2745              : */
    2746              : static GEN
    2747          543 : FpXQ_sqrtl_spec(GEN z, GEN n, GEN T, GEN p, GEN *zetan)
    2748              : {
    2749          543 :   pari_sp av = avma;
    2750              :   GEN psn, c, b, new_z, beta, x, y, w, ax, g, zeta;
    2751          543 :   long s, l, v = get_FpX_var(T), d = get_FpX_degree(T);
    2752          543 :   if(!isprime(n)) pari_err_PRIME("FpXQ_sqrtn", n);
    2753          543 :   s = itos(Fp_order(p, subiu(n,1), n));
    2754          543 :   if(s >= d || d % s != 0)
    2755            0 :     pari_err(e_MISC, "expected p's order mod n to divide the degree of T");
    2756          543 :   l = d/s;
    2757          543 :   if (!signe(z)) return pol_0(varn(z));
    2758          543 :   T = FpX_get_red(T, p);
    2759          543 :   ax = mkvec2(NULL, FpXQ_autpow(FpX_Frobenius(T,p), s, T, p));
    2760          543 :   psn = diviiexact(subii(powiu(p, s), gen_1), n);
    2761              :   do {
    2762          543 :     do c = random_FpX(d, v, p); while (!signe(c));
    2763          543 :     new_z = FpXQ_mul(z, FpXQ_pow(c, n, T, p), T, p);
    2764          543 :     gel(ax,1) = FpXQ_pow(new_z, psn, T, p);
    2765              : 
    2766              :     /*If l == 2, b has to be 1 + a^((p^s-1)/n)*/
    2767          543 :     if(l == 2) y = gel(ax, 1);
    2768          543 :     else y = FpXQ_sumautsum(ax, l-2, T, p);
    2769          543 :     b = FpX_Fp_add(y, gen_1, p);
    2770          543 :   } while (!signe(b));
    2771              : 
    2772          543 :   x = FpXQ_mul(new_z, FpXQ_pow(b, n, T, p), T, p);
    2773          543 :   if(s == 1) {
    2774          221 :     if (degpol(x) > 0) return gc_NULL(av);
    2775          184 :     beta = Fp_sqrtn(constant_coeff(x), n, p, &zeta);
    2776          184 :     if (!beta) return gc_NULL(av);
    2777          184 :     if(zetan) *zetan = scalarpol(zeta, varn(z));
    2778          184 :     w = FpX_Fp_mul(FpXQ_inv(FpXQ_mul(b, c, T, p), T, p), beta, p);
    2779          184 :     (void)gc_all(av, zetan? 2: 1, &w, zetan);
    2780          184 :     return w;
    2781              :   }
    2782          322 :   g = FpXQ_minpoly(x, T, p);
    2783          322 :   if (degpol(g) > s) return gc_NULL(av);
    2784              : 
    2785          322 :   beta = FpXQ_sqrtn(pol_x(varn(z)), n, g, p, &zeta);
    2786          322 :   if (!beta) return gc_NULL(av);
    2787              : 
    2788          322 :   if(zetan) *zetan = FpX_FpXQ_eval(zeta, x, T, p);
    2789          322 :   beta = FpX_FpXQ_eval(beta, x, T, p);
    2790          322 :   w = FpXQ_mul(FpXQ_inv(FpXQ_mul(b, c, T, p), T, p), beta, T, p);
    2791          322 :   (void)gc_all(av, zetan? 2: 1, &w, zetan);
    2792          322 :   return w;
    2793              : }
    2794              : 
    2795              : static GEN
    2796          858 : FpXQ_sqrtn_spec(GEN a, GEN n, GEN T, GEN p, GEN q, GEN *zetan)
    2797              : {
    2798          858 :   pari_sp ltop = avma;
    2799              :   GEN z, m, u1, u2;
    2800              :   int is_1;
    2801          858 :   if (is_pm1(n))
    2802              :   {
    2803          581 :     if (zetan) *zetan = pol_1(varn(a));
    2804          581 :     return signe(n) < 0? FpXQ_inv(a, T, p): gcopy(a);
    2805              :   }
    2806          277 :   is_1 = gequal1(a);
    2807          277 :   if (is_1 && !zetan) return gcopy(a);
    2808          270 :   z = pol_1(varn(a));
    2809          270 :   m = bezout(n,q,&u1,&u2);
    2810          270 :   if (!is_pm1(m))
    2811              :   {
    2812          270 :     GEN F = Z_factor(m);
    2813          270 :     long i, j, j2 = 0;
    2814              :     GEN y, l;
    2815          270 :     pari_sp av1 = avma;
    2816          503 :     for (i = nbrows(F); i; i--)
    2817              :     {
    2818          270 :       l = gcoeff(F,i,1);
    2819          270 :       j = itos(gcoeff(F,i,2));
    2820          270 :       if(zetan) {
    2821           71 :         a = FpXQ_sqrtl_spec(a,l,T,p,&y);
    2822          108 :         if (!a) return gc_NULL(ltop);
    2823           71 :         j--;
    2824           71 :         j2 = j;
    2825              :       }
    2826          270 :       if (!is_1 && j > 0) {
    2827              :         do
    2828              :         {
    2829          395 :           a = FpXQ_sqrtl_spec(a,l,T,p,NULL);
    2830          395 :           if (!a) return gc_NULL(ltop);
    2831          358 :         } while (--j);
    2832              :       }
    2833              :       /*This is below finding a's root,
    2834              :       so we don't spend time doing this, if a is not n-th root*/
    2835          233 :       if(zetan) {
    2836          148 :         for(; j2>0; j2--) y = FpXQ_sqrtl_spec(y, l, T, p, NULL);
    2837           71 :         z = FpXQ_mul(z, y, T, p);
    2838              :       }
    2839          233 :       if (gc_needed(ltop,1))
    2840              :       { /* n can have lots of prime factors*/
    2841            0 :         if(DEBUGMEM>1) pari_warn(warnmem,"FpXQ_sqrtn_spec");
    2842            0 :         (void)gc_all(av1, zetan? 2: 1, &a, &z);
    2843              :       }
    2844              :     }
    2845              :   }
    2846              : 
    2847          233 :   if (!equalii(m, n))
    2848           42 :     a = FpXQ_pow(a,modii(u1,q), T, p);
    2849          233 :   if (zetan)
    2850              :   {
    2851           71 :     *zetan = z;
    2852           71 :     (void)gc_all(ltop,2,&a,zetan);
    2853              :   }
    2854              :   else /* is_1 is 0: a was modified above -> gc_upto valid */
    2855          162 :     a = gc_upto(ltop, a);
    2856          233 :   return a;
    2857              : }
    2858              : GEN
    2859         1222 : FpXQ_sqrtn(GEN a, GEN n, GEN T, GEN p, GEN *zeta)
    2860              : {
    2861         1222 :   pari_sp av = avma;
    2862              :   GEN z;
    2863         1222 :   if (!signe(a))
    2864              :   {
    2865          154 :     long v=varn(a);
    2866          154 :     if (signe(n) < 0) pari_err_INV("FpXQ_sqrtn",a);
    2867          147 :     if (zeta) *zeta=pol_1(v);
    2868          147 :     return pol_0(v);
    2869              :   }
    2870         1068 :   if (lgefint(p)==3)
    2871              :   {
    2872          210 :     if (uel(p,2) == 2)
    2873              :     {
    2874           14 :       z = F2xq_sqrtn(ZX_to_F2x(a), n, ZX_to_F2x(get_FpX_mod(T)), zeta);
    2875           14 :       if (!z) return NULL;
    2876           14 :       z = F2x_to_ZX(z);
    2877           14 :       if (!zeta) return gc_leaf(av, z);
    2878            7 :       *zeta=F2x_to_ZX(*zeta);
    2879              :     } else
    2880              :     {
    2881          196 :       ulong pp = to_Flxq(&a, &T, p);
    2882          196 :       z = Flxq_sqrtn(a, n, T, pp, zeta);
    2883          196 :       if (!z) return NULL;
    2884          196 :       if (!zeta) return Flx_to_ZX_inplace(gc_leaf(av, z));
    2885           70 :       z = Flx_to_ZX(z);
    2886           70 :       *zeta=Flx_to_ZX(*zeta);
    2887              :     }
    2888              :   }
    2889              :   else
    2890              :   {
    2891              :     void *E;
    2892          858 :     const struct bb_group *S = get_FpXQ_star(&E,T,p);
    2893          858 :     long i, s, d = get_FpX_degree(T);
    2894          858 :     GEN o = subiu(powiu(p,d),1);
    2895              :     GEN m, u1, u2, l, zeta2, F, n2;
    2896              : 
    2897          858 :     m = bezout(n,o,&u1,&u2);
    2898          858 :     F = Z_factor(m);
    2899         1632 :     for (i = nbrows(F); i; i--)
    2900              :     {
    2901          774 :       l = gcoeff(F,i,1);
    2902          774 :       s = itos(Fp_order(p, subiu(l, 1), l));
    2903              :       /*FpXQ_sqrtn_spec only works if d > s and s | d
    2904              :       for those factors of m we use FpXQ_sqrtn_spec
    2905              :       for the other factor we stay with gen_Shanks_sqrtn*/
    2906          774 :       if(d <= s || d % s != 0) {
    2907          497 :         gcoeff(F,i,2) = gen_0;
    2908              :       }
    2909          277 :       else gcoeff(F,i,2) = stoi(Z_pval(n,l));
    2910              :     }
    2911          858 :     F = factorback(F);
    2912          858 :     z = FpXQ_sqrtn_spec(a,F,T, p, o,zeta);
    2913         1258 :     if(!z) return gc_NULL(av);
    2914          821 :     n2 = diviiexact(n, F);
    2915          821 :     if(!gequal1(n2)) {
    2916          602 :       if(zeta) zeta2 = gcopy(*zeta);
    2917          602 :       z = gen_Shanks_sqrtn(z, n2, o, zeta, E, S);
    2918          602 :       if (!z) return gc_NULL(av);
    2919          602 :       if(zeta) *zeta = FpXQ_mul(*zeta, zeta2, T, p);
    2920              :     }
    2921          821 :     if (!zeta) return gc_upto(av, z);
    2922              :   }
    2923          498 :   return gc_all(av, 2, &z,zeta);
    2924              : }
    2925              : 
    2926              : static GEN
    2927        18961 : Fp2_norm(GEN x, GEN D, GEN p)
    2928              : {
    2929        18961 :   GEN a = gel(x,1), b = gel(x,2);
    2930        18961 :   if (signe(b)==0) return Fp_sqr(a,p);
    2931        18961 :   return Fp_sub(sqri(a), mulii(D, Fp_sqr(b, p)), p);
    2932              : }
    2933              : 
    2934              : static GEN
    2935        19392 : Fp2_sqrt(GEN z, GEN D, GEN p)
    2936              : {
    2937        19392 :   GEN a = gel(z,1), b = gel(z,2), as2, u, v, s;
    2938        19392 :   GEN y = Fp_2gener_i(D, p);
    2939        19392 :   if (signe(b)==0)
    2940          431 :     return kronecker(a, p)==1 ? mkvec2(Fp_sqrt_i(a, y, p), gen_0)
    2941          431 :                               : mkvec2(gen_0,Fp_sqrt_i(Fp_div(a, D, p), y, p));
    2942        18961 :   s = Fp_sqrt_i(Fp2_norm(z, D, p), y, p);
    2943        18961 :   if(!s) return NULL;
    2944        18551 :   as2 = Fp_halve(Fp_add(a, s, p), p);
    2945        18551 :   if (kronecker(as2, p)==-1) as2 = Fp_sub(as2,s,p);
    2946        18551 :   u = Fp_sqrt_i(as2, y, p);
    2947        18551 :   v = Fp_div(b, Fp_double(u, p), p);
    2948        18551 :   return mkvec2(u,v);
    2949              : }
    2950              : 
    2951              : 
    2952              : GEN
    2953        78680 : FpXQ_sqrt(GEN z, GEN T, GEN p)
    2954              : {
    2955        78680 :   pari_sp av = avma;
    2956              :   long d;
    2957        78680 :   if (lgefint(p)==3)
    2958              :   {
    2959        58550 :     if (uel(p,2) == 2)
    2960              :     {
    2961         5362 :       GEN r = F2xq_sqrt(ZX_to_F2x(z), ZX_to_F2x(get_FpX_mod(T)));
    2962         5362 :       return gc_upto(av, F2x_to_ZX(r));
    2963              :     } else
    2964              :     {
    2965        53188 :       ulong pp = to_Flxq(&z, &T, p);
    2966        53188 :       z = Flxq_sqrt(z, T, pp);
    2967        53188 :       if (!z) return NULL;
    2968        50399 :       return gc_upto(av, Flx_to_ZX(z));
    2969              :     }
    2970              :   }
    2971        20130 :   d = get_FpX_degree(T);
    2972        20130 :   if (d==2)
    2973              :   {
    2974        19392 :     GEN P = get_FpX_mod(T);
    2975        19392 :     GEN c = gel(P,2), b = gel(P,3), a = gel(P,4), b2 = Fp_halve(b, p);
    2976        19392 :     GEN t = Fp_div(b2, a, p);
    2977        19392 :     GEN D = Fp_sub(Fp_sqr(b2, p), Fp_mul(a, c, p), p);
    2978        19823 :     GEN x = degpol(z)<1 ? constant_coeff(z)
    2979        19392 :                         : Fp_sub(gel(z,2), Fp_mul(gel(z,3), t, p), p);
    2980        19392 :     GEN y = degpol(z)<1 ? gen_0: gel(z,3);
    2981        19392 :     GEN r = Fp2_sqrt(mkvec2(x, y), D, p), s;
    2982        19392 :     if (!r) return gc_NULL(av);
    2983        18982 :     s = deg1pol_shallow(gel(r,2),Fp_add(gel(r,1), Fp_mul(gel(r,2),t,p), p), varn(P));
    2984        18982 :     return gc_GEN(av, s);
    2985              :   }
    2986          738 :   if (lgpol(z)<=1 && odd(d))
    2987              :   {
    2988            8 :     pari_sp av = avma;
    2989            8 :     GEN s = Fp_sqrt(constant_coeff(z), p);
    2990            8 :     if (!s) return gc_NULL(av);
    2991            8 :     return gc_GEN(av, scalarpol_shallow(s, get_FpX_var(T)));
    2992              :   } else
    2993              :   {
    2994              :     GEN p2, c, b, new_z, beta, x, y, w, ax;
    2995          730 :     long v = get_FpX_var(T);
    2996          730 :     if (!signe(z)) return pol_0(varn(z));
    2997          730 :     T = FpX_get_red(T, p);
    2998          730 :     ax = mkvec2(NULL, FpX_Frobenius(T,p));
    2999          730 :     p2 = shifti(p, -1); /* (p - 1) / 2 */
    3000              :     do {
    3001          730 :       do c = random_FpX(d, v, p); while (!signe(c));
    3002          730 :       new_z = FpXQ_mul(z, FpXQ_sqr(c, T, p), T, p);
    3003          730 :       gel(ax,1) = FpXQ_pow(new_z, p2, T, p);
    3004          730 :       y = FpXQ_sumautsum(ax, d-2, T, p); /* d > 2 */
    3005          730 :       b = FpX_Fp_add(y, gen_1, p);
    3006          730 :     } while (!signe(b));
    3007              : 
    3008          730 :     x = FpXQ_mul(new_z, FpXQ_sqr(b, T, p), T, p);
    3009          730 :     if (degpol(x) > 0) return gc_NULL(av);
    3010          716 :     beta = Fp_sqrt(constant_coeff(x), p);
    3011          716 :     if (!beta) return gc_NULL(av);
    3012          716 :     w = FpX_Fp_mul(FpXQ_inv(FpXQ_mul(b, c, T, p), T, p), beta, p);
    3013          716 :     return gc_GEN(av, w);
    3014              :   }
    3015              : }
    3016              : 
    3017              : GEN
    3018       363687 : FpXQ_norm(GEN x, GEN TB, GEN p)
    3019              : {
    3020       363687 :   pari_sp av = avma;
    3021       363687 :   GEN T = get_FpX_mod(TB);
    3022       363687 :   GEN y = FpX_resultant(T, x, p);
    3023       363687 :   GEN L = leading_coeff(T);
    3024       363687 :   if (gequal1(L) || signe(x)==0) return y;
    3025            0 :   return gc_upto(av, Fp_div(y, Fp_pows(L, degpol(x), p), p));
    3026              : }
    3027              : 
    3028              : GEN
    3029        21094 : FpXQ_trace(GEN x, GEN TB, GEN p)
    3030              : {
    3031        21094 :   pari_sp av = avma;
    3032        21094 :   GEN T = get_FpX_mod(TB);
    3033        21094 :   GEN dT = FpX_deriv(T,p);
    3034        21094 :   long n = degpol(dT);
    3035        21094 :   GEN z = FpXQ_mul(x, dT, TB, p);
    3036        21094 :   if (degpol(z)<n) return gc_const(av, gen_0);
    3037        19911 :   return gc_INT(av, Fp_div(gel(z,2+n), gel(T,3+n),p));
    3038              : }
    3039              : 
    3040              : GEN
    3041           15 : FpXQ_charpoly(GEN x, GEN T, GEN p)
    3042              : {
    3043           15 :   pari_sp ltop=avma;
    3044           15 :   long vT, v = fetch_var();
    3045              :   GEN R;
    3046           15 :   T = leafcopy(get_FpX_mod(T));
    3047           15 :   vT = varn(T); setvarn(T, v);
    3048           15 :   x = leafcopy(x); setvarn(x, v);
    3049           15 :   R = FpX_FpXY_resultant(T, deg1pol_shallow(gen_1,FpX_neg(x,p),vT),p);
    3050           15 :   (void)delete_var(); return gc_upto(ltop,R);
    3051              : }
    3052              : 
    3053              : /* Computing minimal polynomial :                         */
    3054              : /* cf Shoup 'Efficient Computation of Minimal Polynomials */
    3055              : /*          in Algebraic Extensions of Finite Fields'     */
    3056              : 
    3057              : /* Let v a linear form, return the linear form z->v(tau*z)
    3058              :    that is, v*(M_tau) */
    3059              : 
    3060              : static GEN
    3061         1660 : FpXQ_transmul_init(GEN tau, GEN T, GEN p)
    3062              : {
    3063              :   GEN bht;
    3064         1660 :   GEN h, Tp = get_FpX_red(T, &h);
    3065         1660 :   long n = degpol(Tp), vT = varn(Tp);
    3066         1660 :   GEN ft = FpX_recipspec(Tp+2, n+1, n+1);
    3067         1660 :   GEN bt = FpX_recipspec(tau+2, lgpol(tau), n);
    3068         1660 :   setvarn(ft, vT); setvarn(bt, vT);
    3069         1660 :   if (h)
    3070          602 :     bht = FpXn_mul(bt, h, n-1, p);
    3071              :   else
    3072              :   {
    3073         1058 :     GEN bh = FpX_div(FpX_shift(tau, n-1), T, p);
    3074         1058 :     bht = FpX_recipspec(bh+2, lgpol(bh), n-1);
    3075         1058 :     setvarn(bht, vT);
    3076              :   }
    3077         1660 :   return mkvec3(bt, bht, ft);
    3078              : }
    3079              : 
    3080              : static GEN
    3081         7175 : FpXQ_transmul(GEN tau, GEN a, long n, GEN p)
    3082              : {
    3083         7175 :   pari_sp ltop = avma;
    3084              :   GEN t1, t2, t3, vec;
    3085         7175 :   GEN bt = gel(tau, 1), bht = gel(tau, 2), ft = gel(tau, 3);
    3086         7175 :   if (signe(a)==0) return pol_0(varn(a));
    3087         7140 :   t2 = FpX_shift(FpX_mul(bt, a, p),1-n);
    3088         7140 :   if (signe(bht)==0) return gc_GEN(ltop, t2);
    3089         6289 :   t1 = FpX_shift(FpX_mul(ft, a, p),-n);
    3090         6289 :   t3 = FpXn_mul(t1, bht, n-1, p);
    3091         6289 :   vec = FpX_sub(t2, FpX_shift(t3, 1), p);
    3092         6289 :   return gc_upto(ltop, vec);
    3093              : }
    3094              : 
    3095              : GEN
    3096        14054 : FpXQ_minpoly(GEN x, GEN T, GEN p)
    3097              : {
    3098        14054 :   pari_sp ltop = avma;
    3099              :   long vT, n;
    3100              :   GEN v_x, g, tau;
    3101        14054 :   if (lgefint(p)==3)
    3102              :   {
    3103        13224 :     ulong pp = to_Flxq(&x, &T, p);
    3104        13224 :     GEN g = Flxq_minpoly(x, T, pp);
    3105        13224 :     return gc_upto(ltop, Flx_to_ZX(g));
    3106              :   }
    3107          830 :   vT = get_FpX_var(T);
    3108          830 :   n = get_FpX_degree(T);
    3109          830 :   g = pol_1(vT);
    3110          830 :   tau = pol_1(vT);
    3111          830 :   T = FpX_get_red(T, p);
    3112          830 :   x = FpXQ_red(x, T, p);
    3113          830 :   v_x = FpXQ_powers(x, usqrt(2*n), T, p);
    3114         1660 :   while(signe(tau) != 0)
    3115              :   {
    3116              :     long i, j, m, k1;
    3117              :     GEN M, v, tr;
    3118              :     GEN g_prime, c;
    3119          830 :     if (degpol(g) == n) { tau = pol_1(vT); g = pol_1(vT); }
    3120          830 :     v = random_FpX(n, vT, p);
    3121          830 :     tr = FpXQ_transmul_init(tau, T, p);
    3122          830 :     v = FpXQ_transmul(tr, v, n, p);
    3123          830 :     m = 2*(n-degpol(g));
    3124          830 :     k1 = usqrt(m);
    3125          830 :     tr = FpXQ_transmul_init(gel(v_x,k1+1), T, p);
    3126          830 :     c = cgetg(m+2,t_POL);
    3127          830 :     c[1] = evalsigne(1)|evalvarn(vT);
    3128         7175 :     for (i=0; i<m; i+=k1)
    3129              :     {
    3130         6345 :       long mj = minss(m-i, k1);
    3131        67555 :       for (j=0; j<mj; j++)
    3132        61210 :         gel(c,m+1-(i+j)) = FpX_dotproduct(v, gel(v_x,j+1), p);
    3133         6345 :       v = FpXQ_transmul(tr, v, n, p);
    3134              :     }
    3135          830 :     c = FpX_renormalize(c, m+2);
    3136              :     /* now c contains <v,x^i>, i = 0..m-1  */
    3137          830 :     M = FpX_halfgcd(pol_xn(m, vT), c, p);
    3138          830 :     g_prime = gmael(M, 2, 2);
    3139          830 :     if (degpol(g_prime) < 1) continue;
    3140          830 :     g = FpX_mul(g, g_prime, p);
    3141          830 :     tau = FpXQ_mul(tau, FpX_FpXQV_eval(g_prime, v_x, T, p), T, p);
    3142              :   }
    3143          830 :   g = FpX_normalize(g,p);
    3144          830 :   return gc_GEN(ltop,g);
    3145              : }
    3146              : 
    3147              : GEN
    3148            8 : FpXQ_conjvec(GEN x, GEN T, GEN p)
    3149              : {
    3150            8 :   pari_sp av=avma;
    3151              :   long i;
    3152            8 :   long n = get_FpX_degree(T), v = varn(x);
    3153            8 :   GEN M = FpX_matFrobenius(T, p);
    3154            8 :   GEN z = cgetg(n+1,t_COL);
    3155            8 :   gel(z,1) = RgX_to_RgC(x,n);
    3156           17 :   for (i=2; i<=n; i++) gel(z,i) = FpM_FpC_mul(M,gel(z,i-1),p);
    3157            8 :   gel(z,1) = x;
    3158           17 :   for (i=2; i<=n; i++) gel(z,i) = RgV_to_RgX(gel(z,i),v);
    3159            8 :   return gc_GEN(av,z);
    3160              : }
    3161              : 
    3162              : /* p prime, p_1 = p-1, q = p^deg T, Lp = cofactors of some prime divisors
    3163              :  * l_p of p-1, Lq = cofactors of some prime divisors l_q of q-1, return a
    3164              :  * g in Fq such that
    3165              :  * - Ng generates all l_p-Sylows of Fp^*
    3166              :  * - g generates all l_q-Sylows of Fq^* */
    3167              : static GEN
    3168        84149 : gener_FpXQ_i(GEN T, GEN p, GEN p_1, GEN Lp, GEN Lq)
    3169              : {
    3170              :   pari_sp av;
    3171        84149 :   long vT = varn(T), f = degpol(T), l = lg(Lq);
    3172        84149 :   GEN F = FpX_Frobenius(T, p);
    3173        84149 :   int p_is_2 = is_pm1(p_1);
    3174       168892 :   for (av = avma;; set_avma(av))
    3175        84743 :   {
    3176       168892 :     GEN t, g = random_FpX(f, vT, p);
    3177              :     long i;
    3178       168892 :     if (degpol(g) < 1) continue;
    3179       108651 :     if (p_is_2)
    3180        56563 :       t = g;
    3181              :     else
    3182              :     {
    3183        52088 :       t = FpX_resultant(T, g, p); /* Ng = g^((q-1)/(p-1)), assuming T monic */
    3184        52088 :       if (kronecker(t, p) == 1) continue;
    3185        31144 :       if (lg(Lp) > 1 && !is_gener_Fp(t, p, p_1, Lp)) continue;
    3186        29991 :       t = FpXQ_pow(g, shifti(p_1,-1), T, p);
    3187              :     }
    3188        99382 :     for (i = 1; i < l; i++)
    3189              :     {
    3190        15233 :       GEN a = FpXQ_pow_Frobenius(t, gel(Lq,i), F, T, p);
    3191        15233 :       if (!degpol(a) && equalii(gel(a,2), p_1)) break;
    3192              :     }
    3193        86554 :     if (i == l) return g;
    3194              :   }
    3195              : }
    3196              : 
    3197              : GEN
    3198         7030 : gener_FpXQ(GEN T, GEN p, GEN *po)
    3199              : {
    3200         7030 :   long i, j, f = get_FpX_degree(T);
    3201              :   GEN g, Lp, Lq, p_1, q_1, N, o;
    3202         7030 :   pari_sp av = avma;
    3203              : 
    3204         7030 :   p_1 = subiu(p,1);
    3205         7030 :   if (f == 1) {
    3206              :     GEN Lp, fa;
    3207            7 :     o = p_1;
    3208            7 :     fa = Z_factor(o);
    3209            7 :     Lp = gel(fa,1);
    3210            7 :     Lp = vecslice(Lp, 2, lg(Lp)-1); /* remove 2 for efficiency */
    3211              : 
    3212            7 :     g = cgetg(3, t_POL);
    3213            7 :     g[1] = evalsigne(1) | evalvarn(get_FpX_var(T));
    3214            7 :     gel(g,2) = pgener_Fp_local(p, Lp);
    3215            7 :     if (po) *po = mkvec2(o, fa);
    3216            7 :     return g;
    3217              :   }
    3218         7023 :   if (lgefint(p) == 3)
    3219              :   {
    3220         6986 :     ulong pp = to_Flxq(NULL, &T, p);
    3221         6986 :     g = gener_Flxq(T, pp, po);
    3222         6986 :     if (!po) return Flx_to_ZX_inplace(gc_leaf(av, g));
    3223         6986 :     g = Flx_to_ZX(g); return gc_all(av, 2, &g, po);
    3224              :   }
    3225              :   /* p now odd */
    3226           37 :   q_1 = subiu(powiu(p,f), 1);
    3227           37 :   N = diviiexact(q_1, p_1);
    3228           37 :   Lp = odd_prime_divisors(p_1);
    3229          168 :   for (i=lg(Lp)-1; i; i--) gel(Lp,i) = diviiexact(p_1, gel(Lp,i));
    3230           37 :   o = factor_pn_1(p,f);
    3231           37 :   Lq = leafcopy( gel(o, 1) );
    3232          353 :   for (i = j = 1; i < lg(Lq); i++)
    3233              :   {
    3234          316 :     if (dvdii(p_1, gel(Lq,i))) continue;
    3235          148 :     gel(Lq,j++) = diviiexact(N, gel(Lq,i));
    3236              :   }
    3237           37 :   setlg(Lq, j);
    3238           37 :   g = gener_FpXQ_i(get_FpX_mod(T), p, p_1, Lp, Lq);
    3239           37 :   if (!po) g = gc_GEN(av, g);
    3240              :   else {
    3241           21 :     *po = mkvec2(q_1, o);
    3242           21 :     (void)gc_all(av, 2, &g, po);
    3243              :   }
    3244           37 :   return g;
    3245              : }
    3246              : 
    3247              : GEN
    3248        84112 : gener_FpXQ_local(GEN T, GEN p, GEN L)
    3249              : {
    3250              :   GEN Lp, Lq, p_1, q_1, N, Q;
    3251              :   long f, i, ip, iq, l;
    3252              : 
    3253        84112 :   T = get_FpX_mod(T);
    3254        84112 :   f = degpol(T);
    3255        84112 :   if (f == 1) return pgener_Fp_local(p, L);
    3256        84112 :   l = lg(L);
    3257        84112 :   p_1 = subiu(p,1);
    3258        84112 :   q_1 = subiu(powiu(p,f), 1);
    3259        84112 :   N = diviiexact(q_1, p_1);
    3260              : 
    3261        84112 :   Q = is_pm1(p_1)? gen_1: shifti(p_1,-1);
    3262        84112 :   Lp = cgetg(l, t_VEC); ip = 1;
    3263        84112 :   Lq = cgetg(l, t_VEC); iq = 1;
    3264        99624 :   for (i=1; i < l; i++)
    3265              :   {
    3266        15512 :     GEN a, b, ell = gel(L,i);
    3267        15512 :     if (absequaliu(ell,2)) continue;
    3268        15232 :     a = dvmdii(Q, ell, &b);
    3269        15232 :     if (b == gen_0)
    3270         2555 :       gel(Lp,ip++) = a;
    3271              :     else
    3272        12677 :       gel(Lq,iq++) = diviiexact(N,ell);
    3273              :   }
    3274        84112 :   setlg(Lp, ip);
    3275        84112 :   setlg(Lq, iq);
    3276        84112 :   return gener_FpXQ_i(T, p, p_1, Lp, Lq);
    3277              : }
    3278              : 
    3279              : /***********************************************************************/
    3280              : /**                                                                   **/
    3281              : /**                              FpXn                                 **/
    3282              : /**                                                                   **/
    3283              : /***********************************************************************/
    3284              : 
    3285              : GEN
    3286      2564307 : FpXn_mul(GEN a, GEN b, long n, GEN p)
    3287              : {
    3288      2564307 :   return FpX_red(ZXn_mul(a, b, n), p);
    3289              : }
    3290              : 
    3291              : GEN
    3292            0 : FpXn_sqr(GEN a, long n, GEN p)
    3293              : {
    3294            0 :   return FpX_red(ZXn_sqr(a, n), p);
    3295              : }
    3296              : 
    3297              : /* (f*g) \/ x^n */
    3298              : static GEN
    3299       115055 : FpX_mulhigh_i(GEN f, GEN g, long n, GEN p)
    3300              : {
    3301       115055 :   return FpX_shift(FpX_mul(f,g, p),-n);
    3302              : }
    3303              : 
    3304              : static GEN
    3305        59480 : FpXn_mulhigh(GEN f, GEN g, long n2, long n, GEN p)
    3306              : {
    3307        59480 :   GEN F = RgX_blocks(f, n2, 2), fl = gel(F,1), fh = gel(F,2);
    3308        59480 :   return FpX_add(FpX_mulhigh_i(fl, g, n2, p), FpXn_mul(fh, g, n - n2, p), p);
    3309              : }
    3310              : 
    3311              : GEN
    3312         6412 : FpXn_div(GEN g, GEN f, long e, GEN p)
    3313              : {
    3314         6412 :   pari_sp av = avma, av2;
    3315              :   ulong mask;
    3316              :   GEN W, a;
    3317         6412 :   long v = varn(f), n = 1;
    3318              : 
    3319         6412 :   if (!signe(f)) pari_err_INV("FpXn_inv",f);
    3320         6412 :   a = Fp_inv(gel(f,2), p);
    3321         6412 :   if (e == 1 && !g) return scalarpol(a, v);
    3322         6412 :   else if (e == 2 && !g)
    3323              :   {
    3324              :     GEN b;
    3325            0 :     if (degpol(f) <= 0) return scalarpol(a, v);
    3326            0 :     b = Fp_neg(gel(f,3),p);
    3327            0 :     if (signe(b)==0) return scalarpol(a, v);
    3328            0 :     if (!is_pm1(a)) b = Fp_mul(b, Fp_sqr(a, p), p);
    3329            0 :     W = deg1pol_shallow(b, a, v);
    3330            0 :     return gc_GEN(av, W);
    3331              :   }
    3332         6412 :   W = scalarpol_shallow(Fp_inv(gel(f,2), p),v);
    3333         6412 :   mask = quadratic_prec_mask(e);
    3334         6412 :   av2 = avma;
    3335        27580 :   for (;mask>1;)
    3336              :   {
    3337              :     GEN u, fr;
    3338        21168 :     long n2 = n;
    3339        21168 :     n<<=1; if (mask & 1) n--;
    3340        21168 :     mask >>= 1;
    3341        21168 :     fr = FpXn_red(f, n);
    3342        21168 :     if (mask>1 || !g)
    3343              :     {
    3344        21168 :       u = FpXn_mul(W, FpXn_mulhigh(fr, W, n2, n, p), n-n2, p);
    3345        21168 :       W = FpX_sub(W, FpX_shift(u, n2), p);
    3346              :     }
    3347              :     else
    3348              :     {
    3349            0 :       GEN y = FpXn_mul(g, W, n, p), yt =  FpXn_red(y, n-n2);
    3350            0 :       u = FpXn_mul(yt, FpXn_mulhigh(fr,  W, n2, n, p), n-n2, p);
    3351            0 :       W = FpX_sub(y, FpX_shift(u, n2), p);
    3352              :     }
    3353        21168 :     if (gc_needed(av2,2))
    3354              :     {
    3355            0 :       if(DEBUGMEM>1) pari_warn(warnmem,"FpXn_inv, e = %ld", n);
    3356            0 :       W = gc_upto(av2, W);
    3357              :     }
    3358              :   }
    3359         6412 :   return gc_upto(av, W);
    3360              : }
    3361              : 
    3362              : GEN
    3363         6412 : FpXn_inv(GEN f, long e, GEN p)
    3364         6412 : { return FpXn_div(NULL, f, e, p); }
    3365              : 
    3366              : GEN
    3367        17263 : FpXn_expint(GEN h, long e, GEN p)
    3368              : {
    3369        17263 :   pari_sp av = avma, av2;
    3370        17263 :   long v = varn(h), n=1;
    3371        17263 :   GEN f = pol_1(v), g = pol_1(v);
    3372        17263 :   ulong mask = quadratic_prec_mask(e);
    3373        17263 :   av2 = avma;
    3374        55575 :   for (;mask>1;)
    3375              :   {
    3376              :     GEN u, w;
    3377        55575 :     long n2 = n;
    3378        55575 :     n<<=1; if (mask & 1) n--;
    3379        55575 :     mask >>= 1;
    3380        55575 :     u = FpXn_mul(g, FpX_mulhigh_i(f, FpXn_red(h, n2-1), n2-1, p), n-n2, p);
    3381        55575 :     u = FpX_add(u, FpX_shift(FpXn_red(h, n-1), 1-n2), p);
    3382        55575 :     w = FpXn_mul(f, FpX_integXn(u, n2-1, p), n-n2, p);
    3383        55575 :     f = FpX_add(f, FpX_shift(w, n2), p);
    3384        55575 :     if (mask<=1) break;
    3385        38312 :     u = FpXn_mul(g, FpXn_mulhigh(f, g, n2, n, p), n-n2, p);
    3386        38312 :     g = FpX_sub(g, FpX_shift(u, n2), p);
    3387        38312 :     if (gc_needed(av2,2))
    3388              :     {
    3389            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FpXn_exp, e = %ld", n);
    3390            0 :       (void)gc_all(av2, 2, &f, &g);
    3391              :     }
    3392              :   }
    3393        17263 :   return gc_upto(av, f);
    3394              : }
    3395              : 
    3396              : GEN
    3397            0 : FpXn_exp(GEN h, long e, GEN p)
    3398              : {
    3399            0 :   if (signe(h)==0 || degpol(h)<1 || !gequal0(gel(h,2)))
    3400            0 :     pari_err_DOMAIN("FpXn_exp","valuation", "<", gen_1, h);
    3401            0 :   return FpXn_expint(FpX_deriv(h, p), e, p);
    3402              : }
    3403              : 
    3404              : /****************************************************************************
    3405              :  ***                                                                      ***
    3406              :  ***                    FpXk                                              ***
    3407              :  ***                                                                      ***
    3408              :  ****************************************************************************/
    3409              : 
    3410              : /* FpXk: multivariate polynomials in FpX[X_1,...,X_k] */
    3411              : 
    3412              : INLINE GEN
    3413       115948 : FpXk_renormalize(GEN x, long lx)    { return ZXX_renormalize(x,lx); }
    3414              : 
    3415              : GEN
    3416      1215270 : FpXk_red(GEN z, GEN p)
    3417              : {
    3418      1215270 :   if (typ(z) == t_INT)
    3419      1102843 :     return modii(z, p);
    3420              :   else
    3421              :   {
    3422              :     long i,l;
    3423       112427 :     GEN x = cgetg_copy(z, &l);
    3424       112427 :     x[1] = z[1];
    3425      1304996 :     for (i = 2; i < l; i++)
    3426      1192569 :       gel(x,i) = FpXk_red(gel(z,i), p);
    3427       112427 :     return FpXk_renormalize(x, l);
    3428              :   }
    3429              : }
    3430              : 
    3431              : static GEN
    3432        20461 : FpXk_sub(GEN a, GEN b, GEN p)
    3433        20461 : { return FpXk_red(gsub(a, b), p); }
    3434              : 
    3435              : static GEN
    3436         2240 : FpXk_mul(GEN a, GEN b, GEN p)
    3437         2240 : { return FpXk_red(gmul(a, b), p); }
    3438              : 
    3439              : int
    3440            0 : Rg_is_FpXk(GEN z, GEN *p)
    3441              : {
    3442            0 :   long i, t = typ(z), l = lg(z);
    3443            0 :   if (t != t_POL) return Rg_is_Fp(z, p);
    3444            0 :   for (i = 2; i < l; i++)
    3445            0 :     if (!Rg_is_FpXk(gel(z,i), p)) return 0;
    3446            0 :   return 1;
    3447              : }
    3448              : 
    3449              : GEN
    3450       116669 : Rg_to_FpXk(GEN x, GEN p)
    3451              : {
    3452       116669 :   if (typ(x) != t_POL) return Rg_to_Fp(x, p);
    3453       143682 :   pari_APPLY_pol(Rg_to_FpXk(gel(x,i), p));
    3454              : }
    3455              : 
    3456              : static GEN
    3457        78813 : to_FpXXk(GEN x, long v)
    3458        78813 : { return typ(x)==t_INT ? scalarpol_shallow(x, v): x; }
    3459              : 
    3460              : static GEN
    3461        19530 : FpXXk_simplify(GEN x, long v)
    3462        19530 : { return to_FpXXk(simplify_shallow(x), v); }
    3463              : 
    3464              : static GEN
    3465        18186 : FpXXk_modXn(GEN z, long n, long v)
    3466              : {
    3467        18186 :   if (varn(z) == v)
    3468        15162 :     return RgXn_red_shallow(z, n);
    3469              :   else
    3470              :   {
    3471              :     long i,l;
    3472         3024 :     GEN x = cgetg_copy(z, &l);
    3473         3024 :     x[1] = z[1];
    3474        12509 :     for (i = 2; i < l; i++)
    3475         9485 :       gel(x,i) = FpXXk_modXn(to_FpXXk(gel(z,i), v), n, v);
    3476         3024 :     return RgX_renormalize_lg(x, l);
    3477              :   }
    3478              : }
    3479              : 
    3480              : static GEN
    3481        18186 : FpXXk_shift(GEN z, long n, long v)
    3482              : {
    3483        18186 :   if (varn(z) == v)
    3484        15162 :     return RgX_shift_shallow(z, n);
    3485              :   else
    3486              :   {
    3487              :     long i,l;
    3488         3024 :     GEN x = cgetg_copy(z, &l);
    3489         3024 :     x[1] = z[1];
    3490        12509 :     for (i = 2; i < l; i++)
    3491         9485 :       gel(x,i) = FpXXk_shift(to_FpXXk(gel(z,i), v), n, v);
    3492         3024 :     return RgX_renormalize_lg(x, l);
    3493              :   }
    3494              : }
    3495              : 
    3496              : static GEN FpXXk_gcd_i(GEN A, GEN B, GEN p, long v);
    3497              : static GEN
    3498         5334 : FpXXk_content(GEN x, GEN p, long v)
    3499              : {
    3500         5334 :   long i, l = lg(x);
    3501              :   GEN c;
    3502         5334 :   if (varn(x)==v) return gcopy(x);
    3503         5334 :   if (!signe(x)) return pol_0(v);
    3504         5334 :   c = to_FpXXk(gel(x,2), v);
    3505         5334 :   if (degpol(c)==0) return pol_1(v);
    3506        22757 :   for (i = 3; i < l; i++)
    3507              :   {
    3508        19530 :     c = FpXXk_simplify(FpXXk_gcd_i(c, to_FpXXk(gel(x,i), v), p, v), v);
    3509        19530 :     if (degpol(c)==0) return pol_1(v);
    3510              :   }
    3511         3227 :   return c;
    3512              : }
    3513              : 
    3514              : static GEN
    3515        10703 : FpXXk_content_FpX(GEN x, GEN p, long v)
    3516              : {
    3517        10703 :   long i, l = lg(x);
    3518              :   GEN c;
    3519        10703 :   if (typ(x)==t_INT) return Z_to_FpX(x, p, v);
    3520        10703 :   if (varn(x)==v) return x;
    3521         3304 :   if (!signe(x)) return pol_0(v);
    3522         3213 :   c = FpXXk_content_FpX(gel(x,2), p, v);
    3523         3213 :   if (degpol(c)==0) return pol_1(v);
    3524         5621 :   for (i = 3; i < l; i++)
    3525              :   {
    3526         4914 :     c = FpX_gcd(c, FpXXk_content_FpX(to_FpXXk(gel(x,i), v), p, v), p);
    3527         4914 :     if (degpol(c)==0) return pol_1(v);
    3528              :   }
    3529          707 :   return c;
    3530              : }
    3531              : 
    3532              : static GEN FpXXk_FpX_div(GEN A, GEN B, GEN p);
    3533              : 
    3534              : static GEN
    3535          378 : FpXXk_FpX_div_i(GEN x, GEN B, GEN p)
    3536          945 : { pari_APPLY_ZX(FpXXk_FpX_div(gel(x,i), B, p)); }
    3537              : 
    3538              : static GEN
    3539          945 : FpXXk_FpX_div(GEN A, GEN B, GEN p)
    3540              : {
    3541          945 :   long v = varn(B);
    3542          945 :   if (!signe(A)) return gen_0;
    3543          833 :   if (typ(A)==t_INT)
    3544            0 :     return FpX_div(Z_to_FpX(A, p, v), B, p);
    3545          833 :   else if (varn(A)!=v)
    3546          378 :     return FpXXk_FpX_div_i(A, B, p);
    3547              :   else
    3548          455 :     return FpX_div(A, B, p);
    3549              : }
    3550              : 
    3551              : static GEN
    3552         2576 : FpXXk_primpart_FpX(GEN x, GEN p, long v)
    3553              : {
    3554         2576 :   GEN c = FpXXk_content_FpX(x, p, v);
    3555         2576 :   return degpol(c) == 0 ? gcopy(x) : FpXXk_FpX_div(x, c, p);
    3556              : }
    3557              : 
    3558              : static long
    3559        26775 : RgXk_var_lowest(GEN x)
    3560              : {
    3561        26775 :   long i, l = lg(x), c = varn(x);
    3562       132419 :   for (i = 2; i < l; i++)
    3563       105644 :     if (typ(gel(x,i)) != t_INT)
    3564        25585 :       c = varnmin(c, RgXk_var_lowest(gel(x,i)));
    3565        26775 :   return c;
    3566              : }
    3567              : 
    3568              : static GEN FpXk_divexact_FpXXk(GEN A, GEN B, GEN p, long v);
    3569              : 
    3570              : static GEN
    3571         2814 : FpXkX_FpXk_divexact_FpXXk(GEN x, GEN B, GEN p, long v)
    3572        17486 : { pari_APPLY_ZX(FpXk_divexact_FpXXk(gel(x,i), B, p, v)) }
    3573              : 
    3574              : static GEN
    3575         2576 : FpXXkX_FpXXk_divexact(GEN A, GEN B, GEN p, long v)
    3576              : {
    3577         2576 :   pari_sp av = avma;
    3578         2576 :   return gc_upto(av, FpXkX_FpXk_divexact_FpXXk(A, simplify_shallow(B), p, v));
    3579              : }
    3580              : 
    3581              : static GEN
    3582          784 : FpXXk_divexact_i(GEN x, GEN y, GEN p, long v)
    3583              : {
    3584          784 :   long dx = degpol(x), dy = degpol(y), dz, i, j;
    3585          784 :   GEN z, y_lead = gel(y,dy+2);
    3586          784 :   if (dx < dy)
    3587            0 :     return pol_0(v);
    3588          784 :   dz = dx-dy;
    3589          784 :   z = cgetg(dz+3,t_POL); z[1] = x[1];
    3590          784 :   gel(z,dz+2) = FpXk_divexact_FpXXk(gel(x,dx+2), y_lead, p, v);
    3591         3108 :   for (i=dx-1; i>=dy; i--)
    3592              :   {
    3593         2324 :     pari_sp btop = avma;
    3594         2324 :     GEN p1=gel(x,2+i);
    3595         6594 :     for (j=i-dy+1; j<=i && j<=dz; j++)
    3596         4270 :       p1 = FpXk_sub(p1, gmul(gel(z,2+j), gel(y,2+i-j)), p);
    3597         2324 :     gel(z,2+i-dy) = gc_upto(btop, FpXk_divexact_FpXXk(p1, y_lead, p, v));
    3598              :   }
    3599          784 :   return z;
    3600              : }
    3601              : 
    3602              : static GEN
    3603        17780 : FpXk_divexact_FpXXk(GEN A, GEN B, GEN p, long v)
    3604              : {
    3605        17780 :   if (!signe(B)) pari_err_INV("gcd", gmodulo(B,p));
    3606        17780 :   if (!signe(A)) return pol_0(v);
    3607        12257 :   if (typ(A)==t_INT)
    3608              :   {
    3609           70 :     if (typ(B)==t_INT)
    3610           70 :       return to_FpXXk(Fp_div(A, B, p), v);
    3611            0 :     A = to_FpXXk(A, v);
    3612        12187 :   } else if (typ(B)==t_INT)
    3613         1778 :     B = to_FpXXk(B, v);
    3614        12187 :   if (varn(A)==v && varn(B)==v)
    3615        11165 :     return FpX_div(A, B, p);
    3616         1022 :   else if (varncmp(varn(A),varn(B)) < 0)
    3617          238 :     return FpXkX_FpXk_divexact_FpXXk(A, B, p, v);
    3618              :   else
    3619          784 :     return FpXXk_divexact_i(A, B, p, v);
    3620              : }
    3621              : 
    3622              : #if 0
    3623              : static GEN
    3624              : FpXXk_divexact(GEN A, GEN B, GEN p, long v)
    3625              : {
    3626              :   pari_sp av = avma;
    3627              :   return gc_upto(av, FpXXk_divexact_s(A, FpXXk_simplify(B)));
    3628              : }
    3629              : #endif
    3630              : 
    3631              : static GEN FpXk_divides_FpXXk(GEN A, GEN B, GEN p, long v);
    3632              : 
    3633              : static GEN
    3634         4284 : FpXXk_divides_i(pari_sp av, GEN x, GEN y, GEN p, long v)
    3635              : {
    3636              :   pari_sp av2;
    3637         4284 :   long dx = degpol(x), dy = degpol(y), dz, i, j, s;
    3638         4284 :   GEN z, y_lead = gel(y,dy+2);
    3639         4284 :   if (dx < dy)
    3640            0 :     return NULL;
    3641         4284 :   dz = dx-dy;
    3642         4284 :   z = cgetg(dz+3,t_POL); z[1] = x[1];
    3643         4284 :   gel(z,dz+2) = FpXk_divides_FpXXk(gel(x,dx+2), y_lead, p, v);
    3644         4284 :   if (!gel(z,dz+2)) return gc_NULL(av);
    3645        12068 :   for (i=dx-1; i>=dy; i--)
    3646              :   {
    3647         7784 :     pari_sp btop = avma;
    3648         7784 :     GEN p1 = gel(x,2+i), c;
    3649        19691 :     for (j=i-dy+1; j<=i && j<=dz; j++)
    3650        11907 :       p1 = FpXk_sub(p1, gmul(gel(z,2+j), gel(y,2+i-j)), p);
    3651         7784 :     c = FpXk_divides_FpXXk(p1, y_lead, p, v);
    3652         7784 :     if (!c) return gc_NULL(av);
    3653         7784 :     gel(z,2+i-dy) = gc_upto(btop, c);
    3654              :   }
    3655         4284 :   av2 = avma;
    3656         4284 :   s = gc_long(av2,signe(FpXk_sub(gmul(z,y),x,p)));
    3657         4284 :   return s ? gc_NULL(av): gc_GEN(av, z);
    3658              : }
    3659              : 
    3660              : static GEN
    3661         3521 : FpXXkX_FpXk_divides_FpXXk(GEN x, GEN B, GEN p, long v)
    3662              : {
    3663         3521 :   pari_sp av = avma;
    3664              :   long i, l;
    3665         3521 :   GEN y = cgetg_copy(x, &l); y[1] = x[1];
    3666         3521 :   if (l == 2) return y;
    3667        16233 :   for (i=2; i<l; i++)
    3668              :   {
    3669        12712 :     GEN c = FpXk_divides_FpXXk(gel(x,i), B, p, v);
    3670        12712 :     if (!c) return gc_NULL(av);
    3671        12712 :     gel(y, i) = c;
    3672              :   }
    3673         3521 :   return FpXk_renormalize(y, l);
    3674              : }
    3675              : 
    3676              : static GEN
    3677        29631 : FpXk_divides_FpXXk(GEN A, GEN B, GEN p, long v)
    3678              : {
    3679        29631 :   pari_sp av = avma;
    3680        29631 :   if (!signe(B)) pari_err_INV("gcd", gmodulo(B,p));
    3681        29631 :   if (!signe(A)) return pol_0(v);
    3682        24038 :   if (typ(A)==t_INT)
    3683              :   {
    3684         1645 :     if (typ(B)==t_INT)
    3685          812 :       return to_FpXXk(Fp_div(A, B, p), v);
    3686          833 :     A = to_FpXXk(A, v);
    3687        22393 :   } else if (typ(B)==t_INT)
    3688         7042 :     B = to_FpXXk(B, v);
    3689        23226 :   if (varn(A)==v && varn(B)==v)
    3690        15421 :     return FpX_div(A, B, p);
    3691         7805 :   else if (varncmp(varn(A),varn(B)) < 0)
    3692         3521 :     return FpXXkX_FpXk_divides_FpXXk(A, B, p, v);
    3693              :   else
    3694         4284 :     return FpXXk_divides_i(av, A, B, p, v);
    3695              : }
    3696              : 
    3697              : static GEN
    3698         4851 : FpXXk_divides(GEN A, GEN B, GEN p, long v)
    3699              : {
    3700         4851 :   pari_sp av = avma;
    3701         4851 :   GEN z = FpXk_divides_FpXXk(A, simplify_shallow(B), p, v);
    3702         4851 :   return z ? gc_upto(av, z): z;
    3703              : }
    3704              : 
    3705              : static GEN
    3706         2576 : FpXXk_rec(GEN g, long e, long v, long w)
    3707              : {
    3708         2576 :   pari_sp av = avma;
    3709         2576 :   long i, d = (poldegree(g,w)+2*e-1)/e;
    3710         2576 :   GEN s = cgetg(d+3,t_POL);
    3711         2576 :   s[1] = evalvarn(v);
    3712         8701 :   for (i = 0; i <= d; i++)
    3713              :   {
    3714         8701 :     GEN c = FpXXk_modXn(g, e, w);
    3715         8701 :     gel(s,i+2) = c;
    3716         8701 :     g = FpXXk_shift(g,-e,w);
    3717         8701 :     if (!signe(g)) break;
    3718              :   }
    3719         2576 :   s = RgX_renormalize_lg(s,i+3);
    3720         2576 :   return gc_GEN(av, s);
    3721              : }
    3722              : 
    3723              : static GEN
    3724        25795 : FpXXk_gcd_i(GEN A, GEN B, GEN p, long v)
    3725              : {
    3726              :   pari_sp av;
    3727              :   long e, va, vc;
    3728              :   GEN c, cA, cB;
    3729        25795 :   if (signe(A)==0) return gcopy(B);
    3730        22379 :   if (signe(B)==0) return gcopy(A);
    3731        18963 :   if (degpol(A) == 0 || degpol(B) == 0) return pol_1(v);
    3732        16240 :   va = varn(A); vc = varncmp(va, varn(B));
    3733        16240 :   if (vc < 0) return FpXXk_gcd_i(FpXXk_content(A, p, v), B, p, v);
    3734        15813 :   if (vc > 0) return FpXXk_gcd_i(A, FpXXk_content(B, p, v), p, v);
    3735        15386 :   if (va == v) return FpX_normalize(FpX_gcd(A, B, p), p);
    3736         2240 :   cA = FpXXk_content(A, p, v);
    3737         2240 :   if (degpol(cA)) A = FpXXkX_FpXXk_divexact(A, cA, p, v);
    3738         2240 :   cB = FpXXk_content(B, p, v);
    3739         2240 :   if (degpol(cB)) B = FpXXkX_FpXXk_divexact(B, cB, p, v);
    3740         2240 :   c = FpXXk_gcd_i(cA, cB, p, v); av = avma;
    3741         2240 :   e = maxss(minss(poldegree(A,v), poldegree(B,v)) + 2, 3);
    3742          336 :   for ( ; ; e++, set_avma(av))
    3743          336 :   {
    3744         2576 :     GEN N = monomial(gen_1,e,v), G = FpXXk_gcd_i(poleval(A,N), poleval(B,N), p, v);
    3745         2576 :     GEN g = FpXXk_primpart_FpX(FpXXk_rec(G, e, va, v), p, v);
    3746         2576 :     if (FpXXk_divides(A,g,p,v) &&  FpXXk_divides(B,g,p,v))
    3747         2240 :       return FpXk_mul(c, g, p);
    3748          336 :     if (DEBUGLEVEL>=3) err_printf("FpXk_gcd: increasing interpolation degree to %ld\n",e+1);
    3749              :   }
    3750              : }
    3751              : 
    3752              : GEN
    3753          595 : FpXk_gcd(GEN A, GEN B, GEN p)
    3754              : {
    3755          595 :   pari_sp av = avma;
    3756          595 :   long v = varnmin(RgXk_var_lowest(A), RgXk_var_lowest(B));
    3757          595 :   return gc_upto(av, FpXXk_gcd_i(A, B, p, v));
    3758              : }
        

Generated by: LCOV version 2.0-1