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 - FpXX.c (source / functions) Coverage Total Hit
Test: PARI/GP v2.18.1 lcov report (development 31042-0fbe168e69) Lines: 76.8 % 1229 944
Test Date: 2026-07-23 17:04:59 Functions: 84.4 % 135 114
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Copyright (C) 2012  The PARI group.
       2              : 
       3              : This file is part of the PARI/GP package.
       4              : 
       5              : PARI/GP is free software; you can redistribute it and/or modify it under the
       6              : terms of the GNU General Public License as published by the Free Software
       7              : Foundation; 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 FpX */
      19              : 
      20              : /*******************************************************************/
      21              : /*                                                                 */
      22              : /*                             FpXX                                */
      23              : /*                                                                 */
      24              : /*******************************************************************/
      25              : /*Polynomials whose coefficients are either polynomials or integers*/
      26              : 
      27              : static GEN
      28        51968 : to_ZX(GEN a, long v) { return typ(a)==t_INT? scalarpol_shallow(a,v): a; }
      29              : 
      30              : static ulong
      31      1256078 : to_FlxqX(GEN P, GEN Q, GEN T, GEN p, GEN *pt_P, GEN *pt_Q, GEN *pt_T)
      32              : {
      33      1256078 :   ulong pp = uel(p,2);
      34      1256078 :   long v = get_FpX_var(T);
      35      1256078 :   *pt_P = ZXX_to_FlxX(P, pp, v);
      36      1256078 :   if (pt_Q) *pt_Q = ZXX_to_FlxX(Q, pp, v);
      37      1256078 :   *pt_T = ZXT_to_FlxT(T, pp);
      38      1256078 :   return pp;
      39              : }
      40              : 
      41              : static GEN
      42          126 : ZXX_copy(GEN a) { return gcopy(a); }
      43              : 
      44              : GEN
      45        40693 : FpXX_red(GEN z, GEN p)
      46              : {
      47              :   GEN res;
      48        40693 :   long i, l = lg(z);
      49        40693 :   res = cgetg(l,t_POL); res[1] = z[1];
      50       284553 :   for (i=2; i<l; i++)
      51              :   {
      52       243860 :     GEN zi = gel(z,i), c;
      53       243860 :     if (typ(zi)==t_INT)
      54        14938 :       c = modii(zi,p);
      55              :     else
      56              :     {
      57       228922 :       pari_sp av = avma;
      58       228922 :       c = FpX_red(zi,p);
      59       228922 :       switch(lg(c)) {
      60          931 :         case 2: set_avma(av); c = gen_0; break;
      61        20925 :         case 3: c = gc_GEN(av, gel(c,2)); break;
      62              :       }
      63              :     }
      64       243860 :     gel(res,i) = c;
      65              :   }
      66        40693 :   return FpXX_renormalize(res,lg(res));
      67              : }
      68              : GEN
      69       441507 : FpXX_add(GEN x, GEN y, GEN p)
      70              : {
      71              :   long i,lz;
      72              :   GEN z;
      73       441507 :   long lx=lg(x);
      74       441507 :   long ly=lg(y);
      75       441507 :   if (ly>lx) swapspec(x,y, lx,ly);
      76       441507 :   lz = lx; z = cgetg(lz, t_POL); z[1]=x[1];
      77      9324594 :   for (i=2; i<ly; i++) gel(z,i) = Fq_add(gel(x,i), gel(y,i), NULL, p);
      78      1664001 :   for (   ; i<lx; i++) gel(z,i) = gcopy(gel(x,i));
      79       441507 :   return FpXX_renormalize(z, lz);
      80              : }
      81              : GEN
      82        29848 : FpXX_sub(GEN x, GEN y, GEN p)
      83              : {
      84              :   long i,lz;
      85              :   GEN z;
      86        29848 :   long lx=lg(x);
      87        29848 :   long ly=lg(y);
      88        29848 :   if (ly <= lx)
      89              :   {
      90        15164 :     lz = lx; z = cgetg(lz, t_POL); z[1]=x[1];
      91       195446 :     for (i=2; i<ly; i++) gel(z,i) = Fq_sub(gel(x,i), gel(y,i), NULL, p);
      92        32764 :     for (   ; i<lx; i++) gel(z,i) = gcopy(gel(x,i));
      93              :   }
      94              :   else
      95              :   {
      96        14684 :     lz = ly; z = cgetg(lz, t_POL); z[1]=x[1];
      97        91149 :     for (i=2; i<lx; i++) gel(z,i) = Fq_sub(gel(x,i), gel(y,i), NULL, p);
      98        54223 :     for (   ; i<ly; i++) gel(z,i) = Fq_neg(gel(y,i), NULL, p);
      99              :   }
     100        29848 :   return FpXX_renormalize(z, lz);
     101              : }
     102              : 
     103              : static GEN
     104       149377 : FpXX_subspec(GEN x, GEN y, GEN p, long nx, long ny)
     105              : {
     106              :   long i,lz;
     107              :   GEN z;
     108       149377 :   if (ny <= nx)
     109              :   {
     110       149377 :     lz = nx+2; z = cgetg(lz, t_POL);
     111      3688929 :     for (i=0; i<ny; i++) gel(z,i+2) = Fq_sub(gel(x,i), gel(y,i), NULL, p);
     112       149377 :     for (   ; i<nx; i++) gel(z,i+2) = gcopy(gel(x,i));
     113              :   }
     114              :   else
     115              :   {
     116            0 :     lz = ny+2; z = cgetg(lz, t_POL);
     117            0 :     for (i=0; i<nx; i++) gel(z,i+2) = Fq_sub(gel(x,i), gel(y,i), NULL, p);
     118            0 :     for (   ; i<ny; i++) gel(z,i+2) = Fq_neg(gel(y,i), NULL, p);
     119              :   }
     120       149377 :   z[1] = 0; return FpXX_renormalize(z, lz);
     121              : }
     122              : 
     123              : GEN
     124         2017 : FpXX_neg(GEN x, GEN p)
     125              : {
     126         2017 :   long i, lx = lg(x);
     127         2017 :   GEN y = cgetg(lx,t_POL);
     128         2017 :   y[1] = x[1];
     129        53397 :   for(i=2; i<lx; i++) gel(y,i) = Fq_neg(gel(x,i), NULL, p);
     130         2017 :   return FpXX_renormalize(y, lx);
     131              : }
     132              : 
     133              : GEN
     134            0 : FpXX_Fp_sub(GEN x, GEN y, GEN p)
     135              : {
     136            0 :   long i, l = lg(x);
     137              :   GEN z, a;
     138            0 :   if (signe(x)==0) return scalarpol(Fp_red(y, p),varn(x));
     139            0 :   z = cgetg(l,t_POL); z[1] = x[1];
     140            0 :   a = gel(x,2);
     141            0 :   gel(z, 2) = typ(a)==t_INT? Fp_sub(a, y, p): FpX_Fp_sub(a, y, p);
     142            0 :   for (i = 3; i < l; i++)
     143            0 :     gel(z,i) = gcopy(gel(x,i));
     144            0 :   return z;
     145              : }
     146              : 
     147              : GEN
     148        56546 : FpXX_Fp_mul(GEN P, GEN u, GEN p)
     149              : {
     150              :   long i, lP;
     151        56546 :   GEN res = cgetg_copy(P, &lP); res[1] = P[1];
     152       484471 :   for(i=2; i<lP; i++)
     153              :   {
     154       427925 :     GEN x = gel(P,i);
     155       427925 :     gel(res,i) = typ(x)==t_INT? Fp_mul(x,u,p): FpX_Fp_mul(x,u,p);
     156              :   }
     157        56546 :   return FpXX_renormalize(res,lP);
     158              : }
     159              : 
     160              : GEN
     161         7074 : FpXX_mulu(GEN P, ulong u, GEN p)
     162              : {
     163              :   long i, lP;
     164         7074 :   GEN res = cgetg_copy(P, &lP); res[1] = P[1];
     165        52097 :   for(i=2; i<lP; i++)
     166              :   {
     167        45023 :     GEN x = gel(P,i);
     168        45023 :     gel(res,i) = typ(x)==t_INT? Fp_mulu(x,u,p): FpX_mulu(x,u,p);
     169              :   }
     170         7074 :   return FpXX_renormalize(res,lP);
     171              : }
     172              : 
     173              : GEN
     174         2079 : FpXX_halve(GEN P, GEN p)
     175              : {
     176              :   long i, lP;
     177         2079 :   GEN res = cgetg_copy(P, &lP); res[1] = P[1];
     178         7287 :   for(i=2; i<lP; i++)
     179              :   {
     180         5208 :     GEN x = gel(P,i);
     181         5208 :     gel(res,i) = typ(x)==t_INT? Fp_halve(x,p): FpX_halve(x,p);
     182              :   }
     183         2079 :   return FpXX_renormalize(res,lP);
     184              : }
     185              : 
     186              : GEN
     187        12978 : FpXX_deriv(GEN P, GEN p)
     188              : {
     189        12978 :   long i, l = lg(P)-1;
     190              :   GEN res;
     191              : 
     192        12978 :   if (l < 3) return pol_0(varn(P));
     193        12684 :   res = cgetg(l, t_POL);
     194        12684 :   res[1] = P[1];
     195        78076 :   for (i=2; i<l ; i++)
     196              :   {
     197        65392 :     GEN x = gel(P,i+1);
     198        65392 :     gel(res,i) = typ(x)==t_INT? Fp_mulu(x,i-1,p): FpX_mulu(x,i-1,p);
     199              :   }
     200        12684 :   return FpXX_renormalize(res, l);
     201              : }
     202              : 
     203              : GEN
     204            0 : FpXX_integ(GEN P, GEN p)
     205              : {
     206            0 :   long i, l = lg(P);
     207              :   GEN res;
     208              : 
     209            0 :   if (l == 2) return pol_0(varn(P));
     210            0 :   res = cgetg(l+1, t_POL);
     211            0 :   res[1] = P[1];
     212            0 :   gel(res,2) = gen_0;
     213            0 :   for (i=3; i<=l ; i++)
     214              :   {
     215            0 :     GEN x = gel(P,i-1);
     216            0 :     if (signe(x))
     217              :     {
     218            0 :       GEN i1 = Fp_inv(utoi(i-2), p);
     219            0 :       gel(res,i) = typ(x)==t_INT? Fp_mul(x,i1,p): FpX_Fp_mul(x,i1,p);
     220              :     } else
     221            0 :       gel(res,i) = gen_0;
     222              :   }
     223            0 :   return FpXX_renormalize(res, l+1);
     224              : }
     225              : 
     226              : /*******************************************************************/
     227              : /*                                                                 */
     228              : /*                             (Fp[X]/(Q))[Y]                      */
     229              : /*                                                                 */
     230              : /*******************************************************************/
     231              : 
     232              : static GEN
     233      1334528 : get_FpXQX_red(GEN T, GEN *B)
     234              : {
     235      1334528 :   if (typ(T)!=t_VEC) { *B=NULL; return T; }
     236        91087 :   *B = gel(T,1); return gel(T,2);
     237              : }
     238              : 
     239              : GEN
     240           52 : random_FpXQX(long d1, long v, GEN T, GEN p)
     241              : {
     242           52 :   long dT = get_FpX_degree(T), vT = get_FpX_var(T);
     243           52 :   long i, d = d1+2;
     244           52 :   GEN y = cgetg(d,t_POL); y[1] = evalsigne(1) | evalvarn(v);
     245          284 :   for (i=2; i<d; i++) gel(y,i) = random_FpX(dT, vT, p);
     246           52 :   return FpXQX_renormalize(y,d);
     247              : }
     248              : 
     249              : /*Not stack clean*/
     250              : GEN
     251      1842875 : Kronecker_to_FpXQX(GEN Z, GEN T, GEN p)
     252              : {
     253      1842875 :   long i,j,lx,l, N = (get_FpX_degree(T)<<1) + 1;
     254      1842875 :   GEN x, t = cgetg(N,t_POL), z = FpX_red(Z, p);
     255      1842875 :   t[1] = evalvarn(get_FpX_var(T));
     256      1842875 :   l = lg(z); lx = (l-2) / (N-2);
     257      1842875 :   x = cgetg(lx+3,t_POL);
     258      1842875 :   x[1] = z[1];
     259     29280973 :   for (i=2; i<lx+2; i++)
     260              :   {
     261    231298478 :     for (j=2; j<N; j++) gel(t,j) = gel(z,j);
     262     27438098 :     z += (N-2);
     263     27438098 :     gel(x,i) = FpX_rem(FpX_renormalize(t,N), T,p);
     264              :   }
     265      1842875 :   N = (l-2) % (N-2) + 2;
     266      3031767 :   for (j=2; j<N; j++) gel(t,j) = gel(z,j);
     267      1842875 :   gel(x,i) = FpX_rem(FpX_renormalize(t,N), T,p);
     268      1842875 :   return FpXQX_renormalize(x, i+1);
     269              : }
     270              : 
     271              : GEN
     272      1927223 : FpXQX_red(GEN z, GEN T, GEN p)
     273              : {
     274      1927223 :   long i, l = lg(z);
     275      1927223 :   GEN res = cgetg(l,t_POL); res[1] = z[1];
     276     15906998 :   for(i=2;i<l;i++)
     277     13979775 :     if (typ(gel(z,i)) == t_INT)
     278       159729 :       gel(res,i) = modii(gel(z,i),p);
     279              :     else
     280     13820046 :       gel(res,i) = FpXQ_red(gel(z,i),T,p);
     281      1927223 :   return FpXQX_renormalize(res,l);
     282              : }
     283              : 
     284              : GEN
     285            0 : FpXQXV_red(GEN x, GEN T, GEN p)
     286            0 : { pari_APPLY_type(t_VEC, FpXQX_red(gel(x,i), T, p)) }
     287              : 
     288              : GEN
     289            0 : FpXQXT_red(GEN x, GEN T, GEN p)
     290              : {
     291            0 :   if (typ(x) == t_POL)
     292            0 :     return FpXQX_red(x, T, p);
     293              :   else
     294            0 :     pari_APPLY_type(t_VEC, FpXQXT_red(gel(x,i), T, p))
     295              : }
     296              : 
     297              : static GEN
     298         2191 : to_intmod(GEN x, GEN p) { retmkintmod(modii(x, p), p); }
     299              : 
     300              : GEN
     301          532 : FpXQX_to_mod(GEN z, GEN T, GEN p)
     302              : {
     303          532 :   long i, l = lg(z);
     304              :   GEN x;
     305          532 :   if (l == 2)
     306              :   {
     307            0 :     x = cgetg(3, t_POL); x[1] = z[1];
     308            0 :     p = icopy(p); T = FpX_to_mod_raw(T, p);
     309            0 :     gel(x,2) = mkpolmod(mkintmod(gen_0, p), T);
     310            0 :     return x;
     311              :   }
     312          532 :   x = cgetg(l, t_POL); x[1] = z[1];
     313          532 :   p = icopy(p); T = FpX_to_mod_raw(T, p);
     314         6720 :   for (i=2; i<l; i++)
     315              :   {
     316         6188 :     GEN zi = gel(z,i);
     317         6188 :     gel(x,i) = typ(zi) == t_POL? mkpolmod(FpX_to_mod_raw(zi, p), T)
     318         6188 :                                : to_intmod(zi, p);
     319              :   }
     320          532 :   return normalizepol_lg(x,l);
     321              : }
     322              : 
     323              : static GEN
     324            0 : FpXQX_to_mod_raw(GEN z, GEN T, GEN p)
     325              : {
     326            0 :   long i, l = lg(z);
     327              :   GEN x;
     328              : 
     329            0 :   if (l == 2)
     330              :   {
     331            0 :     x = cgetg(3, t_POL); x[1] = z[1];
     332            0 :     p = icopy(p);
     333            0 :     gel(x,2) = mkpolmod(mkintmod(gen_0, p), T);
     334            0 :     return x;
     335              :   }
     336            0 :   x = cgetg(l, t_POL); x[1] = z[1];
     337            0 :   for (i=2; i<l; i++)
     338              :   {
     339            0 :     GEN zi = gel(z,i);
     340            0 :     gel(x,i) = typ(zi) == t_POL? mkpolmod(FpX_to_mod_raw(zi, p), T)
     341            0 :                                : to_intmod(zi, p);
     342              :   }
     343            0 :   return normalizepol_lg(x,l);
     344              : }
     345              : 
     346              : INLINE GEN
     347            0 : FqX_to_mod_raw(GEN f, GEN T, GEN p)
     348            0 : { return T?FpXQX_to_mod_raw(f, T, p): FpX_to_mod_raw(f, p); }
     349              : 
     350              : static GEN
     351            0 : FqXC_to_mod_raw(GEN x, GEN T, GEN p)
     352            0 : { pari_APPLY_type(t_COL, FqX_to_mod_raw(gel(x,i), T, p)) }
     353              : 
     354              : GEN
     355           14 : FqXC_to_mod(GEN z, GEN T, GEN p)
     356              : {
     357              :   GEN x;
     358           14 :   long i,l = lg(z);
     359           14 :   if (!T) return FpXC_to_mod(z, p);
     360            0 :   x = cgetg(l, t_COL);
     361            0 :   if (l == 1) return x;
     362            0 :   p = icopy(p);
     363            0 :   T = FpX_to_mod_raw(T, p);
     364            0 :   for (i=1; i<l; i++)
     365            0 :     gel(x,i) = FqX_to_mod_raw(gel(z, i), T, p);
     366            0 :   return x;
     367              : }
     368              : 
     369              : GEN
     370            0 : FqXM_to_mod(GEN z, GEN T, GEN p)
     371              : {
     372              :   GEN x;
     373            0 :   long i,l = lg(z);
     374            0 :   if (!T) return FpXM_to_mod(z, p);
     375            0 :   x = cgetg(l, t_MAT);
     376            0 :   if (l == 1) return x;
     377            0 :   p = icopy(p);
     378            0 :   T = FpX_to_mod_raw(T, p);
     379            0 :   for (i=1; i<l; i++)
     380            0 :     gel(x,i) = FqXC_to_mod_raw(gel(z, i), T, p);
     381            0 :   return x;
     382              : }
     383              : 
     384              : static int
     385      3549521 : ZXX_is_ZX_spec(GEN a,long na)
     386              : {
     387              :   long i;
     388      3852261 :   for(i=0;i<na;i++)
     389      3794678 :     if(typ(gel(a,i))!=t_INT) return 0;
     390        57583 :   return 1;
     391              : }
     392              : 
     393              : static int
     394       235889 : ZXX_is_ZX(GEN a) { return ZXX_is_ZX_spec(a+2,lgpol(a)); }
     395              : 
     396              : static GEN
     397       140194 : FpXX_FpX_mulspec(GEN P, GEN U, GEN p, long v, long lU)
     398              : {
     399       140194 :   long i, lP =lg(P);
     400              :   GEN res;
     401       140194 :   res = cgetg(lP, t_POL); res[1] = P[1];
     402      7689541 :   for(i=2; i<lP; i++)
     403              :   {
     404      7549347 :     GEN Pi = gel(P,i);
     405      7549347 :     gel(res,i) = typ(Pi)==t_INT? FpX_Fp_mulspec(U, Pi, p, lU):
     406      7534820 :                                  FpX_mulspec(U, Pi+2, p, lU, lgpol(Pi));
     407      7549347 :     setvarn(gel(res,i),v);
     408              :   }
     409       140194 :   return FpXQX_renormalize(res,lP);
     410              : }
     411              : 
     412              : GEN
     413       125115 : FpXX_FpX_mul(GEN P, GEN U, GEN p)
     414       125115 : { return FpXX_FpX_mulspec(P,U+2,p,varn(U),lgpol(U)); }
     415              : 
     416              : static GEN
     417        15079 : FpXY_FpY_mulspec(GEN x, GEN y, GEN T, GEN p, long lx, long ly)
     418              : {
     419        15079 :   pari_sp av = avma;
     420        15079 :   long v = get_FpX_var(T);
     421        15079 :   GEN z = RgXY_swapspec(x,get_FpX_degree(T)-1,v,lx);
     422        15079 :   z = FpXX_FpX_mulspec(z,y,p,v,ly);
     423        15079 :   z = RgXY_swapspec(z+2,lx+ly+3,v,lgpol(z));
     424        15079 :   return gc_GEN(av,z);
     425              : }
     426              : 
     427              : static GEN
     428      1656816 : FpXQX_mulspec(GEN x, GEN y, GEN T, GEN p, long lx, long ly)
     429              : {
     430      1656816 :   pari_sp av = avma;
     431              :   GEN z, kx, ky;
     432              :   long n;
     433      1656816 :   if (ZXX_is_ZX_spec(y,ly))
     434              :   {
     435        14962 :     if (ZXX_is_ZX_spec(x,lx))
     436         7753 :       return FpX_mulspec(x,y,p,lx,ly);
     437              :     else
     438         7209 :       return FpXY_FpY_mulspec(x,y,T,p,lx,ly);
     439      1641854 :   } else if (ZXX_is_ZX_spec(x,lx))
     440         7870 :       return FpXY_FpY_mulspec(y,x,T,p,ly,lx);
     441      1633984 :   n = get_FpX_degree(T);
     442      1633984 :   kx = RgXX_to_Kronecker_spec(x, lx, n);
     443      1633984 :   ky = RgXX_to_Kronecker_spec(y, ly, n);
     444      1633984 :   z = Kronecker_to_FpXQX(ZX_mul(ky,kx), T, p);
     445      1633984 :   return gc_upto(av, z);
     446              : }
     447              : 
     448              : GEN
     449      1350155 : FpXQX_mul(GEN x, GEN y, GEN T, GEN p)
     450              : {
     451      1350155 :   GEN z = FpXQX_mulspec(x+2,y+2,T,p,lgpol(x),lgpol(y));
     452      1350155 :   setvarn(z,varn(x)); return z;
     453              : }
     454              : 
     455              : GEN
     456       180858 : FpXQX_sqr(GEN x, GEN T, GEN p)
     457              : {
     458       180858 :   pari_sp av = avma;
     459              :   GEN z, kx;
     460       180858 :   if (ZXX_is_ZX(x)) return ZX_sqr(x);
     461       173950 :   kx= RgXX_to_Kronecker(x, get_FpX_degree(T));
     462       173950 :   z = Kronecker_to_FpXQX(ZX_sqr(kx), T, p);
     463       173950 :   return gc_upto(av, z);
     464              : }
     465              : 
     466              : GEN
     467       550853 : FpXQX_FpXQ_mul(GEN P, GEN U, GEN T, GEN p)
     468              : {
     469              :   long i, lP;
     470              :   GEN res;
     471       550853 :   res = cgetg_copy(P, &lP); res[1] = P[1];
     472      2060127 :   for(i=2; i<lP; i++)
     473      2741306 :     gel(res,i) = typ(gel(P,i))==t_INT? FpX_Fp_mul(U, gel(P,i), p):
     474      1232032 :                                        FpXQ_mul(U, gel(P,i), T,p);
     475       550853 :   return FpXQX_renormalize(res,lP);
     476              : }
     477              : 
     478              : /* x and y in Z[Y][X]. Assume T irreducible mod p */
     479              : static GEN
     480       172542 : FpXQX_divrem_basecase(GEN x, GEN y, GEN T, GEN p, GEN *pr)
     481              : {
     482       172542 :   long vx = varn(x), dx = degpol(x), dy = degpol(y), dy1, dz, i, j, sx, lr;
     483              :   pari_sp av0, av;
     484              :   GEN z, p1, rem, lead;
     485              : 
     486       172542 :   if (!signe(y)) pari_err_INV("FpX_divrem",y);
     487       172542 :   if (dx < dy)
     488              :   {
     489          185 :     if (pr)
     490              :     {
     491          135 :       av0 = avma; x = FpXQX_red(x, T, p);
     492          135 :       if (pr == ONLY_DIVIDES) { set_avma(av0); return signe(x)? NULL: pol_0(vx); }
     493          135 :       if (pr == ONLY_REM) return x;
     494          135 :       *pr = x;
     495              :     }
     496          185 :     return pol_0(vx);
     497              :   }
     498       172357 :   lead = leading_coeff(y);
     499       172357 :   if (!dy) /* y is constant */
     500              :   {
     501         1409 :     if (pr && pr != ONLY_DIVIDES)
     502              :     {
     503         1045 :       if (pr == ONLY_REM) return pol_0(vx);
     504            7 :       *pr = pol_0(vx);
     505              :     }
     506          371 :     if (gequal1(lead)) return FpXQX_red(x,T,p);
     507          355 :     av0 = avma; x = FqX_Fq_mul(x, Fq_inv(lead, T,p), T,p);
     508          355 :     return gc_upto(av0,x);
     509              :   }
     510       170948 :   av0 = avma; dz = dx-dy;
     511       170948 :   lead = gequal1(lead)? NULL: gclone(Fq_inv(lead,T,p));
     512       170948 :   set_avma(av0);
     513       170948 :   z = cgetg(dz+3,t_POL); z[1] = x[1];
     514       170948 :   x += 2; y += 2; z += 2;
     515       177500 :   for (dy1=dy-1; dy1>=0 && !signe(gel(y, dy1)); dy1--);
     516              : 
     517       170948 :   p1 = gel(x,dx); av = avma;
     518       170948 :   gel(z,dz) = lead? gc_upto(av, Fq_mul(p1,lead, T, p)): gcopy(p1);
     519       546466 :   for (i=dx-1; i>=dy; i--)
     520              :   {
     521       375518 :     av=avma; p1=gel(x,i);
     522      1312867 :     for (j=i-dy1; j<=i && j<=dz; j++)
     523       937349 :       p1 = Fq_sub(p1, Fq_mul(gel(z,j),gel(y,i-j),NULL,p),NULL,p);
     524       375518 :     if (lead) p1 = Fq_mul(p1, lead, NULL,p);
     525       375518 :     gel(z,i-dy) = gc_upto(av, Fq_red(p1,T,p));
     526              :   }
     527       170948 :   if (!pr) { guncloneNULL(lead); return z-2; }
     528              : 
     529       167830 :   rem = (GEN)avma; av = (pari_sp)new_chunk(dx+3);
     530       179166 :   for (sx=0; ; i--)
     531              :   {
     532       179166 :     p1 = gel(x,i);
     533       704789 :     for (j=maxss(0,i-dy1); j<=i && j<=dz; j++)
     534       525623 :       p1 = Fq_sub(p1, Fq_mul(gel(z,j),gel(y,i-j),NULL,p),NULL,p);
     535       179166 :     p1 = Fq_red(p1, T, p); if (signe(p1)) { sx = 1; break; }
     536        13268 :     if (!i) break;
     537        11336 :     set_avma(av);
     538              :   }
     539       167830 :   if (pr == ONLY_DIVIDES)
     540              :   {
     541            0 :     guncloneNULL(lead);
     542            0 :     if (sx) return gc_NULL(av0);
     543            0 :     return gc_const((pari_sp)rem, z-2);
     544              :   }
     545       167830 :   lr=i+3; rem -= lr; av = (pari_sp)rem;
     546       167830 :   rem[0] = evaltyp(t_POL) | _evallg(lr);
     547       167830 :   rem[1] = z[-1];
     548       167830 :   rem += 2; gel(rem,i) = gc_upto(av, p1);
     549      1501599 :   for (i--; i>=0; i--)
     550              :   {
     551      1333769 :     av = avma; p1 = gel(x,i);
     552      4263167 :     for (j=maxss(0,i-dy1); j<=i && j<=dz; j++)
     553      2929398 :       p1 = Fq_sub(p1, Fq_mul(gel(z,j),gel(y,i-j), NULL,p), NULL,p);
     554      1333769 :     gel(rem,i) = gc_upto(av, Fq_red(p1, T, p));
     555              :   }
     556       167830 :   rem -= 2;
     557       167830 :   guncloneNULL(lead);
     558       167830 :   if (!sx) (void)FpXQX_renormalize(rem, lr);
     559       167830 :   if (pr == ONLY_REM) return gc_upto(av0,rem);
     560        15691 :   *pr = rem; return z-2;
     561              : }
     562              : 
     563              : static GEN
     564          752 : FpXQX_addmulmul(GEN u, GEN v, GEN x, GEN y, GEN T, GEN p)
     565              : {
     566          752 :   return FpXX_add(FpXQX_mul(u, x, T, p),FpXQX_mul(v, y, T, p), p);
     567              : }
     568              : 
     569              : static GEN
     570          376 : FpXQXM_FpXQX_mul2(GEN M, GEN x, GEN y, GEN T, GEN p)
     571              : {
     572          376 :   GEN res = cgetg(3, t_COL);
     573          376 :   gel(res, 1) = FpXQX_addmulmul(gcoeff(M,1,1), gcoeff(M,1,2), x, y, T, p);
     574          376 :   gel(res, 2) = FpXQX_addmulmul(gcoeff(M,2,1), gcoeff(M,2,2), x, y, T, p);
     575          376 :   return res;
     576              : }
     577              : 
     578              : static GEN
     579          161 : FpXQXM_mul2(GEN A, GEN B, GEN T, GEN p)
     580              : {
     581          161 :   GEN A11=gcoeff(A,1,1),A12=gcoeff(A,1,2), B11=gcoeff(B,1,1),B12=gcoeff(B,1,2);
     582          161 :   GEN A21=gcoeff(A,2,1),A22=gcoeff(A,2,2), B21=gcoeff(B,2,1),B22=gcoeff(B,2,2);
     583          161 :   GEN M1 = FpXQX_mul(FpXX_add(A11,A22, p), FpXX_add(B11,B22, p), T, p);
     584          161 :   GEN M2 = FpXQX_mul(FpXX_add(A21,A22, p), B11, T, p);
     585          161 :   GEN M3 = FpXQX_mul(A11, FpXX_sub(B12,B22, p), T, p);
     586          161 :   GEN M4 = FpXQX_mul(A22, FpXX_sub(B21,B11, p), T, p);
     587          161 :   GEN M5 = FpXQX_mul(FpXX_add(A11,A12, p), B22, T, p);
     588          161 :   GEN M6 = FpXQX_mul(FpXX_sub(A21,A11, p), FpXX_add(B11,B12, p), T, p);
     589          161 :   GEN M7 = FpXQX_mul(FpXX_sub(A12,A22, p), FpXX_add(B21,B22, p), T, p);
     590          161 :   GEN T1 = FpXX_add(M1,M4, p), T2 = FpXX_sub(M7,M5, p);
     591          161 :   GEN T3 = FpXX_sub(M1,M2, p), T4 = FpXX_add(M3,M6, p);
     592          161 :   retmkmat22(FpXX_add(T1,T2, p), FpXX_add(M3,M5, p),
     593              :              FpXX_add(M2,M4, p), FpXX_add(T3,T4, p));
     594              : }
     595              : /* Return [0,1;1,-q]*M */
     596              : static GEN
     597          161 : FpXQX_FpXQXM_qmul(GEN q, GEN M, GEN T, GEN p)
     598              : {
     599          161 :   GEN u = FpXQX_mul(gcoeff(M,2,1), q, T, p);
     600          161 :   GEN v = FpXQX_mul(gcoeff(M,2,2), q, T, p);
     601          161 :   retmkmat22(gcoeff(M,2,1), gcoeff(M,2,2),
     602              :     FpXX_sub(gcoeff(M,1,1), u, p), FpXX_sub(gcoeff(M,1,2), v, p));
     603              : }
     604              : 
     605              : static GEN
     606            0 : matid2_FpXQXM(long v)
     607            0 : { retmkmat22(pol_1(v),pol_0(v),pol_0(v),pol_1(v)); }
     608              : 
     609              : static GEN
     610            0 : matJ2_FpXQXM(long v)
     611            0 : { retmkmat22(pol_0(v),pol_1(v),pol_1(v),pol_0(v)); }
     612              : 
     613              : static GEN
     614        18279 : FpXX_shift(GEN a, long n) { return RgX_shift_shallow(a, n); }
     615              : 
     616              : INLINE GEN
     617         7861 : FpXXn_red(GEN a, long n) { return RgXn_red_shallow(a, n); }
     618              : 
     619              : /* Fast resultant formula from William Hart in Flint <http://flintlib.org/> */
     620              : 
     621              : struct FpXQX_res
     622              : {
     623              :    GEN res, lc;
     624              :    long deg0, deg1, off;
     625              : };
     626              : 
     627              : INLINE void
     628            0 : FpXQX_halfres_update(long da, long db, long dr, GEN T, GEN p, struct FpXQX_res *res)
     629              : {
     630            0 :   if (dr >= 0)
     631              :   {
     632            0 :     if (!ZX_equal1(res->lc))
     633              :     {
     634            0 :       res->lc  = FpXQ_powu(res->lc, da - dr, T, p);
     635            0 :       res->res = FpXQ_mul(res->res, res->lc, T, p);
     636              :     }
     637            0 :     if (both_odd(da + res->off, db + res->off))
     638            0 :       res->res = FpX_neg(res->res, p);
     639              :   } else
     640              :   {
     641            0 :     if (db == 0)
     642              :     {
     643            0 :       if (!ZX_equal1(res->lc))
     644              :       {
     645            0 :           res->lc  = FpXQ_powu(res->lc, da, T, p);
     646            0 :           res->res = FpXQ_mul(res->res, res->lc, T, p);
     647              :       }
     648              :     } else
     649            0 :       res->res = pol_0(get_FpX_var(T));
     650              :   }
     651            0 : }
     652              : 
     653              : static GEN
     654          275 : FpXQX_halfres_basecase(GEN a, GEN b, GEN T, GEN p, GEN *pa, GEN *pb, struct FpXQX_res *res)
     655              : {
     656          275 :   pari_sp av=avma;
     657              :   GEN u,u1,v,v1, M;
     658          275 :   long vx = varn(a), vT = get_FpX_var(T), n = lgpol(a)>>1;
     659          275 :   u1 = v = pol_0(vx);
     660          275 :   u = v1 = pol_1(vx);
     661         2846 :   while (lgpol(b)>n)
     662              :   {
     663              :     GEN r, q;
     664         2571 :     q = FpXQX_divrem(a,b, T, p, &r);
     665         2571 :     if (res)
     666              :     {
     667            0 :       long da = degpol(a), db=degpol(b), dr = degpol(r);
     668            0 :       res->lc = to_ZX(gel(b,db+2),vT);
     669            0 :       if (dr >= n)
     670            0 :         FpXQX_halfres_update(da, db, dr, T, p, res);
     671              :       else
     672              :       {
     673            0 :         res->deg0 = da;
     674            0 :         res->deg1 = db;
     675              :       }
     676              :     }
     677         2571 :     a = b; b = r; swap(u,u1); swap(v,v1);
     678         2571 :     u1 = FpXX_sub(u1, FpXQX_mul(u, q, T, p), p);
     679         2571 :     v1 = FpXX_sub(v1, FpXQX_mul(v, q, T, p), p);
     680         2571 :     if (gc_needed(av,2))
     681              :     {
     682            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FpXQX_halfgcd (d = %ld)",degpol(b));
     683            0 :       if (res)
     684            0 :         (void)gc_all(av, 8, &a,&b,&u1,&v1,&u,&v,&res->res,&res->lc);
     685              :       else
     686            0 :         (void)gc_all(av, 6, &a,&b,&u1,&v1,&u,&v);
     687              :     }
     688              :   }
     689          275 :   M = mkmat22(u,v,u1,v1); *pa = a; *pb = b;
     690            0 :   return res ? gc_all(av, 5, &M, pa, pb, &res->res, &res->lc)
     691          275 :              : gc_all(av, 3, &M, pa, pb);
     692              : }
     693              : 
     694              : static GEN FpXQX_halfres_i(GEN x, GEN y, GEN T, GEN p, GEN *a, GEN *b, struct FpXQX_res *res);
     695              : 
     696              : static GEN
     697          215 : FpXQX_halfres_split(GEN x, GEN y, GEN T, GEN p, GEN *a, GEN *b, struct FpXQX_res *res)
     698              : {
     699          215 :   pari_sp av = avma;
     700              :   GEN Q, R, S, V1, V2;
     701              :   GEN x1, y1, r, q;
     702          215 :   long l = lgpol(x), n = l>>1, k, vT = get_FpX_var(T);
     703          215 :   if (lgpol(y) <= n)
     704            0 :     { *a = RgX_copy(x); *b = RgX_copy(y); return matid2_FpXQXM(varn(x)); }
     705          215 :   if (res)
     706              :   {
     707            0 :      res->lc = to_ZX(leading_coeff(y), vT);
     708            0 :      res->deg0 -= n;
     709            0 :      res->deg1 -= n;
     710            0 :      res->off += n;
     711              :   }
     712          215 :   R = FpXQX_halfres_i(FpXX_shift(x,-n),FpXX_shift(y,-n), T, p, a, b, res);
     713          215 :   if (res)
     714              :   {
     715            0 :     res->off -= n;
     716            0 :     res->deg0 += n;
     717            0 :     res->deg1 += n;
     718              :   }
     719          215 :   V1 = FpXQXM_FpXQX_mul2(R, Flxn_red(x,n), Flxn_red(y,n), T, p);
     720          215 :   x1 = FpXX_add(FpXX_shift(*a,n), gel(V1,1), p);
     721          215 :   y1 = FpXX_add(FpXX_shift(*b,n), gel(V1,2), p);
     722          215 :   if (lgpol(y1) <= n)
     723              :   {
     724           54 :     *a = x1; *b = y1;
     725            0 :     return res ? gc_all(av, 5, &R, a, b, &res->res, &res->lc)
     726           54 :                : gc_all(av, 3, &R, a, b);
     727              :   }
     728          161 :   k = 2*n-degpol(y1);
     729          161 :   q = FpXQX_divrem(x1, y1, T, p, &r);
     730          161 :   if (res)
     731              :   {
     732            0 :     long dx1 = degpol(x1), dy1 = degpol(y1), dr = degpol(r);
     733            0 :     if (dy1 < degpol(y))
     734            0 :       FpXQX_halfres_update(res->deg0, res->deg1, dy1, T, p, res);
     735            0 :     res->lc = to_ZX(leading_coeff(y1), vT);
     736            0 :     res->deg0 = dx1;
     737            0 :     res->deg1 = dy1;
     738            0 :     if (dr >= n)
     739              :     {
     740            0 :       FpXQX_halfres_update(dx1, dy1, dr, T, p, res);
     741            0 :       res->deg0 = dy1;
     742            0 :       res->deg1 = dr;
     743              :     }
     744            0 :     res->deg0 -= k;
     745            0 :     res->deg1 -= k;
     746            0 :     res->off += k;
     747              :   }
     748          161 :   S = FpXQX_halfres_i(FpXX_shift(y1,-k), FpXX_shift(r,-k), T, p, a, b, res);
     749          161 :   if (res)
     750              :   {
     751            0 :     res->deg0 += k;
     752            0 :     res->deg1 += k;
     753            0 :     res->off -= k;
     754              :   }
     755          161 :   Q = FpXQXM_mul2(S,FpXQX_FpXQXM_qmul(q, R, T, p), T, p);
     756          161 :   V2 = FpXQXM_FpXQX_mul2(S, FpXXn_red(y1,k), FpXXn_red(r,k), T, p);
     757          161 :   *a = FpXX_add(FpXX_shift(*a,k), gel(V2,1), p);
     758          161 :   *b = FpXX_add(FpXX_shift(*b,k), gel(V2,2), p);
     759            0 :   return res ? gc_all(av, 5, &Q, a, b, &res->res, &res->lc)
     760          161 :              : gc_all(av, 3, &Q, a, b);
     761              : }
     762              : 
     763              : static GEN
     764          490 : FpXQX_halfres_i(GEN x, GEN y, GEN T, GEN p, GEN *a, GEN *b, struct FpXQX_res *res)
     765              : {
     766          490 :   if (lgpol(x) < FpXQX_HALFGCD_LIMIT)
     767          275 :     return FpXQX_halfres_basecase(x, y, T, p, a, b, res);
     768          215 :   return FpXQX_halfres_split(x, y, T, p, a, b, res);
     769              : }
     770              : 
     771              : static GEN
     772          114 : FpXQX_halfgcd_all_i(GEN x, GEN y, GEN T, GEN p, GEN *pa, GEN *pb)
     773              : {
     774              :   GEN a, b;
     775          114 :   GEN R = FpXQX_halfres_i(x, y, T, p, &a, &b, NULL);
     776          114 :   if (pa) *pa = a;
     777          114 :   if (pb) *pb = b;
     778          114 :   return R;
     779              : }
     780              : 
     781              : /* Return M in GL_2(Fp[X]/(T)[Y]) such that:
     782              : if [a',b']~=M*[a,b]~ then degpol(a')>= (lgpol(a)>>1) >degpol(b')
     783              : */
     784              : 
     785              : GEN
     786          114 : FpXQX_halfgcd_all(GEN x, GEN y, GEN T, GEN p, GEN *a, GEN *b)
     787              : {
     788          114 :   pari_sp av = avma;
     789              :   GEN R,q,r;
     790          114 :   if (lgefint(p)==3)
     791              :   {
     792            0 :     ulong pp = to_FlxqX(x, y, T, p, &x, &y, &T);
     793            0 :     R = FlxXM_to_ZXXM(FlxqX_halfgcd(x, y, T, pp));
     794            0 :     if (a) *a = Flx_to_ZX(*a);
     795            0 :     if (b) *b = Flx_to_ZX(*b);
     796            0 :     return !a && b ? gc_all(av, 2, &R, b): gc_all(av, 1+!!a+!!b, &R, a, b);
     797              :   }
     798          114 :   if (!signe(x))
     799              :   {
     800            0 :     if (a) *a = RgX_copy(y);
     801            0 :     if (b) *b = RgX_copy(x);
     802            0 :     return matJ2_FpXQXM(varn(x));
     803              :   }
     804          114 :   if (degpol(y)<degpol(x)) return FpXQX_halfgcd_all_i(x, y, T, p, a, b);
     805           26 :   q = FpXQX_divrem(y, x, T, p, &r);
     806           26 :   R = FpXQX_halfgcd_all_i(x, r, T, p, a, b);
     807           26 :   gcoeff(R,1,1) = FpXX_sub(gcoeff(R,1,1),
     808           26 :                            FpXQX_mul(q, gcoeff(R,1,2), T, p), p);
     809           26 :   gcoeff(R,2,1) = FpXX_sub(gcoeff(R,2,1),
     810           26 :                            FpXQX_mul(q, gcoeff(R,2,2), T, p), p);
     811           26 :   return !a && b ? gc_all(av, 2, &R, b): gc_all(av, 1+!!a+!!b, &R, a, b);
     812              : }
     813              : 
     814              : GEN
     815           44 : FpXQX_halfgcd(GEN x, GEN y, GEN T, GEN p)
     816           44 : { return FpXQX_halfgcd_all(x, y, T, p, NULL, NULL); }
     817              : 
     818              : static GEN
     819         3870 : FpXQX_gcd_basecase(GEN a, GEN b, GEN T, GEN p)
     820              : {
     821         3870 :   pari_sp av = avma, av0=avma;
     822        38906 :   while (signe(b))
     823              :   {
     824              :     GEN c;
     825        35036 :     if (gc_needed(av0,2))
     826              :     {
     827            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FpXQX_gcd (d = %ld)",degpol(b));
     828            0 :       (void)gc_all(av0,2, &a,&b);
     829              :     }
     830        35036 :     av = avma; c = FpXQX_rem(a, b, T, p); a=b; b=c;
     831              :   }
     832         3870 :   return gc_const(av, a);
     833              : }
     834              : 
     835              : GEN
     836        14664 : FpXQX_gcd(GEN x, GEN y, GEN T, GEN p)
     837              : {
     838        14664 :   pari_sp av = avma;
     839        14664 :   if (lgefint(p) == 3)
     840              :   {
     841              :     GEN Pl, Ql, Tl, U;
     842        10708 :     ulong pp = to_FlxqX(x, y, T, p, &Pl, &Ql, &Tl);
     843        10708 :     U  = FlxqX_gcd(Pl, Ql, Tl, pp);
     844        10708 :     return gc_upto(av, FlxX_to_ZXX(U));
     845              :   }
     846         3956 :   x = FpXQX_red(x, T, p);
     847         3956 :   y = FpXQX_red(y, T, p);
     848         3956 :   if (!signe(x)) return gc_upto(av, y);
     849         3933 :   while (lgpol(y)>=FpXQX_GCD_LIMIT)
     850              :   {
     851           63 :     if (lgpol(y)<=(lgpol(x)>>1))
     852              :     {
     853            0 :       GEN r = FpXQX_rem(x, y, T, p);
     854            0 :       x = y; y = r;
     855              :     }
     856           63 :     (void) FpXQX_halfgcd_all(x,y, T, p, &x, &y);
     857           63 :     if (gc_needed(av,2))
     858              :     {
     859            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FpXQX_gcd (y = %ld)",degpol(y));
     860            0 :       (void)gc_all(av,2,&x,&y);
     861              :     }
     862              :   }
     863         3870 :   return gc_upto(av, FpXQX_gcd_basecase(x, y, T, p));
     864              : }
     865              : 
     866              : static GEN
     867            0 : FpXQX_extgcd_basecase(GEN a, GEN b, GEN T, GEN p, GEN *ptu, GEN *ptv)
     868              : {
     869            0 :   pari_sp av=avma;
     870              :   GEN u,v,d,d1,v1;
     871            0 :   long vx = varn(a);
     872            0 :   d = a; d1 = b;
     873            0 :   v = pol_0(vx); v1 = pol_1(vx);
     874            0 :   while (signe(d1))
     875              :   {
     876            0 :     GEN r, q = FpXQX_divrem(d, d1, T, p, &r);
     877            0 :     v = FpXX_sub(v,FpXQX_mul(q,v1,T, p),p);
     878            0 :     u=v; v=v1; v1=u;
     879            0 :     u=r; d=d1; d1=u;
     880            0 :     if (gc_needed(av,2))
     881              :     {
     882            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FpXQX_extgcd (d = %ld)",degpol(d));
     883            0 :       (void)gc_all(av,5, &d,&d1,&u,&v,&v1);
     884              :     }
     885              :   }
     886            0 :   if (ptu) *ptu = FpXQX_div(FpXX_sub(d,FpXQX_mul(b,v, T, p), p), a, T, p);
     887            0 :   *ptv = v; return d;
     888              : }
     889              : 
     890              : static GEN
     891            0 : FpXQX_extgcd_halfgcd(GEN x, GEN y, GEN T, GEN p, GEN *ptu, GEN *ptv)
     892              : {
     893              :   GEN u,v;
     894            0 :   GEN V = cgetg(expu(lgpol(y))+2,t_VEC);
     895            0 :   long i, n = 0, vs = varn(x);
     896            0 :   while (lgpol(y) >= FpXQX_EXTGCD_LIMIT)
     897              :   {
     898            0 :     if (lgpol(y)<=(lgpol(x)>>1))
     899              :     {
     900            0 :       GEN r, q = FpXQX_divrem(x, y, T, p, &r);
     901            0 :       x = y; y = r;
     902            0 :       gel(V,++n) = mkmat22(pol_0(vs),pol_1(vs),pol_1(vs),FpXX_neg(q,p));
     903              :     } else
     904            0 :       gel(V,++n) = FpXQX_halfgcd_all(x, y, T, p, &x, &y);
     905              :   }
     906            0 :   y = FpXQX_extgcd_basecase(x,y, T, p, &u,&v);
     907            0 :   for (i = n; i>1; i--)
     908              :   {
     909            0 :     GEN R = gel(V,i);
     910            0 :     GEN u1 = FpXQX_addmulmul(u, v, gcoeff(R,1,1), gcoeff(R,2,1), T, p);
     911            0 :     GEN v1 = FpXQX_addmulmul(u, v, gcoeff(R,1,2), gcoeff(R,2,2), T, p);
     912            0 :     u = u1; v = v1;
     913              :   }
     914              :   {
     915            0 :     GEN R = gel(V,1);
     916            0 :     if (ptu)
     917            0 :       *ptu = FpXQX_addmulmul(u, v, gcoeff(R,1,1), gcoeff(R,2,1), T, p);
     918            0 :     *ptv   = FpXQX_addmulmul(u, v, gcoeff(R,1,2), gcoeff(R,2,2), T, p);
     919              :   }
     920            0 :   return y;
     921              : }
     922              : 
     923              : /* x and y in Z[Y][X], return lift(gcd(x mod T,p, y mod T,p)). Set u and v st
     924              :  * ux + vy = gcd (mod T,p) */
     925              : GEN
     926       134218 : FpXQX_extgcd(GEN x, GEN y, GEN T, GEN p, GEN *ptu, GEN *ptv)
     927              : {
     928       134218 :   pari_sp av = avma;
     929              :   GEN d;
     930       134218 :   if (lgefint(p) == 3)
     931              :   {
     932              :     GEN Pl, Ql, Tl, Dl;
     933       134218 :     ulong pp = to_FlxqX(x, y, T, p, &Pl, &Ql, &Tl);
     934       134218 :     Dl = FlxqX_extgcd(Pl, Ql, Tl, pp, ptu, ptv);
     935       134218 :     if (ptu) *ptu = FlxX_to_ZXX(*ptu);
     936       134218 :     *ptv = FlxX_to_ZXX(*ptv);
     937       134218 :     d = FlxX_to_ZXX(Dl);
     938              :   }
     939              :   else
     940              :   {
     941            0 :     x = FpXQX_red(x, T, p);
     942            0 :     y = FpXQX_red(y, T, p);
     943            0 :     if (lgpol(y)>=FpXQX_EXTGCD_LIMIT)
     944            0 :       d = FpXQX_extgcd_halfgcd(x, y, T, p, ptu, ptv);
     945              :     else
     946            0 :       d = FpXQX_extgcd_basecase(x, y, T, p, ptu, ptv);
     947              :   }
     948       134218 :   return gc_all(av, ptu?3:2, &d, ptv, ptu);
     949              : }
     950              : 
     951              : static GEN
     952            0 : FpXQX_halfres(GEN x, GEN y, GEN T, GEN p, GEN *a, GEN *b, GEN *r)
     953              : {
     954              :   struct FpXQX_res res;
     955              :   GEN V;
     956            0 :   long dB, vT = get_FpX_var(T);
     957              : 
     958            0 :   res.res  = *r;
     959            0 :   res.lc   = to_ZX(leading_coeff(y),vT);
     960            0 :   res.deg0 = degpol(x);
     961            0 :   res.deg1 = degpol(y);
     962            0 :   res.off = 0;
     963            0 :   V = FpXQX_halfres_i(x, y, T, p, a, b, &res);
     964            0 :   dB = degpol(*b);
     965            0 :   if (dB < degpol(y))
     966            0 :     FpXQX_halfres_update(res.deg0, res.deg1, dB, T, p, &res);
     967            0 :   *r = res.res;
     968            0 :   return V;
     969              : }
     970              : 
     971              : /* Res(A,B) = Res(B,R) * lc(B)^(a-r) * (-1)^(ab), with R=A%B, a=deg(A) ...*/
     972              : static GEN
     973           28 : FpXQX_resultant_basecase(GEN a, GEN b, GEN T, GEN p)
     974              : {
     975           28 :   pari_sp av = avma;
     976           28 :   long vT = get_FpX_var(T), da,db,dc;
     977           28 :   GEN c,lb, res = pol_1(vT);
     978              : 
     979           28 :   if (!signe(a) || !signe(b)) return pol_0(vT);
     980              : 
     981           28 :   da = degpol(a);
     982           28 :   db = degpol(b);
     983           28 :   if (db > da)
     984              :   {
     985            0 :     swapspec(a,b, da,db);
     986            0 :     if (both_odd(da,db)) res = FpX_neg(res, p);
     987              :   }
     988           28 :   if (!da) return pol_1(vT); /* = res * a[2] ^ db, since 0 <= db <= da = 0 */
     989           98 :   while (db)
     990              :   {
     991           70 :     lb = to_ZX(gel(b,db+2),vT);
     992           70 :     c = FpXQX_rem(a,b, T,p);
     993           70 :     a = b; b = c; dc = degpol(c);
     994           70 :     if (dc < 0) { set_avma(av); return pol_0(vT); }
     995              : 
     996           70 :     if (both_odd(da,db)) res = FpX_neg(res, p);
     997           70 :     if (!ZX_equal1(lb)) res = FpXQ_mul(res, FpXQ_powu(lb, da - dc, T, p), T, p);
     998           70 :     if (gc_needed(av,2))
     999              :     {
    1000            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FpXQX_resultant (da = %ld)",da);
    1001            0 :       (void)gc_all(av,3, &a,&b,&res);
    1002              :     }
    1003           70 :     da = db; /* = degpol(a) */
    1004           70 :     db = dc; /* = degpol(b) */
    1005              :   }
    1006           28 :   res = FpXQ_mul(res, FpXQ_powu(gel(b,2), da, T, p), T, p);
    1007           28 :   return gc_upto(av, res);
    1008              : }
    1009              : 
    1010              : GEN
    1011           63 : FpXQX_resultant(GEN x, GEN y, GEN T, GEN p)
    1012              : {
    1013           63 :   pari_sp av = avma;
    1014           63 :   long dx, dy, vT = get_FpX_var(T);
    1015           63 :   GEN res = pol_1(vT);
    1016           63 :   if (!signe(x) || !signe(y)) return pol_0(vT);
    1017           63 :   if (lgefint(p) == 3)
    1018              :   {
    1019           35 :     pari_sp av = avma;
    1020              :     GEN Pl, Ql, Tl, R;
    1021           35 :     ulong pp = to_FlxqX(x, y, T, p, &Pl, &Ql, &Tl);
    1022           35 :     R = FlxqX_resultant(Pl, Ql, Tl, pp);
    1023           35 :     return gc_upto(av, Flx_to_ZX(R));
    1024              :   }
    1025              : 
    1026           28 :   dx = degpol(x); dy = degpol(y);
    1027           28 :   if (dx < dy)
    1028              :   {
    1029           14 :     swap(x,y);
    1030           14 :     if (both_odd(dx, dy))
    1031            0 :       res = Fp_neg(res, p);
    1032              :   }
    1033           28 :   while (lgpol(y) >= FpXQX_GCD_LIMIT)
    1034              :   {
    1035            0 :     if (lgpol(y)<=(lgpol(x)>>1))
    1036              :     {
    1037            0 :       GEN r = FpXQX_rem(x, y, T, p);
    1038            0 :       long dx = degpol(x), dy = degpol(y), dr = degpol(r);
    1039            0 :       GEN ly = FpX_red(gel(y,dy+2),p);
    1040            0 :       if (!ZX_equal1(ly)) res = FpXQ_mul(res, FpXQ_powu(ly, dx - dr, T, p), T, p);
    1041            0 :       if (both_odd(dx, dy))
    1042            0 :         res = Fp_neg(res, p);
    1043            0 :       x = y; y = r;
    1044              :     }
    1045            0 :     (void) FpXQX_halfres(x, y, T, p, &x, &y, &res);
    1046            0 :     if (gc_needed(av,2))
    1047              :     {
    1048            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FpXQX_resultant (y = %ld)",degpol(y));
    1049            0 :       (void)gc_all(av,3,&x,&y,&res);
    1050              :     }
    1051              :   }
    1052           28 :   return gc_upto(av, FpXQ_mul(res, FpXQX_resultant_basecase(x, y, T, p), T, p));
    1053              : }
    1054              : 
    1055              : /* disc P = (-1)^(n(n-1)/2) lc(P)^(n - deg P' - 2) Res(P,P'), n = deg P */
    1056              : GEN
    1057           35 : FpXQX_disc(GEN P, GEN T, GEN p)
    1058              : {
    1059           35 :   pari_sp av = avma;
    1060           35 :   GEN L, dP = FpXX_deriv(P, p), D = FpXQX_resultant(P, dP, T, p);
    1061              :   long dd;
    1062           35 :   if (!signe(D)) return pol_0(get_FpX_var(T));
    1063           35 :   dd = degpol(P) - 2 - degpol(dP); /* >= -1; > -1 iff p | deg(P) */
    1064           35 :   L = leading_coeff(P);
    1065           35 :   if (dd && !gequal1(L))
    1066            0 :     D = (dd == -1)? FpXQ_div(D,L,T,p): FpXQ_mul(D, FpXQ_powu(L, dd, T, p), T, p);
    1067           35 :   if (degpol(P) & 2) D = FpX_neg(D, p);
    1068           35 :   return gc_upto(av, D);
    1069              : }
    1070              : 
    1071              : GEN
    1072          396 : FpXQX_dotproduct(GEN x, GEN y, GEN T, GEN p)
    1073              : {
    1074          396 :   long i, l = minss(lg(x), lg(y));
    1075              :   pari_sp av;
    1076              :   GEN c;
    1077          396 :   if (l == 2) return gen_0;
    1078          396 :   av = avma; c = gmul(gel(x,2),gel(y,2));
    1079         1642 :   for (i=3; i<l; i++) c = gadd(c, gmul(gel(x,i),gel(y,i)));
    1080          396 :   return gc_upto(av, Fq_red(c,T,p));
    1081              : }
    1082              : 
    1083              : /***********************************************************************/
    1084              : /**                                                                   **/
    1085              : /**                       Barrett reduction                           **/
    1086              : /**                                                                   **/
    1087              : /***********************************************************************/
    1088              : 
    1089              : /* Return new lgpol */
    1090              : static long
    1091       311101 : ZXX_lgrenormalizespec(GEN x, long lx)
    1092              : {
    1093              :   long i;
    1094       311611 :   for (i = lx-1; i>=0; i--)
    1095       311611 :     if (signe(gel(x,i))) break;
    1096       311101 :   return i+1;
    1097              : }
    1098              : 
    1099              : static GEN
    1100         2971 : FpXQX_invBarrett_basecase(GEN S, GEN T, GEN p)
    1101              : {
    1102         2971 :   long i, l=lg(S)-1, lr = l-1, k;
    1103         2971 :   GEN r=cgetg(lr, t_POL); r[1]=S[1];
    1104         2971 :   gel(r,2) = gen_1;
    1105        26371 :   for (i=3; i<lr; i++)
    1106              :   {
    1107        23400 :     pari_sp av = avma;
    1108        23400 :     GEN u = gel(S,l-i+2);
    1109       238864 :     for (k=3; k<i; k++)
    1110       215464 :       u = Fq_add(u, Fq_mul(gel(S,l-i+k), gel(r,k), NULL, p), NULL, p);
    1111        23400 :     gel(r,i) = gc_upto(av, Fq_red(Fq_neg(u, NULL, p), T, p));
    1112              :   }
    1113         2971 :   return FpXQX_renormalize(r,lr);
    1114              : }
    1115              : 
    1116              : INLINE GEN
    1117       300700 : FpXX_recipspec(GEN x, long l, long n)
    1118              : {
    1119       300700 :   return RgX_recipspec_shallow(x, l, n);
    1120              : }
    1121              : 
    1122              : static GEN
    1123          537 : FpXQX_invBarrett_Newton(GEN S, GEN T, GEN p)
    1124              : {
    1125          537 :   pari_sp av = avma;
    1126          537 :   long nold, lx, lz, lq, l = degpol(S), i, lQ;
    1127          537 :   GEN q, y, z, x = cgetg(l+2, t_POL) + 2;
    1128          537 :   ulong mask = quadratic_prec_mask(l-2); /* assume l > 2 */
    1129        38343 :   for (i=0;i<l;i++) gel(x,i) = gen_0;
    1130          537 :   q = RgX_recipspec_shallow(S+2,l+1,l+1); lQ = lgpol(q); q+=2;
    1131              :   /* We work on _spec_ FpX's, all the l[xzq] below are lgpol's */
    1132              : 
    1133              :   /* initialize */
    1134          537 :   gel(x,0) = Fq_inv(gel(q,0), T, p);
    1135          537 :   if (lQ>1) gel(q,1) = Fq_red(gel(q,1), T, p);
    1136          537 :   if (lQ>1 && signe(gel(q,1)))
    1137          537 :   {
    1138          537 :     GEN u = gel(q, 1);
    1139          537 :     if (!gequal1(gel(x,0))) u = Fq_mul(u, Fq_sqr(gel(x,0), T, p), T, p);
    1140          537 :     gel(x,1) = Fq_neg(u, T, p); lx = 2;
    1141              :   }
    1142              :   else
    1143            0 :     lx = 1;
    1144          537 :   nold = 1;
    1145         4004 :   for (; mask > 1; )
    1146              :   { /* set x -= x(x*q - 1) + O(t^(nnew + 1)), knowing x*q = 1 + O(t^(nold+1)) */
    1147         3467 :     long i, lnew, nnew = nold << 1;
    1148              : 
    1149         3467 :     if (mask & 1) nnew--;
    1150         3467 :     mask >>= 1;
    1151              : 
    1152         3467 :     lnew = nnew + 1;
    1153         3467 :     lq = ZXX_lgrenormalizespec(q, minss(lQ,lnew));
    1154         3467 :     z = FpXQX_mulspec(x, q, T, p, lx, lq); /* FIXME: high product */
    1155         3467 :     lz = lgpol(z); if (lz > lnew) lz = lnew;
    1156         3467 :     z += 2;
    1157              :     /* subtract 1 [=>first nold words are 0]: renormalize so that z(0) != 0 */
    1158         6934 :     for (i = nold; i < lz; i++) if (signe(gel(z,i))) break;
    1159         3467 :     nold = nnew;
    1160         3467 :     if (i >= lz) continue; /* z-1 = 0(t^(nnew + 1)) */
    1161              : 
    1162              :     /* z + i represents (x*q - 1) / t^i */
    1163         3467 :     lz = ZXX_lgrenormalizespec (z+i, lz-i);
    1164         3467 :     z = FpXQX_mulspec(x, z+i, T, p, lx, lz); /* FIXME: low product */
    1165         3467 :     lz = lgpol(z); z += 2;
    1166         3467 :     if (lz > lnew-i) lz = ZXX_lgrenormalizespec(z, lnew-i);
    1167              : 
    1168         3467 :     lx = lz+ i;
    1169         3467 :     y  = x + i; /* x -= z * t^i, in place */
    1170        39662 :     for (i = 0; i < lz; i++) gel(y,i) = Fq_neg(gel(z,i), T, p);
    1171              :   }
    1172          537 :   x -= 2; setlg(x, lx + 2); x[1] = S[1];
    1173          537 :   return gc_GEN(av, x);
    1174              : }
    1175              : 
    1176              : GEN
    1177         3529 : FpXQX_invBarrett(GEN S, GEN T, GEN p)
    1178              : {
    1179         3529 :   pari_sp ltop = avma;
    1180         3529 :   long l = lg(S);
    1181              :   GEN r;
    1182         3529 :   if (l<5) return pol_0(varn(S));
    1183         3508 :   if (l<=FpXQX_INVBARRETT_LIMIT)
    1184              :   {
    1185         2971 :     GEN c = gel(S,l-1), ci=gen_1;
    1186         2971 :     if (!gequal1(c))
    1187              :     {
    1188         1870 :       ci = Fq_inv(c, T, p);
    1189         1870 :       S = FqX_Fq_mul(S, ci, T, p);
    1190         1870 :       r = FpXQX_invBarrett_basecase(S, T, p);
    1191         1870 :       r = FqX_Fq_mul(r, ci, T, p);
    1192              :     } else
    1193         1101 :       r = FpXQX_invBarrett_basecase(S, T, p);
    1194              :   }
    1195              :   else
    1196          537 :     r = FpXQX_invBarrett_Newton(S, T, p);
    1197         3508 :   return gc_upto(ltop, r);
    1198              : }
    1199              : 
    1200              : GEN
    1201        12167 : FpXQX_get_red(GEN S, GEN T, GEN p)
    1202              : {
    1203        12167 :   if (typ(S)==t_POL && lg(S)>FpXQX_BARRETT_LIMIT)
    1204         1139 :     retmkvec2(FpXQX_invBarrett(S,T,p),S);
    1205        11028 :   return S;
    1206              : }
    1207              : 
    1208              : /* Compute x mod S where 2 <= degpol(S) <= l+1 <= 2*(degpol(S)-1)
    1209              :  * and mg is the Barrett inverse of S. */
    1210              : static GEN
    1211       150350 : FpXQX_divrem_Barrettspec(GEN x, long l, GEN mg, GEN S, GEN T, GEN p, GEN *pr)
    1212              : {
    1213              :   GEN q, r;
    1214       150350 :   long lt = degpol(S); /*We discard the leading term*/
    1215              :   long ld, lm, lT, lmg;
    1216       150350 :   ld = l-lt;
    1217       150350 :   lm = minss(ld, lgpol(mg));
    1218       150350 :   lT  = ZXX_lgrenormalizespec(S+2,lt);
    1219       150350 :   lmg = ZXX_lgrenormalizespec(mg+2,lm);
    1220       150350 :   q = FpXX_recipspec(x+lt,ld,ld);                 /* q = rec(x)     lq<=ld*/
    1221       150350 :   q = FpXQX_mulspec(q+2,mg+2,T,p,lgpol(q),lmg);    /* q = rec(x) * mg lq<=ld+lm*/
    1222       150350 :   q = FpXX_recipspec(q+2,minss(ld,lgpol(q)),ld);  /* q = rec (rec(x) * mg) lq<=ld*/
    1223       150350 :   if (!pr) return q;
    1224       149377 :   r = FpXQX_mulspec(q+2,S+2,T,p,lgpol(q),lT);      /* r = q*pol        lr<=ld+lt*/
    1225       149377 :   r = FpXX_subspec(x,r+2,p,lt,minss(lt,lgpol(r))); /* r = x - r   lr<=lt */
    1226       149377 :   if (pr == ONLY_REM) return r;
    1227        68546 :   *pr = r; return q;
    1228              : }
    1229              : 
    1230              : static GEN
    1231        82290 : FpXQX_divrem_Barrett(GEN x, GEN mg, GEN S, GEN T, GEN p, GEN *pr)
    1232              : {
    1233        82290 :   GEN q = NULL, r = FpXQX_red(x, T, p);
    1234        82290 :   long l = lgpol(r), lt = degpol(S), lm = 2*lt-1, v = varn(S);
    1235              :   long i;
    1236        82290 :   if (l <= lt)
    1237              :   {
    1238            0 :     if (pr == ONLY_REM) return r;
    1239            0 :     if (pr == ONLY_DIVIDES) return signe(r)? NULL: pol_0(v);
    1240            0 :     if (pr) *pr = r;
    1241            0 :     return pol_0(v);
    1242              :   }
    1243        82290 :   if (lt <= 1)
    1244           21 :     return FpXQX_divrem_basecase(r,S,T,p,pr);
    1245        82269 :   if (pr != ONLY_REM && l>lm)
    1246              :   {
    1247         1424 :     q = cgetg(l-lt+2, t_POL); q[1] = S[1];
    1248        90191 :     for (i=0;i<l-lt;i++) gel(q+2,i) = gen_0;
    1249              :   }
    1250       150431 :   while (l>lm)
    1251              :   {
    1252        68162 :     GEN zr, zq = FpXQX_divrem_Barrettspec(r+2+l-lm,lm,mg,S,T,p,&zr);
    1253        68162 :     long lz = lgpol(zr);
    1254        68162 :     if (pr != ONLY_REM)
    1255              :     {
    1256        35052 :       long lq = lgpol(zq);
    1257       116508 :       for(i=0; i<lq; i++) gel(q+2+l-lm,i) = gel(zq,2+i);
    1258              :     }
    1259       286471 :     for(i=0; i<lz; i++) gel(r+2+l-lm,i) = gel(zr,2+i);
    1260        68162 :     l = l-lm+lz;
    1261              :   }
    1262        82269 :   if (pr == ONLY_REM)
    1263              :   {
    1264        80831 :     if (l > lt)
    1265        80831 :       r = FpXQX_divrem_Barrettspec(r+2,l,mg,S,T,p,ONLY_REM);
    1266              :     else
    1267            0 :       r = FpXQX_renormalize(r, l+2);
    1268        80831 :     setvarn(r, v); return r;
    1269              :   }
    1270         1438 :   if (l > lt)
    1271              :   {
    1272         1357 :     GEN zq = FpXQX_divrem_Barrettspec(r+2,l,mg,S,T,p,pr ? &r: NULL);
    1273         1357 :     if (!q) q = zq;
    1274              :     else
    1275              :     {
    1276         1343 :       long lq = lgpol(zq);
    1277         8318 :       for(i=0; i<lq; i++) gel(q+2,i) = gel(zq,2+i);
    1278              :     }
    1279              :   }
    1280           81 :   else if (pr)
    1281           81 :     r = FpX_renormalize(r, l+2);
    1282         1438 :   setvarn(q, v); q = FpXQX_renormalize(q, lg(q));
    1283         1438 :   if (pr == ONLY_DIVIDES) return signe(r)? NULL: q;
    1284         1438 :   if (pr) { setvarn(r, v); *pr = r; }
    1285         1438 :   return q;
    1286              : }
    1287              : 
    1288              : GEN
    1289      1077825 : FpXQX_divrem(GEN x, GEN S, GEN T, GEN p, GEN *pr)
    1290              : {
    1291              :   GEN B, y;
    1292              :   long dy, dx, d;
    1293      1077825 :   if (pr == ONLY_REM) return FpXQX_rem(x, S, T, p);
    1294      1077825 :   y = get_FpXQX_red(S, &B);
    1295      1077825 :   dy = degpol(y); dx = degpol(x); d = dx-dy;
    1296      1077825 :   if (lgefint(p) == 3)
    1297              :   {
    1298              :     GEN a, b, t, z;
    1299      1057022 :     pari_sp av = avma, tetpil;
    1300      1057022 :     ulong pp = to_FlxqX(x, y, T, p, &a, &b, &t);
    1301      1057022 :     z = FlxqX_divrem(a, b, t, pp, pr);
    1302      1057022 :     if (!z) return gc_NULL(av);
    1303      1057022 :     if (!pr || pr == ONLY_DIVIDES) return gc_upto(av, FlxX_to_ZXX(z));
    1304      1023178 :     tetpil = avma;
    1305      1023178 :     z = FlxX_to_ZXX(z);
    1306      1023178 :     *pr = FlxX_to_ZXX(*pr);
    1307      1023178 :     return gc_all_unsafe(av,tetpil,2, &z, pr);
    1308              :   }
    1309        20803 :   if (!B && d+3 < FpXQX_DIVREM_BARRETT_LIMIT)
    1310        19344 :     return FpXQX_divrem_basecase(x,y,T,p,pr);
    1311              :   else
    1312              :   {
    1313         1459 :     pari_sp av = avma;
    1314         1459 :     GEN mg = B? B: FpXQX_invBarrett(y, T, p);
    1315         1459 :     GEN q = FpXQX_divrem_Barrett(x,mg,y,T,p,pr);
    1316         1459 :     if (!q) return gc_NULL(av);
    1317         1459 :     if (!pr || pr == ONLY_DIVIDES) return gc_GEN(av, q);
    1318          472 :     return gc_all(av, 2, &q, pr);
    1319              :   }
    1320              : }
    1321              : 
    1322              : GEN
    1323       256615 : FpXQX_rem(GEN x, GEN S, GEN T, GEN p)
    1324              : {
    1325       256615 :   GEN B, y = get_FpXQX_red(S, &B);
    1326       256615 :   long dy = degpol(y), dx = degpol(x), d = dx-dy;
    1327       256615 :   if (d < 0) return FpXQX_red(x, T, p);
    1328       236170 :   if (lgefint(p) == 3)
    1329              :   {
    1330         2162 :     pari_sp av = avma;
    1331              :     GEN a, b, t, z;
    1332         2162 :     ulong pp = to_FlxqX(x, y, T, p, &a, &b, &t);
    1333         2162 :     z = FlxqX_rem(a, b, t, pp);
    1334         2162 :     return gc_upto(av, FlxX_to_ZXX(z));
    1335              :   }
    1336       234008 :   if (!B && d+3 < FpXQX_REM_BARRETT_LIMIT)
    1337       153177 :     return FpXQX_divrem_basecase(x,y, T, p, ONLY_REM);
    1338              :   else
    1339              :   {
    1340        80831 :     pari_sp av=avma;
    1341        80831 :     GEN mg = B? B: FpXQX_invBarrett(y, T, p);
    1342        80831 :     GEN r = FpXQX_divrem_Barrett(x, mg, y, T, p, ONLY_REM);
    1343        80831 :     return gc_upto(av, r);
    1344              :   }
    1345              : }
    1346              : 
    1347              : /* x + y*z mod p */
    1348              : INLINE GEN
    1349        35602 : Fq_addmul(GEN x, GEN y, GEN z, GEN T, GEN p)
    1350              : {
    1351              :   pari_sp av;
    1352        35602 :   if (!signe(y) || !signe(z)) return Fq_red(x, T, p);
    1353        35602 :   if (!signe(x)) return Fq_mul(z,y, T, p);
    1354        35602 :   av = avma;
    1355        35602 :   return gc_upto(av, Fq_add(x, Fq_mul(y, z, T, p), T, p));
    1356              : }
    1357              : 
    1358              : GEN
    1359        69699 : FpXQX_div_by_X_x(GEN a, GEN x, GEN T, GEN p, GEN *r)
    1360              : {
    1361        69699 :   long l = lg(a), i;
    1362              :   GEN z;
    1363        69699 :   if (lgefint(p)==3)
    1364              :   {
    1365        51898 :     pari_sp av = avma;
    1366              :     GEN ap, xp, t, z;
    1367        51898 :     ulong pp = to_FlxqX(a, NULL, T, p, &ap, NULL, &t);
    1368        51898 :     xp = ZX_to_Flx(to_ZX(x, get_FpX_var(T)), pp);
    1369        51898 :     z = FlxX_to_ZXX(FlxqX_div_by_X_x(ap, xp, t, pp, r));
    1370        51898 :     if (!r) return gc_upto(av, z);
    1371            0 :     *r = Flx_to_ZX(*r);
    1372            0 :     return gc_all(av, 2, &z, r);
    1373              :   }
    1374        17801 :   if (l <= 3)
    1375              :   {
    1376            0 :     if (r) *r = l == 2? gen_0: gcopy(gel(a,2));
    1377            0 :     return pol_0(varn(a));
    1378              :   }
    1379        17801 :   l--; z = cgetg(l, t_POL); z[1] = a[1];
    1380        17801 :   gel(z, l-1) = gel(a,l);
    1381        53403 :   for (i=l-2; i>1; i--) /* z[i] = a[i+1] + x*z[i+1] */
    1382        35602 :     gel(z, i) = Fq_addmul(gel(a,i+1), x, gel(z,i+1), T, p);
    1383        17801 :   if (r) *r = Fq_addmul(gel(a,2), x, gel(z,2), T, p);
    1384        17801 :   return z;
    1385              : }
    1386              : 
    1387              : struct _FpXQXQ {
    1388              :   GEN T, S;
    1389              :   GEN p;
    1390              : };
    1391              : 
    1392              : static GEN
    1393       118634 : _FpXQX_mul(void *data, GEN a,GEN b)
    1394              : {
    1395       118634 :   struct _FpXQXQ *d=(struct _FpXQXQ*)data;
    1396       118634 :   return FpXQX_mul(a,b,d->T,d->p);
    1397              : }
    1398              : 
    1399              : static GEN
    1400         1729 : _FpXQX_sqr(void *data, GEN a)
    1401              : {
    1402         1729 :   struct _FpXQXQ *d=(struct _FpXQXQ*)data;
    1403         1729 :   return FpXQX_sqr(a, d->T, d->p);
    1404              : }
    1405              : 
    1406              : GEN
    1407           56 : FpXQX_powu(GEN x, ulong n, GEN T, GEN p)
    1408              : {
    1409              :   struct _FpXQXQ D;
    1410           56 :   if (n==0) return pol_1(varn(x));
    1411           56 :   D.T = T; D.p = p;
    1412           56 :   return gen_powu(x, n, (void *)&D, _FpXQX_sqr, _FpXQX_mul);
    1413              : }
    1414              : 
    1415              : GEN
    1416        16716 : FpXQXV_prod(GEN V, GEN T, GEN p)
    1417              : {
    1418        16716 :   if (lgefint(p) == 3)
    1419              :   {
    1420            0 :     pari_sp av = avma;
    1421            0 :     ulong pp = p[2];
    1422            0 :     GEN Tl = ZXT_to_FlxT(T, pp);
    1423            0 :     GEN Vl = ZXXV_to_FlxXV(V, pp, get_FpX_var(T));
    1424            0 :     Tl = FlxqXV_prod(Vl, Tl, pp);
    1425            0 :     return gc_upto(av, FlxX_to_ZXX(Tl));
    1426              :   }
    1427              :   else
    1428              :   {
    1429              :     struct _FpXQXQ d;
    1430        16716 :     d.T=T; d.p=p;
    1431        16716 :     return gen_product(V, (void*)&d, &_FpXQX_mul);
    1432              :   }
    1433              : }
    1434              : 
    1435              : static GEN
    1436         9954 : _FpXQX_divrem(void * E, GEN x, GEN y, GEN *r)
    1437              : {
    1438         9954 :   struct _FpXQXQ *d = (struct _FpXQXQ *) E;
    1439         9954 :   return FpXQX_divrem(x, y, d->T, d->p, r);
    1440              : }
    1441              : 
    1442              : static GEN
    1443       121495 : _FpXQX_add(void * E, GEN x, GEN y)
    1444              : {
    1445       121495 :   struct _FpXQXQ *d = (struct _FpXQXQ *) E;
    1446       121495 :   return FpXX_add(x, y, d->p);
    1447              : }
    1448              : 
    1449              : static GEN
    1450         4491 : _FpXQX_sub(void * E, GEN x, GEN y) {
    1451         4491 :   struct _FpXQXQ *d = (struct _FpXQXQ*) E;
    1452         4491 :   return FpXX_sub(x,y, d->p);
    1453              : }
    1454              : 
    1455              : static struct bb_ring FpXQX_ring = { _FpXQX_add, _FpXQX_mul, _FpXQX_sqr };
    1456              : 
    1457              : GEN
    1458          623 : FpXQX_digits(GEN x, GEN B, GEN T, GEN p)
    1459              : {
    1460          623 :   long d = degpol(B), n = (lgpol(x)+d-1)/d;
    1461              :   struct _FpXQXQ D;
    1462          623 :   D.T = T; D.p = p;
    1463          623 :   return gen_digits(x, B, n, (void *)&D, &FpXQX_ring, _FpXQX_divrem);
    1464              : }
    1465              : 
    1466              : GEN
    1467          189 : FpXQXV_FpXQX_fromdigits(GEN x, GEN B, GEN T, GEN p)
    1468              : {
    1469              :   struct _FpXQXQ D;
    1470          189 :   D.T = T; D.p = p;
    1471          189 :   return gen_fromdigits(x,B,(void *)&D, &FpXQX_ring);
    1472              : }
    1473              : 
    1474              : /* Q an FpXY (t_POL with FpX coeffs), evaluate at X = x */
    1475              : GEN
    1476        51513 : FpXY_evalx(GEN Q, GEN x, GEN p)
    1477              : {
    1478        51513 :   long i, lb = lg(Q);
    1479              :   GEN z;
    1480        51513 :   z = cgetg(lb, t_POL); z[1] = Q[1];
    1481       444976 :   for (i=2; i<lb; i++)
    1482              :   {
    1483       393463 :     GEN q = gel(Q,i);
    1484       393463 :     gel(z,i) = typ(q) == t_INT? modii(q,p): FpX_eval(q, x, p);
    1485              :   }
    1486        51513 :   return FpX_renormalize(z, lb);
    1487              : }
    1488              : /* Q an FpXY, evaluate at Y = y */
    1489              : GEN
    1490        18799 : FpXY_evaly(GEN Q, GEN y, GEN p, long vx)
    1491              : {
    1492        18799 :   pari_sp av = avma;
    1493        18799 :   long i, lb = lg(Q);
    1494              :   GEN z;
    1495        18799 :   if (!signe(Q)) return pol_0(vx);
    1496        18771 :   if (lb == 3 || !signe(y)) {
    1497           84 :     z = gel(Q, 2);
    1498           84 :     return typ(z)==t_INT? scalar_ZX(z, vx): ZX_copy(z);
    1499              :   }
    1500        18687 :   z = gel(Q, lb-1);
    1501        18687 :   if (typ(z) == t_INT) z = scalar_ZX_shallow(z, vx);
    1502       242061 :   for (i=lb-2; i>=2; i--) z = Fq_add(gel(Q,i), FpX_Fp_mul(z, y, p), NULL, p);
    1503        18687 :   return gc_upto(av, z);
    1504              : }
    1505              : /* Q an FpXY, evaluate at (X,Y) = (x,y) */
    1506              : GEN
    1507        13657 : FpXY_eval(GEN Q, GEN y, GEN x, GEN p)
    1508              : {
    1509        13657 :   pari_sp av = avma;
    1510        13657 :   return gc_INT(av, FpX_eval(FpXY_evalx(Q, x, p), y, p));
    1511              : }
    1512              : 
    1513              : GEN
    1514         3618 : FpXY_FpXQV_evalx(GEN P, GEN x, GEN T, GEN p)
    1515              : {
    1516         3618 :   long i, lP = lg(P);
    1517         3618 :   GEN res = cgetg(lP,t_POL);
    1518         3618 :   res[1] = P[1];
    1519        60613 :   for(i=2; i<lP; i++)
    1520       113990 :     gel(res,i) = typ(gel(P,i))==t_INT? icopy(gel(P,i)):
    1521        56995 :                                        FpX_FpXQV_eval(gel(P,i), x, T, p);
    1522         3618 :   return FlxX_renormalize(res, lP);
    1523              : }
    1524              : 
    1525              : GEN
    1526          154 : FpXY_FpXQ_evalx(GEN P, GEN x, GEN T, GEN p)
    1527              : {
    1528          154 :   pari_sp av = avma;
    1529          154 :   long n = brent_kung_optpow(get_FpX_degree(T)-1,lgpol(P),1);
    1530          154 :   GEN xp = FpXQ_powers(x, n, T, p);
    1531          154 :   return gc_upto(av, FpXY_FpXQV_evalx(P, xp, T, p));
    1532              : }
    1533              : 
    1534              : /*******************************************************************/
    1535              : /*                                                                 */
    1536              : /*                       (Fp[X]/T(X))[Y] / S(Y)                    */
    1537              : /*                                                                 */
    1538              : /*******************************************************************/
    1539              : 
    1540              : /*Preliminary implementation to speed up FpX_ffisom*/
    1541              : typedef struct {
    1542              :   GEN S, T, p;
    1543              : } FpXYQQ_muldata;
    1544              : 
    1545              : /* reduce x in Fp[X, Y] in the algebra Fp[X,Y]/ (S(X),T(Y)) */
    1546              : static GEN
    1547          476 : FpXYQQ_redswap(GEN x, GEN S, GEN T, GEN p)
    1548              : {
    1549          476 :   pari_sp ltop=avma;
    1550          476 :   long n = get_FpX_degree(S);
    1551          476 :   long m = get_FpX_degree(T);
    1552          476 :   long v = get_FpX_var(T);
    1553          476 :   GEN V = RgXY_swap(x,m,v);
    1554          476 :   V = FpXQX_red(V,S,p);
    1555          476 :   V = RgXY_swap(V,n,v);
    1556          476 :   return gc_GEN(ltop,V);
    1557              : }
    1558              : static GEN
    1559          280 : FpXYQQ_sqr(void *data, GEN x)
    1560              : {
    1561          280 :   FpXYQQ_muldata *D = (FpXYQQ_muldata*)data;
    1562          280 :   return FpXYQQ_redswap(FpXQX_sqr(x, D->T, D->p),D->S,D->T,D->p);
    1563              : 
    1564              : }
    1565              : static GEN
    1566          196 : FpXYQQ_mul(void *data, GEN x, GEN y)
    1567              : {
    1568          196 :   FpXYQQ_muldata *D = (FpXYQQ_muldata*)data;
    1569          196 :   return FpXYQQ_redswap(FpXQX_mul(x,y, D->T, D->p),D->S,D->T,D->p);
    1570              : }
    1571              : 
    1572              : /* x in Z[X,Y], S in Z[X] over Fq = Z[Y]/(p,T); compute lift(x^n mod (S,T,p)) */
    1573              : GEN
    1574          182 : FpXYQQ_pow(GEN x, GEN n, GEN S, GEN T, GEN p)
    1575              : {
    1576          182 :   pari_sp av = avma;
    1577              :   FpXYQQ_muldata D;
    1578              :   GEN y;
    1579          182 :   if (lgefint(p) == 3)
    1580              :   {
    1581            0 :     ulong pp = to_FlxqX(x, NULL, T, p, &x, NULL, &T);
    1582            0 :     S = ZX_to_Flx(S, pp);
    1583            0 :     y = FlxX_to_ZXX( FlxYqq_pow(x, n, S, T, pp) );
    1584            0 :     y = gc_upto(av, y);
    1585              :   }
    1586              :   else
    1587              :   {
    1588          182 :     D.S = S;
    1589          182 :     D.T = T;
    1590          182 :     D.p = p;
    1591          182 :     y = gen_pow(x, n, (void*)&D, &FpXYQQ_sqr, &FpXYQQ_mul);
    1592              :   }
    1593          182 :   return y;
    1594              : }
    1595              : 
    1596              : GEN
    1597        48020 : FpXQXQ_mul(GEN x, GEN y, GEN S, GEN T, GEN p) {
    1598        48020 :   return FpXQX_rem(FpXQX_mul(x, y, T, p), S, T, p);
    1599              : }
    1600              : 
    1601              : GEN
    1602       170827 : FpXQXQ_sqr(GEN x, GEN S, GEN T, GEN p) {
    1603       170827 :   return FpXQX_rem(FpXQX_sqr(x, T, p), S, T, p);
    1604              : }
    1605              : 
    1606              : /* Inverse of x in Z/pZ[X]/(pol) or NULL if inverse doesn't exist
    1607              :  * return lift(1 / (x mod (p,pol))) */
    1608              : GEN
    1609            0 : FpXQXQ_invsafe(GEN x, GEN S, GEN T, GEN p)
    1610              : {
    1611            0 :   GEN V, z = FpXQX_extgcd(get_FpXQX_mod(S), x, T, p, NULL, &V);
    1612            0 :   if (degpol(z)) return NULL;
    1613            0 :   z = gel(z,2);
    1614            0 :   z = typ(z)==t_INT ? Fp_invsafe(z,p) : FpXQ_invsafe(z,T,p);
    1615            0 :   if (!z) return NULL;
    1616            0 :   return typ(z)==t_INT ? FpXX_Fp_mul(V, z, p): FpXQX_FpXQ_mul(V, z, T, p);
    1617              : }
    1618              : 
    1619              : GEN
    1620            0 : FpXQXQ_inv(GEN x, GEN S, GEN T,GEN p)
    1621              : {
    1622            0 :   pari_sp av = avma;
    1623            0 :   GEN U = FpXQXQ_invsafe(x, S, T, p);
    1624            0 :   if (!U) pari_err_INV("FpXQXQ_inv",x);
    1625            0 :   return gc_upto(av, U);
    1626              : }
    1627              : 
    1628              : GEN
    1629            0 : FpXQXQ_div(GEN x,GEN y,GEN S, GEN T,GEN p)
    1630              : {
    1631            0 :   pari_sp av = avma;
    1632            0 :   return gc_upto(av, FpXQXQ_mul(x, FpXQXQ_inv(y,S,T,p),S,T,p));
    1633              : }
    1634              : 
    1635              : static GEN
    1636       125138 : _FpXQXQ_cmul(void *data, GEN P, long a, GEN x) {
    1637       125138 :   struct _FpXQXQ *d = (struct _FpXQXQ*) data;
    1638       125138 :   GEN y = gel(P,a+2);
    1639       250253 :   return typ(y)==t_INT ? FpXX_Fp_mul(x,y, d->p):
    1640       125115 :                          FpXX_FpX_mul(x,y,d->p);
    1641              : }
    1642              : static GEN
    1643        19370 : _FpXQXQ_red(void *data, GEN x) {
    1644        19370 :   struct _FpXQXQ *d = (struct _FpXQXQ*) data;
    1645        19370 :   return FpXQX_red(x, d->T, d->p);
    1646              : }
    1647              : static GEN
    1648        44890 : _FpXQXQ_mul(void *data, GEN x, GEN y) {
    1649        44890 :   struct _FpXQXQ *d = (struct _FpXQXQ*) data;
    1650        44890 :   return FpXQXQ_mul(x,y, d->S,d->T, d->p);
    1651              : }
    1652              : static GEN
    1653       170827 : _FpXQXQ_sqr(void *data, GEN x) {
    1654       170827 :   struct _FpXQXQ *d = (struct _FpXQXQ*) data;
    1655       170827 :   return FpXQXQ_sqr(x, d->S,d->T, d->p);
    1656              : }
    1657              : 
    1658              : static GEN
    1659        18647 : _FpXQXQ_one(void *data) {
    1660        18647 :   struct _FpXQXQ *d = (struct _FpXQXQ*) data;
    1661        18647 :   return pol_1(get_FpXQX_var(d->S));
    1662              : }
    1663              : 
    1664              : static GEN
    1665          125 : _FpXQXQ_zero(void *data) {
    1666          125 :   struct _FpXQXQ *d = (struct _FpXQXQ*) data;
    1667          125 :   return pol_0(get_FpXQX_var(d->S));
    1668              : }
    1669              : 
    1670              : static struct bb_algebra FpXQXQ_algebra = { _FpXQXQ_red, _FpXQX_add,
    1671              :        _FpXQX_sub, _FpXQXQ_mul, _FpXQXQ_sqr, _FpXQXQ_one, _FpXQXQ_zero };
    1672              : 
    1673              : const struct bb_algebra *
    1674          331 : get_FpXQXQ_algebra(void **E, GEN S, GEN T, GEN p)
    1675              : {
    1676          331 :   GEN z = new_chunk(sizeof(struct _FpXQXQ));
    1677          331 :   struct _FpXQXQ *e = (struct _FpXQXQ *) z;
    1678          331 :   e->T = FpX_get_red(T, p);
    1679          331 :   e->S = FpXQX_get_red(S, e->T, p);
    1680          331 :   e->p  = p; *E = (void*)e;
    1681          331 :   return &FpXQXQ_algebra;
    1682              : }
    1683              : 
    1684              : static struct bb_algebra FpXQX_algebra = { _FpXQXQ_red, _FpXQX_add,
    1685              :        _FpXQX_sub, _FpXQX_mul, _FpXQX_sqr, _FpXQXQ_one, _FpXQXQ_zero };
    1686              : 
    1687              : const struct bb_algebra *
    1688            0 : get_FpXQX_algebra(void **E, GEN T, GEN p, long v)
    1689              : {
    1690            0 :   GEN z = new_chunk(sizeof(struct _FpXQXQ));
    1691            0 :   struct _FpXQXQ *e = (struct _FpXQXQ *) z;
    1692            0 :   e->T = FpX_get_red(T, p);
    1693            0 :   e->S = pol_x(v);
    1694            0 :   e->p  = p; *E = (void*)e;
    1695            0 :   return &FpXQX_algebra;
    1696              : }
    1697              : 
    1698              : /* x over Fq, return lift(x^n) mod S */
    1699              : GEN
    1700         1859 : FpXQXQ_pow(GEN x, GEN n, GEN S, GEN T, GEN p)
    1701              : {
    1702         1859 :   pari_sp ltop = avma;
    1703              :   GEN y;
    1704              :   struct _FpXQXQ D;
    1705         1859 :   long s = signe(n);
    1706         1859 :   if (!s) return pol_1(varn(x));
    1707         1859 :   if (is_pm1(n)) /* +/- 1 */
    1708            0 :     return (s < 0)? FpXQXQ_inv(x,S,T,p): ZXX_copy(x);
    1709         1859 :   if (lgefint(p) == 3)
    1710              :   {
    1711           35 :     ulong pp = to_FlxqX(x, S, T, p, &x, &S, &T);
    1712           35 :     GEN z = FlxqXQ_pow(x, n, S, T, pp);
    1713           35 :     y = FlxX_to_ZXX(z);
    1714           35 :     return gc_upto(ltop, y);
    1715              :   }
    1716              :   else
    1717              :   {
    1718         1824 :     T = FpX_get_red(T, p);
    1719         1824 :     S = FpXQX_get_red(S, T, p);
    1720         1824 :     D.S = S; D.T = T; D.p = p;
    1721         1824 :     if (s < 0) x = FpXQXQ_inv(x,S,T,p);
    1722         1824 :     y = gen_pow_i(x, n, (void*)&D,&_FpXQXQ_sqr,&_FpXQXQ_mul);
    1723         1824 :     return gc_GEN(ltop, y);
    1724              :   }
    1725              : }
    1726              : 
    1727              : /* generates the list of powers of x of degree 0,1,2,...,l*/
    1728              : GEN
    1729         1848 : FpXQXQ_powers(GEN x, long l, GEN S, GEN T, GEN p)
    1730              : {
    1731              :   struct _FpXQXQ D;
    1732         1848 :   int use_sqr = 2*degpol(x) >= get_FpXQX_degree(S);
    1733         1848 :   T = FpX_get_red(T, p);
    1734         1848 :   S = FpXQX_get_red(S, T, p);
    1735         1848 :   D.S = S; D.T = T; D.p = p;
    1736         1848 :   return gen_powers(x, l, use_sqr, (void*)&D, &_FpXQXQ_sqr, &_FpXQXQ_mul,&_FpXQXQ_one);
    1737              : }
    1738              : 
    1739              : /* Let v a linear form, return the linear form z->v(tau*z)
    1740              :    that is, v*(M_tau) */
    1741              : 
    1742              : INLINE GEN
    1743          248 : FpXQX_recipspec(GEN x, long l, long n)
    1744              : {
    1745          248 :   return RgX_recipspec_shallow(x, l, n);
    1746              : }
    1747              : 
    1748              : static GEN
    1749           88 : FpXQXQ_transmul_init(GEN tau, GEN S, GEN T, GEN p)
    1750              : {
    1751              :   GEN bht;
    1752           88 :   GEN h, Sp = get_FpXQX_red(S, &h);
    1753           88 :   long n = degpol(Sp), vT = varn(Sp);
    1754           88 :   GEN ft = FpXQX_recipspec(Sp+2, n+1, n+1);
    1755           88 :   GEN bt = FpXQX_recipspec(tau+2, lgpol(tau), n);
    1756           88 :   setvarn(ft, vT); setvarn(bt, vT);
    1757           88 :   if (h)
    1758           16 :     bht = FpXQXn_mul(bt, h, n-1, T, p);
    1759              :   else
    1760              :   {
    1761           72 :     GEN bh = FpXQX_div(FpXX_shift(tau, n-1), S, T, p);
    1762           72 :     bht = FpXQX_recipspec(bh+2, lgpol(bh), n-1);
    1763           72 :     setvarn(bht, vT);
    1764              :   }
    1765           88 :   return mkvec3(bt, bht, ft);
    1766              : }
    1767              : 
    1768              : static GEN
    1769          200 : FpXQXQ_transmul(GEN tau, GEN a, long n, GEN T, GEN p)
    1770              : {
    1771          200 :   pari_sp ltop = avma;
    1772              :   GEN t1, t2, t3, vec;
    1773          200 :   GEN bt = gel(tau, 1), bht = gel(tau, 2), ft = gel(tau, 3);
    1774          200 :   if (signe(a)==0) return pol_0(varn(a));
    1775          200 :   t2 = FpXX_shift(FpXQX_mul(bt, a, T, p),1-n);
    1776          200 :   if (signe(bht)==0) return gc_GEN(ltop, t2);
    1777          114 :   t1 = FpXX_shift(FpXQX_mul(ft, a, T, p),-n);
    1778          114 :   t3 = FpXQXn_mul(t1, bht, n-1, T, p);
    1779          114 :   vec = FpXX_sub(t2, FpXX_shift(t3, 1), p);
    1780          114 :   return gc_upto(ltop, vec);
    1781              : }
    1782              : 
    1783              : static GEN
    1784           44 : polxn_FpXX(long n, long v, long vT)
    1785              : {
    1786           44 :   long i, a = n+2;
    1787           44 :   GEN p = cgetg(a+1, t_POL);
    1788           44 :   p[1] = evalsigne(1)|evalvarn(v);
    1789          440 :   for (i = 2; i < a; i++) gel(p,i) = pol_0(vT);
    1790           44 :   gel(p,a) = pol_1(vT); return p;
    1791              : }
    1792              : 
    1793              : GEN
    1794           44 : FpXQXQ_minpoly(GEN x, GEN S, GEN T, GEN p)
    1795              : {
    1796           44 :   pari_sp ltop = avma;
    1797              :   long vS, vT, n;
    1798              :   GEN v_x, g, tau;
    1799           44 :   vS = get_FpXQX_var(S);
    1800           44 :   vT = get_FpX_var(T);
    1801           44 :   n = get_FpXQX_degree(S);
    1802           44 :   g = pol_1(vS);
    1803           44 :   tau = pol_1(vS);
    1804           44 :   S = FpXQX_get_red(S, T, p);
    1805           44 :   v_x = FpXQXQ_powers(x, usqrt(2*n), S, T, p);
    1806           88 :   while(signe(tau) != 0)
    1807              :   {
    1808              :     long i, j, m, k1;
    1809              :     GEN M, v, tr;
    1810              :     GEN g_prime, c;
    1811           44 :     if (degpol(g) == n) { tau = pol_1(vS); g = pol_1(vS); }
    1812           44 :     v = random_FpXQX(n, vS, T, p);
    1813           44 :     tr = FpXQXQ_transmul_init(tau, S, T, p);
    1814           44 :     v = FpXQXQ_transmul(tr, v, n, T, p);
    1815           44 :     m = 2*(n-degpol(g));
    1816           44 :     k1 = usqrt(m);
    1817           44 :     tr = FpXQXQ_transmul_init(gel(v_x,k1+1), S, T, p);
    1818           44 :     c = cgetg(m+2,t_POL);
    1819           44 :     c[1] = evalsigne(1)|evalvarn(vS);
    1820          200 :     for (i=0; i<m; i+=k1)
    1821              :     {
    1822          156 :       long mj = minss(m-i, k1);
    1823          552 :       for (j=0; j<mj; j++)
    1824          396 :         gel(c,m+1-(i+j)) = FpXQX_dotproduct(v, gel(v_x,j+1), T, p);
    1825          156 :       v = FpXQXQ_transmul(tr, v, n, T, p);
    1826              :     }
    1827           44 :     c = FpXX_renormalize(c, m+2);
    1828              :     /* now c contains <v,x^i>, i = 0..m-1  */
    1829           44 :     M = FpXQX_halfgcd(polxn_FpXX(m, vS, vT), c, T, p);
    1830           44 :     g_prime = gmael(M, 2, 2);
    1831           44 :     if (degpol(g_prime) < 1) continue;
    1832           44 :     g = FpXQX_mul(g, g_prime, T, p);
    1833           44 :     tau = FpXQXQ_mul(tau, FpXQX_FpXQXQV_eval(g_prime, v_x, S, T, p), S, T, p);
    1834              :   }
    1835           44 :   g = FpXQX_normalize(g,T, p);
    1836           44 :   return gc_GEN(ltop,g);
    1837              : }
    1838              : 
    1839              : GEN
    1840            0 : FpXQXQ_matrix_pow(GEN y, long n, long m, GEN S, GEN T, GEN p)
    1841              : {
    1842            0 :   return RgXV_to_RgM(FpXQXQ_powers(y,m-1,S,T,p),n);
    1843              : }
    1844              : 
    1845              : GEN
    1846         3957 : FpXQX_FpXQXQV_eval(GEN P, GEN V, GEN S, GEN T, GEN p)
    1847              : {
    1848              :   struct _FpXQXQ D;
    1849         3957 :   T = FpX_get_red(T, p);
    1850         3957 :   S = FpXQX_get_red(S, T, p);
    1851         3957 :   D.S=S; D.T=T; D.p=p;
    1852         3957 :   return gen_bkeval_powers(P, degpol(P), V, (void*)&D, &FpXQXQ_algebra,
    1853              :                                                    _FpXQXQ_cmul);
    1854              : }
    1855              : 
    1856              : GEN
    1857          855 : FpXQX_FpXQXQ_eval(GEN Q, GEN x, GEN S, GEN T, GEN p)
    1858              : {
    1859              :   struct _FpXQXQ D;
    1860          855 :   int use_sqr = 2*degpol(x) >= get_FpXQX_degree(S);
    1861          855 :   T = FpX_get_red(T, p);
    1862          855 :   S = FpXQX_get_red(S, T, p);
    1863          855 :   D.S=S; D.T=T; D.p=p;
    1864          855 :   return gen_bkeval(Q, degpol(Q), x, use_sqr, (void*)&D, &FpXQXQ_algebra,
    1865              :       _FpXQXQ_cmul);
    1866              : }
    1867              : 
    1868              : static GEN
    1869          507 : FpXQXQ_autpow_sqr(void * E, GEN x)
    1870              : {
    1871          507 :   struct _FpXQXQ *D = (struct _FpXQXQ *)E;
    1872          507 :   GEN S = D->S, T = D->T, p = D->p;
    1873          507 :   GEN phi = gel(x,1), S1 = gel(x,2);
    1874          507 :   long n = brent_kung_optpow(get_FpX_degree(T)-1,lgpol(S1)+1,1);
    1875          507 :   GEN V = FpXQ_powers(phi, n, T, p);
    1876          507 :   GEN phi2 = FpX_FpXQV_eval(phi, V, T, p);
    1877          507 :   GEN Sphi = FpXY_FpXQV_evalx(S1, V, T, p);
    1878          507 :   GEN S2 = FpXQX_FpXQXQ_eval(Sphi, S1, S, T, p);
    1879          507 :   return mkvec2(phi2, S2);
    1880              : }
    1881              : 
    1882              : static GEN
    1883          325 : FpXQXQ_autpow_mul(void * E, GEN x, GEN y)
    1884              : {
    1885          325 :   struct _FpXQXQ *D = (struct _FpXQXQ *)E;
    1886          325 :   GEN S = D->S, T = D->T, p = D->p;
    1887          325 :   GEN phi1 = gel(x,1), S1 = gel(x,2);
    1888          325 :   GEN phi2 = gel(y,1), S2 = gel(y,2);
    1889          325 :   long n = brent_kung_optpow(get_FpX_degree(T)-1, lgpol(S1)+1, 1);
    1890          325 :   GEN V = FpXQ_powers(phi2, n, T, p);
    1891          325 :   GEN phi3 = FpX_FpXQV_eval(phi1, V, T, p);
    1892          325 :   GEN Sphi = FpXY_FpXQV_evalx(S1, V, T, p);
    1893          325 :   GEN S3 = FpXQX_FpXQXQ_eval(Sphi, S2, S, T, p);
    1894          325 :   return mkvec2(phi3, S3);
    1895              : }
    1896              : 
    1897              : GEN
    1898          493 : FpXQXQ_autpow(GEN aut, long n, GEN S, GEN T, GEN p)
    1899              : {
    1900          493 :   pari_sp av = avma;
    1901              :   struct _FpXQXQ D;
    1902          493 :   T = FpX_get_red(T, p);
    1903          493 :   S = FpXQX_get_red(S, T, p);
    1904          493 :   D.S=S; D.T=T; D.p=p;
    1905          493 :   aut = gen_powu_i(aut,n,&D,FpXQXQ_autpow_sqr,FpXQXQ_autpow_mul);
    1906          493 :   return gc_GEN(av, aut);
    1907              : }
    1908              : 
    1909              : static GEN
    1910            1 : FpXQXQ_auttrace_mul(void *E, GEN x, GEN y)
    1911              : {
    1912            1 :   struct _FpXQXQ *D = (struct _FpXQXQ *)E;
    1913            1 :   GEN S = D->S, T = D->T;
    1914            1 :   GEN p = D->p;
    1915            1 :   GEN S1 = gel(x,1), a1 = gel(x,2);
    1916            1 :   GEN S2 = gel(y,1), a2 = gel(y,2);
    1917            1 :   long n = brent_kung_optpow(maxss(degpol(S1),degpol(a1)),2,1);
    1918            1 :   GEN V = FpXQXQ_powers(S2, n, S, T, p);
    1919            1 :   GEN S3 = FpXQX_FpXQXQV_eval(S1, V, S, T, p);
    1920            1 :   GEN aS = FpXQX_FpXQXQV_eval(a1, V, S, T, p);
    1921            1 :   GEN a3 = FpXX_add(aS, a2, p);
    1922            1 :   return mkvec2(S3, a3);
    1923              : }
    1924              : 
    1925              : static GEN
    1926            1 : FpXQXQ_auttrace_sqr(void *E, GEN x)
    1927            1 : { return FpXQXQ_auttrace_mul(E, x, x); }
    1928              : 
    1929              : GEN
    1930            8 : FpXQXQ_auttrace(GEN aut, long n, GEN S, GEN T, GEN p)
    1931              : {
    1932            8 :   pari_sp av = avma;
    1933              :   struct _FpXQXQ D;
    1934            8 :   T = FpX_get_red(T, p);
    1935            8 :   S = FpXQX_get_red(S, T, p);
    1936            8 :   D.S=S; D.T=T; D.p=p;
    1937            8 :   aut = gen_powu_i(aut,n,&D,FpXQXQ_auttrace_sqr,FpXQXQ_auttrace_mul);
    1938            8 :   return gc_GEN(av, aut);
    1939              : }
    1940              : 
    1941              : static GEN
    1942         1316 : FpXQXQ_autsum_mul(void *E, GEN x, GEN y)
    1943              : {
    1944         1316 :   struct _FpXQXQ *D = (struct _FpXQXQ *) E;
    1945         1316 :   GEN S = D->S, T = D->T, p = D->p;
    1946         1316 :   GEN phi1 = gel(x,1), S1 = gel(x,2), a1 = gel(x,3);
    1947         1316 :   GEN phi2 = gel(y,1), S2 = gel(y,2), a2 = gel(y,3);
    1948         1316 :   long n2 = brent_kung_optpow(get_FpX_degree(T)-1, lgpol(S1)+lgpol(a1)+1, 1);
    1949         1316 :   GEN V2 = FpXQ_powers(phi2, n2, T, p);
    1950         1316 :   GEN phi3 = FpX_FpXQV_eval(phi1, V2, T, p);
    1951         1316 :   GEN Sphi = FpXY_FpXQV_evalx(S1, V2, T, p);
    1952         1316 :   GEN aphi = FpXY_FpXQV_evalx(a1, V2, T, p);
    1953         1316 :   long n = brent_kung_optpow(maxss(degpol(Sphi),degpol(aphi)),2,1);
    1954         1316 :   GEN V = FpXQXQ_powers(S2, n, S, T, p);
    1955         1316 :   GEN S3 = FpXQX_FpXQXQV_eval(Sphi, V, S, T, p);
    1956         1316 :   GEN aS = FpXQX_FpXQXQV_eval(aphi, V, S, T, p);
    1957         1316 :   GEN a3 = FpXQXQ_mul(aS, a2, S, T, p);
    1958         1316 :   return mkvec3(phi3, S3, a3);
    1959              : }
    1960              : 
    1961              : static GEN
    1962         1198 : FpXQXQ_autsum_sqr(void * T, GEN x)
    1963         1198 : { return FpXQXQ_autsum_mul(T,x,x); }
    1964              : 
    1965              : GEN
    1966         1184 : FpXQXQ_autsum(GEN aut, long n, GEN S, GEN T, GEN p)
    1967              : {
    1968         1184 :   pari_sp av = avma;
    1969              :   struct _FpXQXQ D;
    1970         1184 :   T = FpX_get_red(T, p);
    1971         1184 :   S = FpXQX_get_red(S, T, p);
    1972         1184 :   D.S=S; D.T=T; D.p=p;
    1973         1184 :   aut = gen_powu_i(aut,n,&D,FpXQXQ_autsum_sqr,FpXQXQ_autsum_mul);
    1974         1184 :   return gc_GEN(av, aut);
    1975              : }
    1976              : 
    1977              : GEN
    1978        41367 : FpXQXn_mul(GEN x, GEN y, long n, GEN T, GEN p)
    1979              : {
    1980        41367 :   pari_sp av = avma;
    1981              :   GEN z, kx, ky;
    1982              :   long d;
    1983        41367 :   if (ZXX_is_ZX(y) && ZXX_is_ZX(x))
    1984         6426 :     return FpXn_mul(x,y,n,p);
    1985        34941 :   d = get_FpX_degree(T);
    1986        34941 :   kx = RgXX_to_Kronecker(x, d);
    1987        34941 :   ky = RgXX_to_Kronecker(y, d);
    1988        34941 :   z = Kronecker_to_FpXQX(ZXn_mul(ky,kx,(2*d-1)*n), T, p);
    1989        34941 :   return gc_upto(av, z);
    1990              : }
    1991              : 
    1992              : GEN
    1993            0 : FpXQXn_sqr(GEN x, long n, GEN T, GEN p)
    1994              : {
    1995            0 :   pari_sp av = avma;
    1996              :   GEN z, kx;
    1997              :   long d;
    1998            0 :   if (ZXX_is_ZX(x)) return ZXn_sqr(x, n);
    1999            0 :   d = get_FpX_degree(T);
    2000            0 :   kx= RgXX_to_Kronecker(x, d);
    2001            0 :   z = Kronecker_to_FpXQX(ZXn_sqr(kx, (2*d-1)*n), T, p);
    2002            0 :   return gc_upto(av, z);
    2003              : }
    2004              : 
    2005              : /* (f*g) \/ x^n */
    2006              : static GEN
    2007         6881 : FpXQX_mulhigh_i(GEN f, GEN g, long n, GEN T, GEN p)
    2008              : {
    2009         6881 :   return FpXX_shift(FpXQX_mul(f,g,T, p),-n);
    2010              : }
    2011              : 
    2012              : static GEN
    2013         4368 : FpXQXn_mulhigh(GEN f, GEN g, long n2, long n, GEN T, GEN p)
    2014              : {
    2015         4368 :   GEN F = RgX_blocks(f, n2, 2), fl = gel(F,1), fh = gel(F,2);
    2016         4368 :   return FpXX_add(FpXQX_mulhigh_i(fl, g, n2, T, p), FpXQXn_mul(fh, g, n - n2, T, p), p);
    2017              : }
    2018              : 
    2019              : /* Compute intformal(x^n*S)/x^(n+1) */
    2020              : static GEN
    2021          763 : FpXX_integXn(GEN x, long n, GEN p)
    2022              : {
    2023          763 :   long i, lx = lg(x);
    2024              :   GEN y;
    2025          763 :   if (lx == 2) return ZXX_copy(x);
    2026          763 :   y = cgetg(lx, t_POL); y[1] = x[1];
    2027         4317 :   for (i=2; i<lx; i++)
    2028              :   {
    2029         3554 :     ulong j = n+i-1;
    2030         3554 :     GEN xi = gel(x,i);
    2031         3554 :     if (!signe(xi))
    2032            0 :       gel(y,i) = gen_0;
    2033              :     else
    2034         3554 :       gel(y,i) = typ(xi)==t_INT ? Fp_divu(xi, j, p)
    2035         3554 :                                 : FpX_divu(xi, j, p);
    2036              :   }
    2037          763 :   return ZXX_renormalize(y, lx);;
    2038              : }
    2039              : 
    2040              : /* Compute intformal(x^n*S)/x^(n+1) */
    2041              : static GEN
    2042         2513 : ZlXX_integXn(GEN x, long n, GEN p, ulong pp)
    2043              : {
    2044         2513 :   long i, lx = lg(x);
    2045              :   GEN y;
    2046         2513 :   if (lx == 2) return ZXX_copy(x);
    2047         2387 :   if (!pp) return FpXX_integXn(x, n, p);
    2048         1624 :   y = cgetg(lx, t_POL); y[1] = x[1];
    2049         6183 :   for (i=2; i<lx; i++)
    2050              :   {
    2051         4559 :     GEN xi = gel(x,i);
    2052         4559 :     if (!signe(xi))
    2053           14 :       gel(y,i) = gen_0;
    2054              :     else
    2055              :     {
    2056              :       ulong j;
    2057         4545 :       long v = u_lvalrem(n+i-1, pp, &j);
    2058         4545 :       if (typ(xi)==t_INT)
    2059              :       {
    2060            0 :         if (v==0)
    2061            0 :           gel(y,i) = Fp_divu(xi, j, p);
    2062              :         else
    2063            0 :           gel(y,i) = Fp_divu(diviuexact(xi, upowuu(pp, v)), j, p);
    2064              :       } else
    2065              :       {
    2066         4545 :         if (v==0)
    2067         4545 :           gel(y,i) = FpX_divu(xi, j, p);
    2068              :         else
    2069            0 :           gel(y,i) = FpX_divu(ZX_divuexact(xi, upowuu(pp, v)), j, p);
    2070              :       }
    2071              :     }
    2072              :   }
    2073         1624 :   return ZXX_renormalize(y, lx);;
    2074              : }
    2075              : 
    2076              : GEN
    2077          658 : ZlXQXn_expint(GEN h, long e, GEN T, GEN p, ulong pp)
    2078              : {
    2079          658 :   pari_sp av = avma, av2;
    2080          658 :   long v = varn(h), n=1;
    2081          658 :   GEN f = pol_1(v), g = pol_1(v);
    2082          658 :   ulong mask = quadratic_prec_mask(e);
    2083          658 :   av2 = avma;
    2084         2513 :   for (;mask>1;)
    2085              :   {
    2086              :     GEN u, w;
    2087         2513 :     long n2 = n;
    2088         2513 :     n<<=1; if (mask & 1) n--;
    2089         2513 :     mask >>= 1;
    2090         2513 :     u = FpXQXn_mul(g, FpXQX_mulhigh_i(f, FpXXn_red(h, n2-1), n2-1, T, p), n-n2, T, p);
    2091         2513 :     u = FpXX_add(u, FpXX_shift(FpXXn_red(h, n-1), 1-n2), p);
    2092         2513 :     w = FpXQXn_mul(f, ZlXX_integXn(u, n2-1, p, pp), n-n2, T, p);
    2093         2513 :     f = FpXX_add(f, FpXX_shift(w, n2), p);
    2094         2513 :     if (mask<=1) break;
    2095         1855 :     u = FpXQXn_mul(g, FpXQXn_mulhigh(f, g, n2, n, T, p), n-n2, T, p);
    2096         1855 :     g = FpXX_sub(g, FpXX_shift(u, n2), p);
    2097         1855 :     if (gc_needed(av2,2))
    2098              :     {
    2099            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FpXQXn_exp, e = %ld", n);
    2100            0 :       (void)gc_all(av2, 2, &f, &g);
    2101              :     }
    2102              :   }
    2103          658 :   return gc_upto(av, f);
    2104              : }
    2105              : 
    2106              : GEN
    2107          178 : FpXQXn_expint(GEN h, long e, GEN T, GEN p)
    2108          178 : { return ZlXQXn_expint(h, e, T, p, 0); }
    2109              : 
    2110              : GEN
    2111            0 : FpXQXn_exp(GEN h, long e, GEN T, GEN p)
    2112              : {
    2113            0 :   if (signe(h)==0 || degpol(h)<1 || !gequal0(gel(h,2)))
    2114            0 :     pari_err_DOMAIN("FpXQXn_exp","valuation", "<", gen_1, h);
    2115            0 :   return FpXQXn_expint(FpXX_deriv(h, p), e, T, p);
    2116              : }
    2117              : 
    2118              : GEN
    2119          658 : FpXQXn_div(GEN g, GEN f, long e, GEN T, GEN p)
    2120              : {
    2121          658 :   pari_sp av = avma, av2;
    2122              :   ulong mask;
    2123              :   GEN W, a;
    2124          658 :   long v = varn(f), n = 1;
    2125              : 
    2126          658 :   if (!signe(f)) pari_err_INV("FpXXn_inv",f);
    2127          658 :   a = Fq_inv(gel(f,2), T, p);
    2128          658 :   if (e == 1 && !g) return scalarpol(a, v);
    2129          658 :   else if (e == 2 && !g)
    2130              :   {
    2131              :     GEN b;
    2132            0 :     if (degpol(f) <= 0) return scalarpol(a, v);
    2133            0 :     b = Fq_neg(gel(f,3),T,p);
    2134            0 :     if (signe(b)==0) return scalarpol(a, v);
    2135            0 :     b = Fq_mul(b, Fq_sqr(a, T, p), T, p);
    2136            0 :     W = deg1pol_shallow(b, a, v);
    2137            0 :     return gc_GEN(av, W);
    2138              :   }
    2139          658 :   W = scalarpol_shallow(Fq_inv(gel(f,2), T, p),v);
    2140          658 :   mask = quadratic_prec_mask(e);
    2141          658 :   av2 = avma;
    2142         3171 :   for (;mask>1;)
    2143              :   {
    2144              :     GEN u, fr;
    2145         2513 :     long n2 = n;
    2146         2513 :     n<<=1; if (mask & 1) n--;
    2147         2513 :     mask >>= 1;
    2148         2513 :     fr = FpXXn_red(f, n);
    2149         2513 :     if (mask>1 || !g)
    2150              :     {
    2151         2513 :       u = FpXQXn_mul(W, FpXQXn_mulhigh(fr, W, n2, n, T, p), n-n2, T, p);
    2152         2513 :       W = FpXX_sub(W, FpXX_shift(u, n2), p);
    2153              :     }
    2154              :     else
    2155              :     {
    2156            0 :       GEN y = FpXQXn_mul(g, W, n, T, p), yt =  FpXXn_red(y, n-n2);
    2157            0 :       u = FpXQXn_mul(yt, FpXQXn_mulhigh(fr,  W, n2, n, T, p), n-n2, T, p);
    2158            0 :       W = FpXX_sub(y, FpXX_shift(u, n2), p);
    2159              :     }
    2160         2513 :     if (gc_needed(av2,2))
    2161              :     {
    2162            0 :       if(DEBUGMEM>1) pari_warn(warnmem,"FpXQXn_inv, e = %ld", n);
    2163            0 :       W = gc_upto(av2, W);
    2164              :     }
    2165              :   }
    2166          658 :   return gc_upto(av, W);
    2167              : }
    2168              : 
    2169              : GEN
    2170          658 : FpXQXn_inv(GEN f, long e, GEN T, GEN p)
    2171          658 : { return FpXQXn_div(NULL, f, e, T, p); }
        

Generated by: LCOV version 2.0-1