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 - FlxX.c (source / functions) Coverage Total Hit
Test: PARI/GP v2.18.1 lcov report (development 31042-0fbe168e69) Lines: 80.5 % 1492 1201
Test Date: 2026-07-23 17:04:59 Functions: 75.5 % 200 151
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Copyright (C) 2019  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              : /***********************************************************************/
      19              : /**                                                                   **/
      20              : /**                               FlxX                                **/
      21              : /**                                                                   **/
      22              : /***********************************************************************/
      23              : 
      24              : /* FlxX are t_POL with Flx coefficients.
      25              :  * Normally the variable ordering should be respected.*/
      26              : 
      27              : /*Similar to normalizepol, in place*/
      28              : /*FlxX_renormalize=zxX_renormalize */
      29              : GEN
      30     17969390 : FlxX_renormalize(GEN /*in place*/ x, long lx)
      31              : {
      32              :   long i;
      33     22925112 :   for (i = lx-1; i>1; i--)
      34     22141416 :     if (lgpol(gel(x,i))) break;
      35     17969390 :   stackdummy((pari_sp)(x + lg(x)), (pari_sp)(x + i+1));
      36     17969390 :   setlg(x, i+1); setsigne(x, i!=1); return x;
      37              : }
      38              : 
      39              : GEN
      40       760668 : pol1_FlxX(long v, long sv)
      41              : {
      42       760668 :   GEN z = cgetg(3, t_POL);
      43       760668 :   z[1] = evalsigne(1) | evalvarn(v);
      44       760668 :   gel(z,2) = pol1_Flx(sv); return z;
      45              : }
      46              : 
      47              : GEN
      48       692005 : polx_FlxX(long v, long sv)
      49              : {
      50       692005 :   GEN z = cgetg(4, t_POL);
      51       692005 :   z[1] = evalsigne(1) | evalvarn(v);
      52       692005 :   gel(z,2) = pol0_Flx(sv);
      53       692005 :   gel(z,3) = pol1_Flx(sv); return z;
      54              : }
      55              : 
      56              : long
      57      3067261 : FlxY_degreex(GEN b)
      58              : {
      59      3067261 :   long deg = 0, i;
      60      3067261 :   if (!signe(b)) return -1;
      61     10993877 :   for (i = 2; i < lg(b); ++i)
      62      7926616 :     deg = maxss(deg, degpol(gel(b, i)));
      63      3067261 :   return deg;
      64              : }
      65              : 
      66              : /*Lift coefficient of B to constant Flx, to give a FlxY*/
      67              : GEN
      68         2565 : Fly_to_FlxY(GEN B, long sv)
      69              : {
      70         2565 :   long lb=lg(B);
      71              :   long i;
      72         2565 :   GEN b=cgetg(lb,t_POL);
      73         2565 :   b[1]=evalsigne(1)|(((ulong)B[1])&VARNBITS);
      74        67006 :   for (i=2; i<lb; i++)
      75        64441 :     gel(b,i) = Fl_to_Flx(B[i], sv);
      76         2565 :   return FlxX_renormalize(b, lb);
      77              : }
      78              : 
      79              : GEN
      80      2864835 : zxX_to_FlxX(GEN B, ulong p)
      81              : {
      82      2864835 :   long i, lb = lg(B);
      83      2864835 :   GEN b = cgetg(lb,t_POL);
      84      9357831 :   for (i=2; i<lb; i++)
      85      6492996 :     gel(b,i) = zx_to_Flx(gel(B,i), p);
      86      2864835 :   b[1] = B[1]; return FlxX_renormalize(b, lb);
      87              : }
      88              : 
      89              : GEN
      90      2782427 : FlxX_to_ZXX(GEN B)
      91              : {
      92      2782427 :   long i, lb = lg(B);
      93      2782427 :   GEN b = cgetg(lb,t_POL);
      94      8935666 :   for (i=2; i<lb; i++)
      95              :   {
      96      6153239 :     GEN c = gel(B,i);
      97      6153239 :     switch(lgpol(c))
      98              :     {
      99       267910 :       case 0:  c = gen_0; break;
     100       796757 :       case 1:  c = utoi(c[2]); break;
     101      5088572 :       default: c = Flx_to_ZX(c); break;
     102              :     }
     103      6153239 :     gel(b,i) = c;
     104              :   }
     105      2782427 :   b[1] = B[1]; return b;
     106              : }
     107              : 
     108              : /* Note: v is used _only_ for the t_INT. It must match
     109              :  * the variable of any t_POL coefficients. */
     110              : GEN
     111      4706572 : ZXX_to_FlxX(GEN B, ulong p, long v)
     112              : {
     113      4706572 :   long lb=lg(B);
     114              :   long i;
     115      4706572 :   GEN b=cgetg(lb,t_POL);
     116      4706572 :   b[1]=evalsigne(1)|(((ulong)B[1])&VARNBITS);
     117     21634741 :   for (i=2; i<lb; i++)
     118     16928169 :     switch (typ(gel(B,i)))
     119              :     {
     120      7124923 :     case t_INT:
     121      7124923 :       gel(b,i) = Z_to_Flx(gel(B,i), p, evalvarn(v));
     122      7124923 :       break;
     123      9803246 :     case t_POL:
     124      9803246 :       gel(b,i) = ZX_to_Flx(gel(B,i), p);
     125      9803246 :       break;
     126              :     }
     127      4706572 :   return FlxX_renormalize(b, lb);
     128              : }
     129              : 
     130              : GEN
     131            0 : ZXXV_to_FlxXV(GEN x, ulong p, long v)
     132            0 : { pari_APPLY_type(t_VEC, ZXX_to_FlxX(gel(x,i), p, v)) }
     133              : 
     134              : GEN
     135          442 : ZXXT_to_FlxXT(GEN x, ulong p, long v)
     136              : {
     137          442 :   if (typ(x) == t_POL)
     138          428 :     return ZXX_to_FlxX(x, p, v);
     139              :   else
     140           42 :     pari_APPLY_type(t_VEC, ZXXT_to_FlxXT(gel(x,i), p, v))
     141              : }
     142              : 
     143              : GEN
     144       328131 : FlxX_to_FlxC(GEN x, long N, long sv)
     145              : {
     146              :   long i, l;
     147              :   GEN z;
     148       328131 :   l = lg(x)-1; x++;
     149       328131 :   if (l > N+1) l = N+1; /* truncate higher degree terms */
     150       328131 :   z = cgetg(N+1,t_COL);
     151      2990274 :   for (i=1; i<l ; i++) gel(z,i) = gel(x,i);
     152      3601734 :   for (   ; i<=N; i++) gel(z,i) = pol0_Flx(sv);
     153       328131 :   return z;
     154              : }
     155              : 
     156              : /* matrix whose entries are given by the coeffs of the polynomial v in
     157              :  * two variables (considered as degree n polynomials) */
     158              : GEN
     159        58299 : FlxX_to_Flm(GEN v, long n)
     160              : {
     161        58299 :   long j, N = lg(v)-1;
     162        58299 :   GEN y = cgetg(N, t_MAT);
     163        58299 :   v++;
     164       204854 :   for (j=1; j<N; j++) gel(y,j) = Flx_to_Flv(gel(v,j), n);
     165        58299 :   return y;
     166              : }
     167              : 
     168              : GEN
     169       378159 : FlxX_to_Flx(GEN f)
     170              : {
     171       378159 :   long i, l = lg(f);
     172       378159 :   GEN V = cgetg(l, t_VECSMALL);
     173       378159 :   V[1] = ((ulong)f[1])&VARNBITS;
     174      3559405 :   for(i=2; i<l; i++)
     175      3181246 :     V[i] = lgpol(gel(f,i)) ? mael(f,i,2): 0L;
     176       378159 :   return V;
     177              : }
     178              : 
     179              : GEN
     180       221990 : Flm_to_FlxX(GEN x, long v,long w)
     181              : {
     182       221990 :   long j, lx = lg(x);
     183       221990 :   GEN y = cgetg(lx+1, t_POL);
     184       221990 :   y[1]=evalsigne(1) | v;
     185       221990 :   y++;
     186       816075 :   for (j=1; j<lx; j++) gel(y,j) = Flv_to_Flx(gel(x,j), w);
     187       221990 :   return FlxX_renormalize(--y, lx+1);
     188              : }
     189              : 
     190              : /* P(X,Y) --> P(Y,X), n is the degree in Y */
     191              : GEN
     192       181920 : FlxX_swap(GEN x, long n, long ws)
     193              : {
     194       181920 :   long j, lx = lg(x), ly = n+3;
     195       181920 :   GEN y = cgetg(ly, t_POL);
     196       181920 :   y[1] = x[1];
     197      1169418 :   for (j=2; j<ly; j++)
     198              :   {
     199              :     long k;
     200       987498 :     GEN p1 = cgetg(lx, t_VECSMALL);
     201       987498 :     p1[1] = ws;
     202     11227877 :     for (k=2; k<lx; k++)
     203     10240379 :       if (j<lg(gel(x,k)))
     204      7199741 :         p1[k] = mael(x,k,j);
     205              :       else
     206      3040638 :         p1[k] = 0;
     207       987498 :     gel(y,j) = Flx_renormalize(p1,lx);
     208              :   }
     209       181920 :   return FlxX_renormalize(y,ly);
     210              : }
     211              : 
     212              : static GEN
     213      4537658 : zxX_to_Kronecker_spec(GEN P, long lp, long n)
     214              : { /* P(X) = sum Pi(Y) * X^i, return P( Y^(2n-1) ) */
     215      4537658 :   long i, j, k, l, N = (n<<1) + 1;
     216      4537658 :   GEN y = cgetg((N-2)*lp + 2, t_VECSMALL) + 2;
     217     37893800 :   for (k=i=0; i<lp; i++)
     218              :   {
     219     37857157 :     GEN c = gel(P,i);
     220     37857157 :     l = lg(c);
     221     37857157 :     if (l-3 >= n)
     222            0 :       pari_err_BUG("zxX_to_Kronecker, P is not reduced mod Q");
     223    169618382 :     for (j=2; j < l; j++) y[k++] = c[j];
     224     37857157 :     if (i == lp-1) break;
     225    275949064 :     for (   ; j < N; j++) y[k++] = 0;
     226              :   }
     227      4537658 :   y -= 2;
     228      4537658 :   y[1] = 0; setlg(y, k+2); return y;
     229              : }
     230              : 
     231              : GEN
     232      3822282 : zxX_to_Kronecker(GEN P, GEN Q)
     233              : {
     234      3822282 :   GEN z = zxX_to_Kronecker_spec(P+2, lg(P)-2, degpol(Q));
     235      3822282 :   z[1] = P[1]; return z;
     236              : }
     237              : 
     238              : GEN
     239       360094 : FlxX_add(GEN x, GEN y, ulong p)
     240              : {
     241              :   long i,lz;
     242              :   GEN z;
     243       360094 :   long lx=lg(x);
     244       360094 :   long ly=lg(y);
     245       360094 :   if (ly>lx) swapspec(x,y, lx,ly);
     246       360094 :   lz = lx; z = cgetg(lz, t_POL); z[1]=x[1];
     247      4720395 :   for (i=2; i<ly; i++) gel(z,i) = Flx_add(gel(x,i), gel(y,i), p);
     248      2185145 :   for (   ; i<lx; i++) gel(z,i) = Flx_copy(gel(x,i));
     249       360094 :   return FlxX_renormalize(z, lz);
     250              : }
     251              : 
     252              : GEN
     253          245 : FlxY_Flx_add(GEN y, GEN x, ulong p)
     254              : {
     255          245 :   long i, lz = lg(y);
     256              :   GEN z;
     257          245 :   if (signe(y) == 0) return scalarpol(x, varn(y));
     258          245 :   z = cgetg(lz,t_POL); z[1] = y[1];
     259          245 :   gel(z,2) = Flx_add(gel(y,2), x, p);
     260          245 :   if (lz == 3) z = FlxX_renormalize(z,lz);
     261              :   else
     262         1071 :     for(i=3;i<lz;i++) gel(z,i) = Flx_copy(gel(y,i));
     263          245 :   return z;
     264              : }
     265              : 
     266              : GEN
     267        11703 : FlxY_Flx_sub(GEN y, GEN x, ulong p)
     268              : {
     269        11703 :   long i, lz = lg(y);
     270              :   GEN z;
     271        11703 :   if (signe(y) == 0) return scalarpol(x, varn(y));
     272        11703 :   z = cgetg(lz,t_POL); z[1] = y[1];
     273        11703 :   gel(z,2) = Flx_sub(gel(y,2), x, p);
     274        11703 :   if (lz == 3) z = FlxX_renormalize(z,lz);
     275              :   else
     276        84534 :     for(i=3;i<lz;i++) gel(z,i) = Flx_copy(gel(y,i));
     277        11703 :   return z;
     278              : }
     279              : 
     280              : GEN
     281         2538 : FlxX_neg(GEN x, ulong p)
     282              : {
     283         2538 :   long i, lx=lg(x);
     284         2538 :   GEN z = cgetg(lx, t_POL);
     285         2538 :   z[1]=x[1];
     286        43405 :   for (i=2; i<lx; i++) gel(z,i) = Flx_neg(gel(x,i), p);
     287         2538 :   return z;
     288              : }
     289              : 
     290              : GEN
     291          684 : FlxX_Fl_mul(GEN x, ulong y, ulong p)
     292              : {
     293          684 :   long i, lx=lg(x);
     294          684 :   GEN z = cgetg(lx, t_POL);
     295          684 :   z[1]=x[1];
     296         3296 :   for (i=2; i<lx; i++) gel(z,i) = Flx_Fl_mul(gel(x,i), y, p);
     297          684 :   return FlxX_renormalize(z, lx);
     298              : }
     299              : 
     300              : GEN
     301            0 : FlxX_triple(GEN x, ulong p)
     302              : {
     303            0 :   long i, lx=lg(x);
     304            0 :   GEN z = cgetg(lx, t_POL);
     305            0 :   z[1]=x[1];
     306            0 :   for (i=2; i<lx; i++) gel(z,i) = Flx_triple(gel(x,i), p);
     307            0 :   return FlxX_renormalize(z, lx);
     308              : }
     309              : 
     310              : GEN
     311          684 : FlxX_double(GEN x, ulong p)
     312              : {
     313          684 :   long i, lx=lg(x);
     314          684 :   GEN z = cgetg(lx, t_POL);
     315          684 :   z[1]=x[1];
     316         5472 :   for (i=2; i<lx; i++) gel(z,i) = Flx_double(gel(x,i), p);
     317          684 :   return FlxX_renormalize(z, lx);
     318              : }
     319              : 
     320              : GEN
     321        85571 : FlxX_deriv(GEN z, ulong p)
     322              : {
     323        85571 :   long i,l = lg(z)-1;
     324              :   GEN x;
     325        85571 :   if (l < 2) l = 2;
     326        85571 :   x = cgetg(l, t_POL); x[1] = z[1];
     327       966413 :   for (i=2; i<l; i++) gel(x,i) = Flx_mulu(gel(z,i+1), (ulong) i-1, p);
     328        85571 :   return FlxX_renormalize(x,l);
     329              : }
     330              : 
     331              : GEN
     332            0 : FlxX_translate1(GEN P, ulong p, long n)
     333              : {
     334              :   GEN Q;
     335            0 :   long i, l, ws, lP = lgpol(P);
     336            0 :   if (!lP) return gcopy(P);
     337            0 :   ws = mael(P,2,1);
     338            0 :   Q = FlxX_swap(P, n, ws);
     339            0 :   l = lg(Q);
     340            0 :   for (i=2; i<l; i++) gel(Q, i) = Flx_translate1(gel(Q, i), p);
     341            0 :   return FlxX_swap(Q, lP, ws);
     342              : }
     343              : 
     344              : GEN
     345            0 : zlxX_translate1(GEN P, ulong p, long e, long n)
     346              : {
     347              :   GEN Q;
     348            0 :   long i, l, ws, lP = lgpol(P);
     349            0 :   if (!lP) return gcopy(P);
     350            0 :   ws = mael(P,2,1);
     351            0 :   Q = FlxX_swap(P, n, ws);
     352            0 :   l = lg(Q);
     353            0 :   for (i=2; i<l; i++) gel(Q, i) = zlx_translate1(gel(Q, i), p, e);
     354            0 :   return FlxX_swap(Q, lP, ws);
     355              : }
     356              : 
     357              : static GEN
     358       132746 : FlxX_subspec(GEN x, GEN y, ulong p, long lx, long ly)
     359              : {
     360              :   long i,lz;
     361              :   GEN z;
     362              : 
     363       132746 :   if (ly <= lx)
     364              :   {
     365       132746 :     lz = lx+2; z = cgetg(lz, t_POL);
     366      4911339 :     for (i=0; i<ly; i++) gel(z,i+2) = Flx_sub(gel(x,i),gel(y,i),p);
     367       134609 :     for (   ; i<lx; i++) gel(z,i+2) = Flx_copy(gel(x,i));
     368              :   }
     369              :   else
     370              :   {
     371            0 :     lz = ly+2; z = cgetg(lz, t_POL);
     372            0 :     for (i=0; i<lx; i++) gel(z,i+2) = Flx_sub(gel(x,i),gel(y,i),p);
     373            0 :     for (   ; i<ly; i++) gel(z,i+2) = Flx_neg(gel(y,i),p);
     374              :   }
     375       132746 :   z[1] = 0; return FlxX_renormalize(z, lz);
     376              : }
     377              : 
     378              : GEN
     379       626217 : FlxX_sub(GEN x, GEN y, ulong p)
     380              : {
     381              :   long lx,ly,i,lz;
     382              :   GEN z;
     383       626217 :   lx = lg(x); ly = lg(y);
     384       626217 :   lz=maxss(lx,ly);
     385       626217 :   z = cgetg(lz,t_POL);
     386       626217 :   if (lx >= ly)
     387              :   {
     388       110106 :     z[1] = x[1];
     389       625856 :     for (i=2; i<ly; i++) gel(z,i) = Flx_sub(gel(x,i),gel(y,i),p);
     390       386849 :     for (   ; i<lx; i++) gel(z,i) = Flx_copy(gel(x,i));
     391       110106 :     if (lx==ly) z = FlxX_renormalize(z, lz);
     392              :   }
     393              :   else
     394              :   {
     395       516111 :     z[1] = y[1];
     396      1302112 :     for (i=2; i<lx; i++) gel(z,i) = Flx_sub(gel(x,i),gel(y,i),p);
     397      1388420 :     for (   ; i<ly; i++) gel(z,i) = Flx_neg(gel(y,i),p);
     398              :   }
     399       626217 :   if (!lgpol(z)) { set_avma((pari_sp)(z + lz)); z = pol_0(varn(x)); }
     400       626217 :   return z;
     401              : }
     402              : 
     403              : GEN
     404            0 : FlxY_Flx_mul_pre(GEN P, GEN U, ulong p, ulong pi)
     405              : {
     406            0 :   long i, lP = lg(P);
     407            0 :   GEN res = cgetg(lP,t_POL);
     408            0 :   res[1] = P[1];
     409            0 :   for(i=2; i<lP; i++) gel(res,i) = Flx_mul_pre(U,gel(P,i), p, pi);
     410            0 :   return FlxX_renormalize(res, lP);
     411              : }
     412              : 
     413              : GEN
     414            0 : FlxY_Flx_mul(GEN P, GEN U, ulong p)
     415            0 : { return FlxY_Flx_mul_pre(P, U, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
     416              : 
     417              : GEN
     418         7667 : FlxY_Flx_div_pre(GEN x, GEN y, ulong p, ulong pi)
     419              : {
     420              :   long i, l;
     421              :   GEN z;
     422         7667 :   if (degpol(y) == 0)
     423              :   {
     424         5678 :     ulong t = uel(y,2);
     425         5678 :     if (t == 1) return x;
     426            0 :     t = Fl_inv(t, p);
     427            0 :     z = cgetg_copy(x, &l); z[1] = x[1];
     428            0 :     for (i=2; i<l; i++) gel(z,i) = Flx_Fl_mul_pre(gel(x,i),t,p,pi);
     429              :   }
     430              :   else
     431              :   {
     432         1989 :     y = Flx_get_red_pre(y, p, pi);
     433         1989 :     z = cgetg_copy(x, &l); z[1] = x[1];
     434         3978 :     for (i=2; i<l; i++) gel(z,i) = Flx_div_pre(gel(x,i),y,p,pi);
     435              :   }
     436         1989 :   return z;
     437              : }
     438              : GEN
     439            0 : FlxY_Flx_div(GEN P, GEN U, ulong p)
     440            0 : { return FlxY_Flx_div_pre(P, U, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
     441              : 
     442              : GEN
     443     14263722 : FlxY_evalx_pre(GEN Q, ulong x, ulong p, ulong pi)
     444              : {
     445     14263722 :   long i, lb = lg(Q);
     446              :   GEN z;
     447     14263722 :   z = cgetg(lb,t_VECSMALL); z[1] = evalvarn(varn(Q));
     448    115619432 :   for (i=2; i<lb; i++) z[i] = Flx_eval_pre(gel(Q,i), x, p, pi);
     449     14263722 :   return Flx_renormalize(z, lb);
     450              : }
     451              : GEN
     452          238 : FlxY_evalx(GEN Q, ulong x, ulong p)
     453          238 : { return FlxY_evalx_pre(Q, x, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
     454              : 
     455              : GEN
     456            0 : FlxY_Flx_translate(GEN P, GEN c, ulong p)
     457              : {
     458            0 :   pari_sp av = avma;
     459            0 :   ulong pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
     460              :   GEN Q;
     461              :   long i, k, n;
     462              : 
     463            0 :   if (!signe(P) || gequal0(c)) return RgX_copy(P);
     464            0 :   Q = leafcopy(P); n = degpol(P);
     465            0 :   for (i=1; i<=n; i++)
     466              :   {
     467            0 :     for (k=n-i; k<n; k++)
     468            0 :       gel(Q,2+k) = Flx_add(gel(Q,2+k), Flx_mul_pre(gel(Q,2+k+1), c, p, pi), p);
     469            0 :     if (gc_needed(av,2))
     470              :     {
     471            0 :       if(DEBUGMEM>1)
     472            0 :         pari_warn(warnmem,"FlxY_Flx_translate, i = %ld/%ld", i,n);
     473            0 :       Q = gc_GEN(av, Q);
     474              :     }
     475              :   }
     476            0 :   return gc_GEN(av, Q);
     477              : }
     478              : 
     479              : /* allow pi = 0 */
     480              : GEN
     481     11326857 : FlxY_evalx_powers_pre(GEN pol, GEN ypowers, ulong p, ulong pi)
     482              : {
     483     11326857 :   long i, len = lg(pol);
     484     11326857 :   GEN res = cgetg(len, t_VECSMALL);
     485     11326857 :   res[1] = pol[1] & VARNBITS;
     486     38456970 :   for (i = 2; i < len; ++i)
     487     27130113 :     res[i] = Flx_eval_powers_pre(gel(pol, i), ypowers, p, pi);
     488     11326857 :   return Flx_renormalize(res, len);
     489              : }
     490              : 
     491              : /* allow pi = 0 */
     492              : ulong
     493      7591544 : FlxY_eval_powers_pre(GEN pol, GEN ypowers, GEN xpowers, ulong p, ulong pi)
     494              : {
     495      7591544 :   pari_sp av = avma;
     496      7591544 :   GEN t = FlxY_evalx_powers_pre(pol, ypowers, p, pi);
     497      7591544 :   return gc_ulong(av, Flx_eval_powers_pre(t, xpowers, p, pi));
     498              : }
     499              : 
     500              : GEN
     501       137237 : FlxY_FlxqV_evalx_pre(GEN P, GEN x, GEN T, ulong p, ulong pi)
     502              : {
     503       137237 :   long i, lP = lg(P);
     504       137237 :   GEN res = cgetg(lP,t_POL);
     505       137237 :   res[1] = P[1];
     506      1026715 :   for(i=2; i<lP; i++)
     507       889478 :     gel(res,i) = Flx_FlxqV_eval_pre(gel(P,i), x, T, p, pi);
     508       137237 :   return FlxX_renormalize(res, lP);
     509              : }
     510              : GEN
     511            0 : FlxY_FlxqV_evalx(GEN P, GEN x, GEN T, ulong p)
     512            0 : { return FlxY_FlxqV_evalx_pre(P, x, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
     513              : 
     514              : GEN
     515            0 : FlxY_Flxq_evalx_pre(GEN P, GEN x, GEN T, ulong p, ulong pi)
     516              : {
     517            0 :   pari_sp av = avma;
     518            0 :   long n = brent_kung_optpow(get_Flx_degree(T)-1,lgpol(P),1);
     519            0 :   GEN xp = Flxq_powers_pre(x, n, T, p, pi);
     520            0 :   return gc_upto(av, FlxY_FlxqV_evalx_pre(P, xp, T, p, pi));
     521              : }
     522              : GEN
     523            0 : FlxY_Flxq_evalx(GEN P, GEN x, GEN T, ulong p)
     524            0 : { return FlxY_Flxq_evalx_pre(P, x, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
     525              : 
     526              : GEN
     527        71643 : FlxX_shift(GEN a, long n, long vs)
     528              : {
     529        71643 :   long i, l = lg(a);
     530              :   GEN  b;
     531        71643 :   if (l == 2 || !n) return a;
     532        64649 :   l += n;
     533        64649 :   if (n < 0)
     534              :   {
     535        35785 :     if (l <= 2) return pol_0(varn(a));
     536        29415 :     b = cgetg(l, t_POL); b[1] = a[1];
     537        29415 :     a -= n;
     538       612756 :     for (i=2; i<l; i++) gel(b,i) = gel(a,i);
     539              :   } else {
     540        28864 :     b = cgetg(l, t_POL); b[1] = a[1];
     541        28864 :     a -= n; n += 2;
     542       507181 :     for (i=2; i<n; i++) gel(b,i) = pol0_Flx(vs);
     543       365846 :     for (   ; i<l; i++) gel(b,i) = gel(a,i);
     544              :   }
     545        58279 :   return b;
     546              : }
     547              : 
     548              : GEN
     549        13196 : FlxX_blocks(GEN P, long n, long m, long vs)
     550              : {
     551        13196 :   GEN z = cgetg(m+1,t_VEC);
     552        13196 :   long i,j, k=2, l = lg(P);
     553        39588 :   for(i=1; i<=m; i++)
     554              :   {
     555        26392 :     GEN zi = cgetg(n+2,t_POL);
     556        26392 :     zi[1] = P[1];
     557        26392 :     gel(z,i) = zi;
     558       160586 :     for(j=2; j<n+2; j++)
     559       134194 :       gel(zi, j) = k==l ? pol0_Flx(vs) : gel(P,k++);
     560        26392 :     zi = FlxX_renormalize(zi, n+2);
     561              :   }
     562        13196 :   return z;
     563              : }
     564              : 
     565              : static GEN
     566       281996 : FlxX_recipspec(GEN x, long l, long n, long vs)
     567              : {
     568              :   long i;
     569       281996 :   GEN z = cgetg(n+2,t_POL);
     570       281996 :   z[1] = 0; z += 2;
     571      8350838 :   for(i=0; i<l; i++)
     572      8068842 :     gel(z,n-i-1) = Flx_copy(gel(x,i));
     573       289060 :   for(   ; i<n; i++)
     574         7064 :     gel(z,n-i-1) = pol0_Flx(vs);
     575       281996 :   return FlxX_renormalize(z-2,n+2);
     576              : }
     577              : 
     578              : GEN
     579         2432 : FlxX_invLaplace(GEN x, ulong p)
     580              : {
     581         2432 :   long i, d = degpol(x);
     582              :   GEN y;
     583              :   ulong t;
     584         2432 :   if (d <= 1) return gcopy(x);
     585         2425 :   t = Fl_inv(factorial_Fl(d, p), p);
     586         2425 :   y = cgetg(d+3, t_POL);
     587         2425 :   y[1] = x[1];
     588        47686 :   for (i=d; i>=2; i--)
     589              :   {
     590        45261 :     gel(y,i+2) = Flx_Fl_mul(gel(x,i+2), t, p);
     591        45261 :     t = Fl_mul(t, i, p);
     592              :   }
     593         2425 :   gel(y,3) = Flx_copy(gel(x,3));
     594         2425 :   gel(y,2) = Flx_copy(gel(x,2));
     595         2425 :   return FlxX_renormalize(y, d+3);
     596              : }
     597              : 
     598              : GEN
     599         1216 : FlxX_Laplace(GEN x, ulong p)
     600              : {
     601         1216 :   long i, d = degpol(x);
     602         1216 :   ulong t = 1;
     603              :   GEN y;
     604         1216 :   if (d <= 1) return gcopy(x);
     605         1216 :   y = cgetg(d+3, t_POL);
     606         1216 :   y[1] = x[1];
     607         1216 :   gel(y,2) = Flx_copy(gel(x,2));
     608         1216 :   gel(y,3) = Flx_copy(gel(x,3));
     609        23850 :   for (i=2; i<=d; i++)
     610              :   {
     611        22634 :     t = Fl_mul(t, i%p, p);
     612        22634 :     gel(y,i+2) = Flx_Fl_mul(gel(x,i+2), t, p);
     613              :   }
     614         1216 :   return FlxX_renormalize(y, d+3);
     615              : }
     616              : 
     617              : /***********************************************************************/
     618              : /**                                                                   **/
     619              : /**                               FlxXV                               **/
     620              : /**                                                                   **/
     621              : /***********************************************************************/
     622              : 
     623              : GEN
     624            0 : FlxXC_sub(GEN x, GEN y, ulong p)
     625            0 : { pari_APPLY_same(FlxX_sub(gel(x, i), gel(y,i), p)) }
     626              : 
     627              : static GEN
     628       139112 : FlxXV_to_FlxM_lg(GEN x, long m, long n, long sv)
     629              : {
     630              :   long i;
     631       139112 :   GEN y = cgetg(n+1, t_MAT);
     632       467243 :   for (i=1; i<=n; i++) gel(y,i) = FlxX_to_FlxC(gel(x,i), m, sv);
     633       139112 :   return y;
     634              : }
     635              : 
     636              : GEN
     637            0 : FlxXV_to_FlxM(GEN v, long n, long sv)
     638            0 : { return FlxXV_to_FlxM_lg(v, n, lg(v)-1, sv); }
     639              : 
     640              : GEN
     641        12516 : FlxXC_to_ZXXC(GEN x)
     642        62621 : { pari_APPLY_type(t_COL, FlxX_to_ZXX(gel(x,i))) }
     643              : 
     644              : GEN
     645            0 : FlxXM_to_ZXXM(GEN x)
     646            0 : { pari_APPLY_same(FlxXC_to_ZXXC(gel(x,i))) }
     647              : 
     648              : /***********************************************************************/
     649              : /**                                                                   **/
     650              : /**                               FlxqX                               **/
     651              : /**                                                                   **/
     652              : /***********************************************************************/
     653              : 
     654              : static GEN
     655      3700283 : get_FlxqX_red(GEN T, GEN *B)
     656              : {
     657      3700283 :   if (typ(T)!=t_VEC) { *B=NULL; return T; }
     658       170844 :   *B = gel(T,1); return gel(T,2);
     659              : }
     660              : 
     661              : GEN
     662       166250 : RgX_to_FlxqX(GEN x, GEN T, ulong p)
     663              : {
     664       166250 :   long i, l = lg(x);
     665       166250 :   GEN z = cgetg(l, t_POL); z[1] = x[1];
     666      2440082 :   for (i = 2; i < l; i++)
     667      2273832 :     gel(z,i) = Rg_to_Flxq(gel(x,i), T, p);
     668       166250 :   return FlxX_renormalize(z, l);
     669              : }
     670              : 
     671              : /* FlxqX are t_POL with Flxq coefficients.
     672              :  * Normally the variable ordering should be respected.*/
     673              : 
     674              : GEN
     675          592 : random_FlxqX(long d1, long v, GEN T, ulong p)
     676              : {
     677          592 :   long dT = get_Flx_degree(T), vT = get_Flx_var(T);
     678          592 :   long i, d = d1+2;
     679          592 :   GEN y = cgetg(d,t_POL); y[1] = evalsigne(1) | evalvarn(v);
     680         3140 :   for (i=2; i<d; i++) gel(y,i) = random_Flx(dT, vT, p);
     681          592 :   return FlxX_renormalize(y,d);
     682              : }
     683              : 
     684              : /*Not stack clean*/
     685              : GEN
     686      2450652 : Kronecker_to_FlxqX_pre(GEN z, GEN T, ulong p, ulong pi)
     687              : {
     688      2450652 :   long i,j,lx,l, N = (get_Flx_degree(T)<<1) + 1;
     689      2450652 :   GEN x, t = cgetg(N,t_VECSMALL);
     690      2450652 :   t[1] = get_Flx_var(T);
     691      2450652 :   l = lg(z); lx = (l-2) / (N-2);
     692      2450652 :   x = cgetg(lx+3,t_POL);
     693      2450652 :   x[1] = z[1];
     694     38267377 :   for (i=2; i<lx+2; i++)
     695              :   {
     696    421516380 :     for (j=2; j<N; j++) t[j] = z[j];
     697     35816725 :     z += (N-2);
     698     35816725 :     gel(x,i) = Flx_rem_pre(Flx_renormalize(t,N), T,p,pi);
     699              :   }
     700      2450652 :   N = (l-2) % (N-2) + 2;
     701      7645340 :   for (j=2; j<N; j++) t[j] = z[j];
     702      2450652 :   gel(x,i) = Flx_rem_pre(Flx_renormalize(t,N), T,p,pi);
     703      2450652 :   return FlxX_renormalize(x, i+1);
     704              : }
     705              : GEN
     706            0 : Kronecker_to_FlxqX(GEN z, GEN T, ulong p)
     707            0 : { return Kronecker_to_FlxqX_pre(z, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
     708              : 
     709              : GEN
     710      1294113 : FlxqX_red_pre(GEN z, GEN T, ulong p, ulong pi)
     711              : {
     712              :   GEN res;
     713      1294113 :   long i, l = lg(z);
     714      1294113 :   res = cgetg(l,t_POL); res[1] = z[1];
     715     16419539 :   for(i=2;i<l;i++) gel(res,i) = Flx_rem_pre(gel(z,i),T,p,pi);
     716      1294113 :   return FlxX_renormalize(res,l);
     717              : }
     718              : GEN
     719            0 : FlxqX_red(GEN z, GEN T, ulong p)
     720            0 : { return FlxqX_red_pre(z, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
     721              : 
     722              : static GEN
     723       357688 : FlxqX_mulspec(GEN x, GEN y, GEN T, ulong p, ulong pi, long lx, long ly)
     724              : {
     725       357688 :   pari_sp av = avma;
     726              :   GEN z,kx,ky;
     727       357688 :   long dT =  get_Flx_degree(T);
     728       357688 :   kx= zxX_to_Kronecker_spec(x,lx,dT);
     729       357688 :   ky= zxX_to_Kronecker_spec(y,ly,dT);
     730       357688 :   z = Flx_mul_pre(ky, kx, p, pi);
     731       357688 :   z = Kronecker_to_FlxqX_pre(z,T,p,pi);
     732       357688 :   return gc_upto(av, z);
     733              : }
     734              : 
     735              : GEN
     736      1729318 : FlxqX_mul_pre(GEN x, GEN y, GEN T, ulong p, ulong pi)
     737              : {
     738      1729318 :   pari_sp av = avma;
     739      1729318 :   GEN z, kx, ky, Tm = get_Flx_mod(T);
     740      1729318 :   kx= zxX_to_Kronecker(x, Tm);
     741      1729318 :   ky= zxX_to_Kronecker(y, Tm);
     742      1729318 :   z = Flx_mul_pre(ky, kx, p, pi);
     743      1729318 :   z = Kronecker_to_FlxqX_pre(z, T, p, pi);
     744      1729318 :   return gc_upto(av, z);
     745              : }
     746              : GEN
     747        63936 : FlxqX_mul(GEN x, GEN y, GEN T, ulong p)
     748        63936 : { return FlxqX_mul_pre(x, y, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
     749              : 
     750              : GEN
     751       363646 : FlxqX_sqr_pre(GEN x, GEN T, ulong p, ulong pi)
     752              : {
     753       363646 :   pari_sp av = avma;
     754              :   GEN z,kx;
     755       363646 :   kx= zxX_to_Kronecker(x,get_Flx_mod(T));
     756       363646 :   z = Flx_sqr_pre(kx, p, pi);
     757       363646 :   z = Kronecker_to_FlxqX_pre(z,T,p,pi);
     758       363646 :   return gc_upto(av, z);
     759              : }
     760              : GEN
     761         1218 : FlxqX_sqr(GEN x, GEN T, ulong p)
     762         1218 : { return FlxqX_sqr_pre(x, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
     763              : 
     764              : GEN
     765       155542 : FlxqX_Flxq_mul_pre(GEN P, GEN U, GEN T, ulong p, ulong pi)
     766              : {
     767       155542 :   long i, lP = lg(P);
     768       155542 :   GEN res = cgetg(lP,t_POL);
     769       155542 :   res[1] = P[1];
     770       555675 :   for(i=2; i<lP; i++) gel(res,i) = Flxq_mul_pre(U,gel(P,i), T,p,pi);
     771       155542 :   return FlxX_renormalize(res, lP);
     772              : }
     773              : GEN
     774            0 : FlxqX_Flxq_mul(GEN P, GEN U, GEN T, ulong p)
     775            0 : { return FlxqX_Flxq_mul_pre(P, U, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
     776              : 
     777              : GEN
     778       673076 : FlxqX_Flxq_mul_to_monic_pre(GEN P, GEN U, GEN T, ulong p, ulong pi)
     779              : {
     780       673076 :   long i, lP = lg(P);
     781       673076 :   GEN res = cgetg(lP,t_POL);
     782       673076 :   res[1] = P[1];
     783      3635265 :   for(i=2; i<lP-1; i++) gel(res,i) = Flxq_mul_pre(U,gel(P,i), T,p,pi);
     784       673076 :   gel(res,lP-1) = pol1_Flx(get_Flx_var(T));
     785       673076 :   return FlxX_renormalize(res, lP);
     786              : }
     787              : GEN
     788            0 : FlxqX_Flxq_mul_to_monic(GEN P, GEN U, GEN T, ulong p)
     789              : {
     790            0 :   ulong pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
     791            0 :   return FlxqX_Flxq_mul_to_monic_pre(P, U, T, p, pi);
     792              : }
     793              : 
     794              : GEN
     795       190026 : FlxqX_normalize_pre(GEN z, GEN T, ulong p, ulong pi)
     796              : {
     797       190026 :   GEN p1 = leading_coeff(z);
     798       190026 :   if (!lgpol(z) || (!degpol(p1) && p1[1] == 1)) return z;
     799       190005 :   return FlxqX_Flxq_mul_to_monic_pre(z, Flxq_inv_pre(p1,T,p,pi), T,p,pi);
     800              : }
     801              : GEN
     802          133 : FlxqX_normalize(GEN z, GEN T, ulong p)
     803          133 : { return FlxqX_normalize_pre(z, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
     804              : 
     805              : struct _FlxqXQ {
     806              :   GEN T, S;
     807              :   ulong p, pi;
     808              : };
     809              : 
     810              : static GEN
     811       538511 : _FlxqX_mul(void *data,GEN a,GEN b)
     812              : {
     813       538511 :   struct _FlxqXQ *d=(struct _FlxqXQ*)data;
     814       538511 :   return FlxqX_mul_pre(a,b,d->T,d->p,d->pi);
     815              : }
     816              : static GEN
     817        10339 : _FlxqX_sqr(void *data,GEN a)
     818              : {
     819        10339 :   struct _FlxqXQ *d=(struct _FlxqXQ*)data;
     820        10339 :   return FlxqX_sqr_pre(a,d->T,d->p,d->pi);
     821              : }
     822              : 
     823              : GEN
     824        10262 : FlxqX_powu_pre(GEN V, ulong n, GEN T, ulong p, ulong pi)
     825              : {
     826        10262 :   struct _FlxqXQ d; d.p = p; d.pi = pi; d.T = T;
     827        10262 :   return gen_powu(V, n, (void*)&d, &_FlxqX_sqr, &_FlxqX_mul);
     828              : }
     829              : GEN
     830            0 : FlxqX_powu(GEN V, ulong n, GEN T, ulong p)
     831            0 : { return FlxqX_powu_pre(V, n, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
     832              : 
     833              : /* x and y in Z[Y][X]. Assume T irreducible mod p */
     834              : static GEN
     835      3219762 : FlxqX_divrem_basecase(GEN x, GEN y, GEN T, ulong p, ulong pi, GEN *pr)
     836              : {
     837      3219762 :   long vx = varn(x), dx = degpol(x), dy = degpol(y), dz, i, j, sx, lr;
     838              :   pari_sp av0, av;
     839              :   GEN z, p1, rem, lead;
     840              : 
     841      3219762 :   if (!signe(y)) pari_err_INV("FlxqX_divrem",y);
     842      3219762 :   if (dx < dy)
     843              :   {
     844        21653 :     if (pr)
     845              :     {
     846        21400 :       av0 = avma; x = FlxqX_red_pre(x, T, p, pi);
     847        21400 :       if (pr == ONLY_DIVIDES) { set_avma(av0); return signe(x)? NULL: pol_0(vx); }
     848        21400 :       if (pr == ONLY_REM) return x;
     849        21400 :       *pr = x;
     850              :     }
     851        21653 :     return pol_0(vx);
     852              :   }
     853      3198109 :   lead = leading_coeff(y);
     854      3198109 :   if (!dy) /* y is constant */
     855              :   {
     856       333560 :     if (pr && pr != ONLY_DIVIDES)
     857              :     {
     858       328871 :       if (pr == ONLY_REM) return pol_0(vx);
     859       134239 :       *pr = pol_0(vx);
     860              :     }
     861       138928 :     if (Flx_equal1(lead)) return gcopy(x);
     862       134680 :     av0 = avma; x = FlxqX_Flxq_mul_pre(x,Flxq_inv(lead,T,p),T,p,pi);
     863       134680 :     return gc_upto(av0,x);
     864              :   }
     865      2864549 :   av0 = avma; dz = dx-dy;
     866      2864549 :   lead = Flx_equal1(lead)? NULL: gclone(Flxq_inv_pre(lead,T,p,pi));
     867      2864549 :   set_avma(av0);
     868      2864549 :   z = cgetg(dz+3,t_POL); z[1] = x[1];
     869      2864549 :   x += 2; y += 2; z += 2;
     870              : 
     871      2864549 :   p1 = gel(x,dx); av = avma;
     872      2864549 :   gel(z,dz) = lead? gc_upto(av, Flxq_mul_pre(p1,lead, T,p,pi)): gcopy(p1);
     873      6581331 :   for (i=dx-1; i>=dy; i--)
     874              :   {
     875      3716782 :     av = avma; p1 = gel(x,i);
     876     12024688 :     for (j=i-dy+1; j<=i && j<=dz; j++)
     877      8307906 :       p1 = Flx_sub(p1, Flx_mul_pre(gel(z,j),gel(y,i-j),p,pi),p);
     878      3716782 :     if (lead) p1 = Flx_mul_pre(p1, lead,p,pi);
     879      3716782 :     gel(z,i-dy) = gc_leaf(av, Flx_rem_pre(p1,T,p,pi));
     880              :   }
     881      2864549 :   if (!pr) { guncloneNULL(lead); return z-2; }
     882              : 
     883      2670003 :   rem = (GEN)avma; av = (pari_sp)new_chunk(dx+3);
     884      2997699 :   for (sx=0; ; i--)
     885              :   {
     886      2997699 :     p1 = gel(x,i);
     887      8857879 :     for (j=0; j<=i && j<=dz; j++)
     888      5860180 :       p1 = Flx_sub(p1, Flx_mul_pre(gel(z,j),gel(y,i-j),p,pi),p);
     889      2997699 :     p1 = Flx_rem_pre(p1, T,p,pi); if (lgpol(p1)) { sx = 1; break; }
     890       402680 :     if (!i) break;
     891       327696 :     set_avma(av);
     892              :   }
     893      2670003 :   if (pr == ONLY_DIVIDES)
     894              :   {
     895            0 :     guncloneNULL(lead);
     896            0 :     if (sx) return gc_NULL(av0);
     897            0 :     return gc_const((pari_sp)rem, z-2);
     898              :   }
     899      2670003 :   lr=i+3; rem -= lr; av = (pari_sp)rem;
     900      2670003 :   rem[0] = evaltyp(t_POL) | _evallg(lr);
     901      2670003 :   rem[1] = z[-1];
     902      2670003 :   rem += 2; gel(rem,i) = gc_leaf(av, p1);
     903     17798479 :   for (i--; i>=0; i--)
     904              :   {
     905     15128476 :     av = avma; p1 = gel(x,i);
     906     49009065 :     for (j=0; j<=i && j<=dz; j++)
     907     33880589 :       p1 = Flx_sub(p1, Flx_mul_pre(gel(z,j),gel(y,i-j),p,pi), p);
     908     15128476 :     gel(rem,i) = gc_leaf(av, Flx_rem_pre(p1, T,p,pi));
     909              :   }
     910      2670003 :   rem -= 2;
     911      2670003 :   guncloneNULL(lead);
     912      2670003 :   if (!sx) (void)FlxX_renormalize(rem, lr);
     913      2670003 :   if (pr == ONLY_REM) return gc_upto(av0,rem);
     914      1227146 :   *pr = rem; return z-2;
     915              : }
     916              : 
     917              : static GEN
     918         1391 : FlxqX_invBarrett_basecase(GEN T, GEN Q, ulong p, ulong pi)
     919              : {
     920         1391 :   long i, l=lg(T)-1, lr = l-1, k;
     921         1391 :   long sv=Q[1];
     922         1391 :   GEN r=cgetg(lr,t_POL); r[1]=T[1];
     923         1391 :   gel(r,2) = pol1_Flx(sv);
     924        15941 :   for (i=3;i<lr;i++)
     925              :   {
     926        14550 :     pari_sp ltop=avma;
     927        14550 :     GEN u = Flx_neg(gel(T,l-i+2),p);
     928       105265 :     for (k=3;k<i;k++)
     929        90715 :       u = Flx_sub(u, Flxq_mul_pre(gel(T,l-i+k), gel(r,k), Q, p, pi), p);
     930        14550 :     gel(r,i) = gc_upto(ltop, u);
     931              :   }
     932         1391 :   r = FlxX_renormalize(r,lr);
     933         1391 :   return r;
     934              : }
     935              : 
     936              : /* Return new lgpol */
     937              : static long
     938       400717 : FlxX_lgrenormalizespec(GEN x, long lx)
     939              : {
     940              :   long i;
     941       485136 :   for (i = lx-1; i>=0; i--)
     942       485136 :     if (lgpol(gel(x,i))) break;
     943       400717 :   return i+1;
     944              : }
     945              : 
     946              : static GEN
     947         8354 : FlxqX_invBarrett_Newton(GEN S, GEN T, ulong p, ulong pi)
     948              : {
     949         8354 :   pari_sp av = avma;
     950         8354 :   long nold, lx, lz, lq, l = degpol(S), i, lQ;
     951         8354 :   GEN q, y, z, x = cgetg(l+2, t_POL) + 2;
     952         8354 :   long dT = get_Flx_degree(T), vT = get_Flx_var(T);
     953         8354 :   ulong mask = quadratic_prec_mask(l-2); /* assume l > 2 */
     954       374914 :   for (i=0;i<l;i++) gel(x,i) = pol0_Flx(vT);
     955         8354 :   q = FlxX_recipspec(S+2,l+1,l+1,dT);
     956         8354 :   lQ = lgpol(q); q+=2;
     957              :   /* We work on _spec_ FlxX's, all the l[xzq] below are lgpol's */
     958              : 
     959              :   /* initialize */
     960         8354 :   gel(x,0) = Flxq_inv_pre(gel(q,0),T, p, pi);
     961         8354 :   if (lQ>1 && degpol(gel(q,1)) >= dT)
     962            0 :     gel(q,1) = Flx_rem_pre(gel(q,1), T, p, pi);
     963         8354 :   if (lQ>1 && lgpol(gel(q,1)))
     964         5635 :   {
     965         5635 :     GEN u = gel(q, 1);
     966         5635 :     if (!Flx_equal1(gel(x,0)))
     967            7 :       u = Flxq_mul_pre(u, Flxq_sqr_pre(gel(x,0), T,p,pi), T,p,pi);
     968         5635 :     gel(x,1) = Flx_neg(u, p); lx = 2;
     969              :   }
     970              :   else
     971         2719 :     lx = 1;
     972         8354 :   nold = 1;
     973        54795 :   for (; mask > 1; )
     974              :   { /* set x -= x(x*q - 1) + O(t^(nnew + 1)), knowing x*q = 1 + O(t^(nold+1)) */
     975        46441 :     long i, lnew, nnew = nold << 1;
     976              : 
     977        46441 :     if (mask & 1) nnew--;
     978        46441 :     mask >>= 1;
     979              : 
     980        46441 :     lnew = nnew + 1;
     981        46441 :     lq = FlxX_lgrenormalizespec(q, minss(lQ,lnew));
     982        46441 :     z = FlxqX_mulspec(x, q, T,p,pi, lx, lq); /* FIXME: high product */
     983        46441 :     lz = lgpol(z); if (lz > lnew) lz = lnew;
     984        46441 :     z += 2;
     985              :     /* subtract 1 [=>first nold words are 0]: renormalize so that z(0) != 0 */
     986        99660 :     for (i = nold; i < lz; i++) if (lgpol(gel(z,i))) break;
     987        46441 :     nold = nnew;
     988        46441 :     if (i >= lz) continue; /* z-1 = 0(t^(nnew + 1)) */
     989              : 
     990              :     /* z + i represents (x*q - 1) / t^i */
     991        45482 :     lz = FlxX_lgrenormalizespec (z+i, lz-i);
     992        45482 :     z = FlxqX_mulspec(x, z+i, T,p,pi, lx, lz); /* FIXME: low product */
     993        45482 :     lz = lgpol(z); z += 2;
     994        45482 :     if (lz > lnew-i) lz = FlxX_lgrenormalizespec(z, lnew-i);
     995              : 
     996        45482 :     lx = lz+ i;
     997        45482 :     y  = x + i; /* x -= z * t^i, in place */
     998       374886 :     for (i = 0; i < lz; i++) gel(y,i) = Flx_neg(gel(z,i), p);
     999              :   }
    1000         8354 :   x -= 2; setlg(x, lx + 2); x[1] = S[1];
    1001         8354 :   return gc_GEN(av, x);
    1002              : }
    1003              : 
    1004              : GEN
    1005         9745 : FlxqX_invBarrett_pre(GEN T, GEN Q, ulong p, ulong pi)
    1006              : {
    1007         9745 :   pari_sp ltop=avma;
    1008         9745 :   long l=lg(T), v = varn(T);
    1009              :   GEN r;
    1010         9745 :   GEN c = gel(T,l-1);
    1011         9745 :   if (l<5) return pol_0(v);
    1012         9745 :   if (l<=FlxqX_INVBARRETT_LIMIT)
    1013              :   {
    1014         1391 :     if (!Flx_equal1(c))
    1015              :     {
    1016            0 :       GEN ci = Flxq_inv_pre(c,Q,p,pi);
    1017            0 :       T = FlxqX_Flxq_mul_pre(T, ci, Q, p, pi);
    1018            0 :       r = FlxqX_invBarrett_basecase(T,Q,p,pi);
    1019            0 :       r = FlxqX_Flxq_mul_pre(r,ci,Q,p,pi);
    1020              :     } else
    1021         1391 :       r = FlxqX_invBarrett_basecase(T,Q,p,pi);
    1022              :   } else
    1023         8354 :     r = FlxqX_invBarrett_Newton(T,Q,p,pi);
    1024         9745 :   return gc_upto(ltop, r);
    1025              : }
    1026              : GEN
    1027           62 : FlxqX_invBarrett(GEN T, GEN Q, ulong p)
    1028           62 : { return FlxqX_invBarrett_pre(T, Q, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    1029              : 
    1030              : GEN
    1031       495992 : FlxqX_get_red_pre(GEN S, GEN T, ulong p, ulong pi)
    1032              : {
    1033       495992 :   if (typ(S)==t_POL && lg(S)>FlxqX_BARRETT_LIMIT)
    1034         8221 :     retmkvec2(FlxqX_invBarrett_pre(S, T, p, pi), S);
    1035       487771 :   return S;
    1036              : }
    1037              : GEN
    1038          336 : FlxqX_get_red(GEN S, GEN T, ulong p)
    1039              : {
    1040          336 :   if (typ(S)==t_POL && lg(S)>FlxqX_BARRETT_LIMIT)
    1041           62 :     retmkvec2(FlxqX_invBarrett(S, T, p), S);
    1042          274 :   return S;
    1043              : }
    1044              : 
    1045              : /* Compute x mod S where 2 <= degpol(S) <= l+1 <= 2*(degpol(S)-1)
    1046              :  *  * and mg is the Barrett inverse of S. */
    1047              : static GEN
    1048       133019 : FlxqX_divrem_Barrettspec(GEN x, long l, GEN mg, GEN S, GEN T, ulong p,
    1049              :   ulong pi, GEN *pr)
    1050              : {
    1051              :   GEN q, r;
    1052       133019 :   long lt = degpol(S); /*We discard the leading term*/
    1053              :   long ld, lm, lT, lmg;
    1054       133019 :   ld = l-lt;
    1055       133019 :   lm = minss(ld, lgpol(mg));
    1056       133019 :   lT  = FlxX_lgrenormalizespec(S+2,lt);
    1057       133019 :   lmg = FlxX_lgrenormalizespec(mg+2,lm);
    1058       133019 :   q = FlxX_recipspec(x+lt,ld,ld,0);               /* = rec(x)     lq<=ld*/
    1059       133019 :   q = FlxqX_mulspec(q+2,mg+2,T,p,pi,lgpol(q),lmg); /* = rec(x)*mg lq<=ld+lm*/
    1060       133019 :   q = FlxX_recipspec(q+2,minss(ld,lgpol(q)),ld,0); /* = rec(rec(x)*mg) lq<=ld*/
    1061       133019 :   if (!pr) return q;
    1062       132746 :   r = FlxqX_mulspec(q+2,S+2,T,p,pi,lgpol(q),lT);  /* = q*pol   lr<=ld+lt*/
    1063       132746 :   r = FlxX_subspec(x,r+2,p,lt,minss(lt,lgpol(r)));/* = x - r   lr<=lt */
    1064       132746 :   if (pr == ONLY_REM) return r;
    1065         7934 :   *pr = r; return q;
    1066              : }
    1067              : 
    1068              : static GEN
    1069       125966 : FlxqX_divrem_Barrett(GEN x, GEN mg, GEN S, GEN T, ulong p, ulong pi, GEN *pr)
    1070              : {
    1071       125966 :   GEN q = NULL, r = FlxqX_red_pre(x, T, p, pi);
    1072       125966 :   long l = lgpol(r), lt = degpol(S), lm = 2*lt-1, v = varn(S);
    1073              :   long i;
    1074       125966 :   if (l <= lt)
    1075              :   {
    1076            0 :     if (pr == ONLY_REM) return r;
    1077            0 :     if (pr == ONLY_DIVIDES) return signe(r)? NULL: pol_0(v);
    1078            0 :     if (pr) *pr = r;
    1079            0 :     return pol_0(v);
    1080              :   }
    1081       125966 :   if (lt <= 1)
    1082            0 :     return FlxqX_divrem_basecase(x,S,T,p,pi,pr);
    1083       125966 :   if (pr != ONLY_REM && l>lm)
    1084              :   {
    1085          846 :     long vT = get_Flx_var(T);
    1086          846 :     q = cgetg(l-lt+2, t_POL); q[1] = S[1];
    1087        61868 :     for (i=0;i<l-lt;i++) gel(q+2,i) = pol0_Flx(vT);
    1088              :   }
    1089       133101 :   while (l>lm)
    1090              :   {
    1091         7135 :     GEN zr, zq = FlxqX_divrem_Barrettspec(r+2+l-lm,lm,mg,S,T,p,pi,&zr);
    1092         7135 :     long lz = lgpol(zr);
    1093         7135 :     if (pr != ONLY_REM)
    1094              :     {
    1095         2746 :       long lq = lgpol(zq);
    1096        55408 :       for(i=0; i<lq; i++) gel(q+2+l-lm,i) = gel(zq,2+i);
    1097              :     }
    1098        77270 :     for(i=0; i<lz; i++) gel(r+2+l-lm,i) = gel(zr,2+i);
    1099         7135 :     l = l-lm+lz;
    1100              :   }
    1101       125966 :   if (pr == ONLY_REM)
    1102              :   {
    1103       124812 :     if (l > lt)
    1104       124812 :       r = FlxqX_divrem_Barrettspec(r+2,l,mg,S,T,p,pi,ONLY_REM);
    1105              :     else
    1106            0 :       r = FlxX_renormalize(r, l+2);
    1107       124812 :     setvarn(r, v); return r;
    1108              :   }
    1109         1154 :   if (l > lt)
    1110              :   {
    1111         1072 :     GEN zq = FlxqX_divrem_Barrettspec(r+2,l,mg,S,T,p,pi,pr? &r: NULL);
    1112         1072 :     if (!q) q = zq;
    1113              :     else
    1114              :     {
    1115          764 :       long lq = lgpol(zq);
    1116         6540 :       for(i=0; i<lq; i++) gel(q+2,i) = gel(zq,2+i);
    1117              :     }
    1118              :   }
    1119           82 :   else if (pr)
    1120           82 :     r = FlxX_renormalize(r, l+2);
    1121         1154 :   setvarn(q, v); q = FlxX_renormalize(q, lg(q));
    1122         1154 :   if (pr == ONLY_DIVIDES) return signe(r)? NULL: q;
    1123         1154 :   if (pr) { setvarn(r, v); *pr = r; }
    1124         1154 :   return q;
    1125              : }
    1126              : 
    1127              : GEN
    1128      1583427 : FlxqX_divrem_pre(GEN x, GEN S, GEN T, ulong p, ulong pi, GEN *pr)
    1129              : {
    1130              :   GEN B, y;
    1131              :   long dy, dx, d;
    1132      1583427 :   if (pr==ONLY_REM) return FlxqX_rem_pre(x, S, T, p, pi);
    1133      1583427 :   y = get_FlxqX_red(S, &B);
    1134      1583427 :   dy = degpol(y); dx = degpol(x); d = dx-dy;
    1135      1583427 :   if (!B && d+3 < FlxqX_DIVREM_BARRETT_LIMIT)
    1136      1582273 :     return FlxqX_divrem_basecase(x,y,T,p,pi,pr);
    1137              :   else
    1138              :   {
    1139         1154 :     pari_sp av = avma;
    1140         1154 :     GEN mg = B? B: FlxqX_invBarrett_pre(y, T, p, pi);
    1141         1154 :     GEN q = FlxqX_divrem_Barrett(x,mg,y,T,p,pi,pr);
    1142         1154 :     if (!q) return gc_NULL(av);
    1143         1154 :     if (!pr || pr==ONLY_DIVIDES) return gc_GEN(av, q);
    1144          881 :     return gc_all(av, 2, &q, pr);
    1145              :   }
    1146              : }
    1147              : GEN
    1148      1078751 : FlxqX_divrem(GEN x, GEN S, GEN T, ulong p, GEN *pr)
    1149              : {
    1150      1078751 :   ulong pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
    1151      1078751 :   return FlxqX_divrem_pre(x, S, T, p, pi, pr);
    1152              : }
    1153              : 
    1154              : GEN
    1155      2116348 : FlxqX_rem_pre(GEN x, GEN S, GEN T, ulong p, ulong pi)
    1156              : {
    1157      2116348 :   GEN B, y = get_FlxqX_red(S, &B);
    1158      2116348 :   long dy = degpol(y), dx = degpol(x), d = dx-dy;
    1159      2116348 :   if (d < 0) return FlxqX_red_pre(x, T, p, pi);
    1160      1762301 :   if (!B && d+3 < FlxqX_REM_BARRETT_LIMIT)
    1161      1637489 :     return FlxqX_divrem_basecase(x,y, T, p, pi, ONLY_REM);
    1162              :   else
    1163              :   {
    1164       124812 :     pari_sp av=avma;
    1165       124812 :     GEN mg = B? B: FlxqX_invBarrett_pre(y, T, p, pi);
    1166       124812 :     GEN r = FlxqX_divrem_Barrett(x, mg, y, T, p, pi, ONLY_REM);
    1167       124812 :     return gc_upto(av, r);
    1168              :   }
    1169              : }
    1170              : GEN
    1171         5109 : FlxqX_rem(GEN x, GEN S, GEN T, ulong p)
    1172         5109 : { return FlxqX_rem_pre(x, S, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    1173              : 
    1174              : /* x + y*z mod p */
    1175              : INLINE GEN
    1176       103796 : Flxq_addmul_pre(GEN x, GEN y, GEN z, GEN T, ulong p, ulong pi)
    1177              : {
    1178              :   pari_sp av;
    1179       103796 :   if (!lgpol(y) || !lgpol(z)) return Flx_rem_pre(x, T, p, pi);
    1180       102265 :   if (!lgpol(x)) return Flxq_mul_pre(z, y, T, p, pi);
    1181       102161 :   av = avma;
    1182       102161 :   return gc_upto(av, Flx_add(x, Flxq_mul_pre(y, z, T, p, pi), p));
    1183              : }
    1184              : 
    1185              : GEN
    1186        51898 : FlxqX_div_by_X_x_pre(GEN a, GEN x, GEN T, ulong p, ulong pi, GEN *r)
    1187              : {
    1188        51898 :   long l = lg(a), i;
    1189              :   GEN z;
    1190        51898 :   if (l <= 3)
    1191              :   {
    1192            0 :     if (r) *r = l == 2? pol0_Flx(get_Flx_var(T)): Flx_copy(gel(a,2));
    1193            0 :     return pol_0(varn(a));
    1194              :   }
    1195        51898 :   l--; z = cgetg(l, t_POL); z[1] = a[1];
    1196        51898 :   gel(z, l-1) = gel(a,l);
    1197       155694 :   for (i=l-2; i>1; i--) /* z[i] = a[i+1] + x*z[i+1] */
    1198       103796 :     gel(z, i) = Flxq_addmul_pre(gel(a,i+1), x, gel(z,i+1), T, p, pi);
    1199        51898 :   if (r) *r = Flxq_addmul_pre(gel(a,2), x, gel(z,2), T, p, pi);
    1200        51898 :   return z;
    1201              : }
    1202              : 
    1203              : GEN
    1204        51898 : FlxqX_div_by_X_x(GEN a, GEN x, GEN T, ulong p, GEN *r)
    1205        51898 : { return FlxqX_div_by_X_x_pre(a, x, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p), r); }
    1206              : 
    1207              : static GEN
    1208        13562 : FlxqX_addmulmul(GEN u, GEN v, GEN x, GEN y, GEN T, ulong p, ulong pi)
    1209              : {
    1210        13562 :   return FlxX_add(FlxqX_mul_pre(u, x, T, p, pi),
    1211              :                   FlxqX_mul_pre(v, y, T, p, pi), p);
    1212              : }
    1213              : 
    1214              : static GEN
    1215         6626 : FlxqXM_FlxqX_mul2(GEN M, GEN x, GEN y, GEN T, ulong p, ulong pi)
    1216              : {
    1217         6626 :   GEN res = cgetg(3, t_COL);
    1218         6626 :   gel(res, 1) = FlxqX_addmulmul(gcoeff(M,1,1), gcoeff(M,1,2), x, y, T, p, pi);
    1219         6626 :   gel(res, 2) = FlxqX_addmulmul(gcoeff(M,2,1), gcoeff(M,2,2), x, y, T, p, pi);
    1220         6626 :   return res;
    1221              : }
    1222              : 
    1223              : static GEN
    1224         3276 : FlxqXM_mul2(GEN A, GEN B, GEN T, ulong p, ulong pi)
    1225              : {
    1226         3276 :   GEN A11=gcoeff(A,1,1),A12=gcoeff(A,1,2), B11=gcoeff(B,1,1),B12=gcoeff(B,1,2);
    1227         3276 :   GEN A21=gcoeff(A,2,1),A22=gcoeff(A,2,2), B21=gcoeff(B,2,1),B22=gcoeff(B,2,2);
    1228         3276 :   GEN M1 = FlxqX_mul_pre(FlxX_add(A11,A22, p), FlxX_add(B11,B22, p), T, p, pi);
    1229         3276 :   GEN M2 = FlxqX_mul_pre(FlxX_add(A21,A22, p), B11, T, p, pi);
    1230         3276 :   GEN M3 = FlxqX_mul_pre(A11, FlxX_sub(B12,B22, p), T, p, pi);
    1231         3276 :   GEN M4 = FlxqX_mul_pre(A22, FlxX_sub(B21,B11, p), T, p, pi);
    1232         3276 :   GEN M5 = FlxqX_mul_pre(FlxX_add(A11,A12, p), B22, T, p, pi);
    1233         3276 :   GEN M6 = FlxqX_mul_pre(FlxX_sub(A21,A11, p), FlxX_add(B11,B12, p), T, p, pi);
    1234         3276 :   GEN M7 = FlxqX_mul_pre(FlxX_sub(A12,A22, p), FlxX_add(B21,B22, p), T, p, pi);
    1235         3276 :   GEN T1 = FlxX_add(M1,M4, p), T2 = FlxX_sub(M7,M5, p);
    1236         3276 :   GEN T3 = FlxX_sub(M1,M2, p), T4 = FlxX_add(M3,M6, p);
    1237         3276 :   retmkmat22(FlxX_add(T1,T2, p), FlxX_add(M3,M5, p),
    1238              :              FlxX_add(M2,M4, p), FlxX_add(T3,T4, p));
    1239              : }
    1240              : 
    1241              : /* Return [0,1;1,-q]*M */
    1242              : static GEN
    1243         3276 : FlxqX_FlxqXM_qmul(GEN q, GEN M, GEN T, ulong p, ulong pi)
    1244              : {
    1245         3276 :   GEN u = FlxqX_mul_pre(gcoeff(M,2,1), q, T,p,pi);
    1246         3276 :   GEN v = FlxqX_mul_pre(gcoeff(M,2,2), q, T,p,pi);
    1247         3276 :   retmkmat22(gcoeff(M,2,1), gcoeff(M,2,2),
    1248              :     FlxX_sub(gcoeff(M,1,1), u, p), FlxX_sub(gcoeff(M,1,2), v, p));
    1249              : }
    1250              : 
    1251              : static GEN
    1252           16 : matid2_FlxXM(long v, long sv)
    1253           16 : { retmkmat22(pol1_FlxX(v, sv),pol_0(v),pol_0(v),pol1_FlxX(v, sv)); }
    1254              : 
    1255              : static GEN
    1256            0 : matJ2_FlxXM(long v, long sv)
    1257            0 : { retmkmat22(pol_0(v),pol1_FlxX(v, sv),pol1_FlxX(v, sv),pol_0(v)); }
    1258              : 
    1259              : struct FlxqX_res
    1260              : {
    1261              :    GEN res, lc;
    1262              :    long deg0, deg1, off;
    1263              : };
    1264              : 
    1265              : INLINE void
    1266            0 : FlxqX_halfres_update(long da, long db, long dr, GEN T, ulong p, ulong pi, struct FlxqX_res *res)
    1267              : {
    1268            0 :   if (dr >= 0)
    1269              :   {
    1270            0 :     if (!Flx_equal1(res->lc))
    1271              :     {
    1272            0 :       res->lc  = Flxq_powu_pre(res->lc, da - dr, T, p, pi);
    1273            0 :       res->res = Flxq_mul_pre(res->res, res->lc, T, p, pi);
    1274              :     }
    1275            0 :     if (both_odd(da + res->off, db + res->off))
    1276            0 :       res->res = Flx_neg(res->res, p);
    1277              :   } else
    1278              :   {
    1279            0 :     if (db == 0)
    1280              :     {
    1281            0 :       if (!Flx_equal1(res->lc))
    1282              :       {
    1283            0 :           res->lc  = Flxq_powu_pre(res->lc, da, T, p, pi);
    1284            0 :           res->res = Flxq_mul_pre(res->res, res->lc, T, p, pi);
    1285              :       }
    1286              :     } else
    1287            0 :       res->res = pol0_Flx(get_Flx_var(T));
    1288              :   }
    1289            0 : }
    1290              : 
    1291              : static GEN
    1292         4052 : FlxqX_halfres_basecase(GEN a, GEN b, GEN T, ulong p, ulong pi, GEN *pa, GEN *pb, struct FlxqX_res *res)
    1293              : {
    1294         4052 :   pari_sp av=avma;
    1295              :   GEN u,u1,v,v1, M;
    1296         4052 :   long vx = varn(a), vT = get_Flx_var(T), n = lgpol(a)>>1;
    1297         4052 :   u1 = v = pol_0(vx);
    1298         4052 :   u = v1 = pol1_FlxX(vx, vT);
    1299        22505 :   while (lgpol(b)>n)
    1300              :   {
    1301              :     GEN r, q;
    1302        18453 :     q = FlxqX_divrem(a,b, T, p, &r);
    1303        18453 :     if (res)
    1304              :     {
    1305            0 :       long da = degpol(a), db = degpol(b), dr = degpol(r);
    1306            0 :       res->lc = gel(b,db+2);
    1307            0 :       if (dr >= n)
    1308            0 :         FlxqX_halfres_update(da, db, dr, T, p, pi, res);
    1309              :       else
    1310              :       {
    1311            0 :         res->deg0 = da;
    1312            0 :         res->deg1 = db;
    1313              :       }
    1314              :     }
    1315        18453 :     a = b; b = r; swap(u,u1); swap(v,v1);
    1316        18453 :     u1 = FlxX_sub(u1, FlxqX_mul_pre(u, q, T, p, pi), p);
    1317        18453 :     v1 = FlxX_sub(v1, FlxqX_mul_pre(v, q, T, p, pi), p);
    1318        18453 :     if (gc_needed(av,2))
    1319              :     {
    1320            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_halfgcd (d = %ld)",degpol(b));
    1321            0 :       if (res)
    1322            0 :         (void)gc_all(av, 8, &a,&b,&u1,&v1,&u,&v,&res->res,&res->lc);
    1323              :       else
    1324            0 :         (void)gc_all(av, 6, &a,&b,&u1,&v1,&u,&v);
    1325              :     }
    1326              :   }
    1327         4052 :   M = mkmat22(u,v,u1,v1); *pa = a; *pb = b;
    1328            0 :   return res ? gc_all(av, 5, &M, pa, pb, &res->res, &res->lc)
    1329         4052 :              : gc_all(av, 3, &M, pa, pb);
    1330              : }
    1331              : 
    1332              : static GEN FlxqX_halfres_i(GEN x, GEN y, GEN T, ulong p, ulong pi, GEN *a, GEN *b, struct FlxqX_res *res);
    1333              : 
    1334              : static GEN
    1335         3366 : FlxqX_halfres_split(GEN x, GEN y, GEN T, ulong p, ulong pi, GEN *a, GEN *b, struct FlxqX_res *res)
    1336              : {
    1337         3366 :   pari_sp av = avma;
    1338              :   GEN Q, R, S, V1, V2;
    1339              :   GEN x1, y1, r, q;
    1340         3366 :   long l = lgpol(x), n = l>>1, k, vT = get_Flx_var(T);
    1341         3366 :   if (lgpol(y) <= n)
    1342           16 :     { *a = RgX_copy(x); *b = RgX_copy(y); return matid2_FlxXM(varn(x), vT); }
    1343         3350 :   if (res)
    1344              :   {
    1345            0 :      res->lc = leading_coeff(y);
    1346            0 :      res->deg0 -= n;
    1347            0 :      res->deg1 -= n;
    1348            0 :      res->off += n;
    1349              :   }
    1350         3350 :   R = FlxqX_halfres_i(FlxX_shift(x,-n, vT),FlxX_shift(y,-n, vT), T, p, pi, a, b, res);
    1351         3350 :   if (res)
    1352              :   {
    1353            0 :     res->off -= n;
    1354            0 :     res->deg0 += n;
    1355            0 :     res->deg1 += n;
    1356              :   }
    1357         3350 :   V1 = FlxqXM_FlxqX_mul2(R, Flxn_red(x,n), Flxn_red(y,n), T, p, pi);
    1358         3350 :   x1 = FlxX_add(FlxX_shift(*a,n,vT), gel(V1,1), p);
    1359         3350 :   y1 = FlxX_add(FlxX_shift(*b,n,vT), gel(V1,2), p);
    1360         3350 :   if (lgpol(y1) <= n)
    1361              :   {
    1362           74 :     *a = x1; *b = y1;
    1363            0 :     return res ? gc_all(av, 5, &R, a, b, &res->res, &res->lc)
    1364           74 :                : gc_all(av, 3, &R, a, b);
    1365              :   }
    1366         3276 :   k = 2*n-degpol(y1);
    1367         3276 :   q = FlxqX_divrem(x1, y1, T, p, &r);
    1368         3276 :   if (res)
    1369              :   {
    1370            0 :     long dx1 = degpol(x1), dy1 = degpol(y1), dr = degpol(r);
    1371            0 :     if (dy1 < degpol(y))
    1372            0 :       FlxqX_halfres_update(res->deg0, res->deg1, dy1, T, p, pi, res);
    1373            0 :     res->lc = leading_coeff(y1);
    1374            0 :     res->deg0 = dx1;
    1375            0 :     res->deg1 = dy1;
    1376            0 :     if (dr >= n)
    1377              :     {
    1378            0 :       FlxqX_halfres_update(dx1, dy1, dr, T, p, pi, res);
    1379            0 :       res->deg0 = dy1;
    1380            0 :       res->deg1 = dr;
    1381              :     }
    1382            0 :     res->deg0 -= k;
    1383            0 :     res->deg1 -= k;
    1384            0 :     res->off += k;
    1385              :   }
    1386         3276 :   S = FlxqX_halfres_i(FlxX_shift(y1,-k, vT), FlxX_shift(r,-k, vT), T, p, pi, a, b, res);
    1387         3276 :   if (res)
    1388              :   {
    1389            0 :     res->deg0 += k;
    1390            0 :     res->deg1 += k;
    1391            0 :     res->off -= k;
    1392              :   }
    1393         3276 :   Q = FlxqXM_mul2(S, FlxqX_FlxqXM_qmul(q, R, T, p, pi), T, p, pi);
    1394         3276 :   V2 = FlxqXM_FlxqX_mul2(S, FlxXn_red(y1,k), FlxXn_red(r,k), T, p, pi);
    1395         3276 :   *a = FlxX_add(FlxX_shift(*a,k,vT), gel(V2,1), p);
    1396         3276 :   *b = FlxX_add(FlxX_shift(*b,k,vT), gel(V2,2), p);
    1397            0 :   return res ? gc_all(av, 5, &Q, a, b, &res->res, &res->lc)
    1398         3276 :              : gc_all(av, 3, &Q, a, b);
    1399              : }
    1400              : 
    1401              : static GEN
    1402         7418 : FlxqX_halfres_i(GEN x, GEN y, GEN T, ulong p, ulong pi, GEN *a, GEN *b, struct FlxqX_res *res)
    1403              : {
    1404         7418 :   if (lgpol(x) < FlxqX_HALFGCD_LIMIT)
    1405         4052 :     return FlxqX_halfres_basecase(x, y, T, p, pi, a, b, res);
    1406         3366 :   return FlxqX_halfres_split(x, y, T, p, pi, a, b, res);
    1407              : }
    1408              : 
    1409              : static GEN
    1410          792 : FlxqX_halfgcd_all_i(GEN x, GEN y, GEN T, ulong p, ulong pi, GEN *pa, GEN *pb)
    1411              : {
    1412              :   GEN a, b;
    1413          792 :   GEN R = FlxqX_halfres_i(x, y, T, p, pi, &a, &b, NULL);
    1414          792 :   if (pa) *pa = a;
    1415          792 :   if (pb) *pb = b;
    1416          792 :   return R;
    1417              : }
    1418              : 
    1419              : /* Return M in GL_2(Fp[X]/(T)[Y]) such that:
    1420              : if [a',b']~=M*[a,b]~ then degpol(a')>= (lgpol(a)>>1) >degpol(b')
    1421              : */
    1422              : 
    1423              : GEN
    1424          792 : FlxqX_halfgcd_all_pre(GEN x, GEN y, GEN T, ulong p, ulong pi, GEN *a, GEN *b)
    1425              : {
    1426          792 :   pari_sp av = avma;
    1427              :   GEN R,q,r;
    1428          792 :   if (!signe(x))
    1429              :   {
    1430            0 :     if (a) *a = RgX_copy(y);
    1431            0 :     if (b) *b = RgX_copy(x);
    1432            0 :     return matJ2_FlxXM(varn(x),get_Flx_var(T));
    1433              :   }
    1434          792 :   if (degpol(y)<degpol(x)) return FlxqX_halfgcd_all_i(x, y, T, p, pi, a, b);
    1435          193 :   q = FlxqX_divrem_pre(y, x, T, p, pi, &r);
    1436          193 :   R = FlxqX_halfgcd_all_i(x, r, T, p, pi, a, b);
    1437          193 :   gcoeff(R,1,1) = FlxX_sub(gcoeff(R,1,1),
    1438          193 :                            FlxqX_mul_pre(q, gcoeff(R,1,2), T, p, pi), p);
    1439          193 :   gcoeff(R,2,1) = FlxX_sub(gcoeff(R,2,1),
    1440          193 :                            FlxqX_mul_pre(q, gcoeff(R,2,2), T, p, pi), p);
    1441          193 :   return !a && b ? gc_all(av, 2, &R, b): gc_all(av, 1+!!a+!!b, &R, a, b);
    1442              : }
    1443              : GEN
    1444            7 : FlxqX_halfgcd_all(GEN x, GEN y, GEN T, ulong p, GEN *a, GEN *b)
    1445            7 : { return FlxqX_halfgcd_all_pre(x, y, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p), a, b); }
    1446              : 
    1447              : GEN
    1448          254 : FlxqX_halfgcd_pre(GEN x, GEN y, GEN T, ulong p, ulong pi)
    1449          254 : { return FlxqX_halfgcd_all_pre(x, y, T, p, pi, NULL, NULL); }
    1450              : 
    1451              : GEN
    1452            0 : FlxqX_halfgcd(GEN x, GEN y, GEN T, ulong p)
    1453            0 : { return FlxqX_halfgcd_pre(x, y, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    1454              : 
    1455              : static GEN
    1456       167928 : FlxqX_gcd_basecase(GEN a, GEN b, GEN T, ulong p, ulong pi)
    1457              : {
    1458       167928 :   pari_sp av = avma, av0=avma;
    1459      1124147 :   while (signe(b))
    1460              :   {
    1461              :     GEN c;
    1462       956219 :     if (gc_needed(av0,2))
    1463              :     {
    1464            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_gcd (d = %ld)",degpol(b));
    1465            0 :       (void)gc_all(av0,2, &a,&b);
    1466              :     }
    1467       956219 :     av = avma; c = FlxqX_rem_pre(a, b, T, p, pi); a=b; b=c;
    1468              :   }
    1469       167928 :   return gc_const(av, a);
    1470              : }
    1471              : 
    1472              : GEN
    1473       177830 : FlxqX_gcd_pre(GEN x, GEN y, GEN T, ulong p, ulong pi)
    1474              : {
    1475       177830 :   pari_sp av = avma;
    1476       177830 :   x = FlxqX_red_pre(x, T, p, pi);
    1477       177830 :   y = FlxqX_red_pre(y, T, p, pi);
    1478       177830 :   if (!signe(x)) return gc_upto(av, y);
    1479       168304 :   while (lgpol(y)>=FlxqX_GCD_LIMIT)
    1480              :   {
    1481          376 :     if (lgpol(y)<=(lgpol(x)>>1))
    1482              :     {
    1483            0 :       GEN r = FlxqX_rem_pre(x, y, T, p, pi);
    1484            0 :       x = y; y = r;
    1485              :     }
    1486          376 :     (void) FlxqX_halfgcd_all_pre(x,y, T, p, pi, &x, &y);
    1487          376 :     if (gc_needed(av,2))
    1488              :     {
    1489            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_gcd (y = %ld)",degpol(y));
    1490            0 :       (void)gc_all(av,2,&x,&y);
    1491              :     }
    1492              :   }
    1493       167928 :   return gc_upto(av, FlxqX_gcd_basecase(x, y, T, p, pi));
    1494              : }
    1495              : GEN
    1496        24557 : FlxqX_gcd(GEN x, GEN y, GEN T, ulong p)
    1497        24557 : { return FlxqX_gcd_pre(x, y, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    1498              : 
    1499              : static GEN
    1500       134246 : FlxqX_extgcd_basecase(GEN a, GEN b, GEN T, ulong p,ulong pi, GEN *ptu, GEN *ptv)
    1501              : {
    1502       134246 :   pari_sp av=avma;
    1503              :   GEN u,v,d,d1,v1;
    1504       134246 :   long vx = varn(a);
    1505       134246 :   d = a; d1 = b;
    1506       134246 :   v = pol_0(vx); v1 = pol1_FlxX(vx, get_Flx_var(T));
    1507       472812 :   while (signe(d1))
    1508              :   {
    1509       338566 :     GEN r, q = FlxqX_divrem_pre(d, d1, T, p, pi, &r);
    1510       338566 :     v = FlxX_sub(v, FlxqX_mul_pre(q,v1,T, p, pi),p);
    1511       338566 :     u=v; v=v1; v1=u;
    1512       338566 :     u=r; d=d1; d1=u;
    1513       338566 :     if (gc_needed(av,2))
    1514              :     {
    1515            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_extgcd (d = %ld)",degpol(d));
    1516            0 :       (void)gc_all(av,5, &d,&d1,&u,&v,&v1);
    1517              :     }
    1518              :   }
    1519       134246 :   if (ptu)
    1520       134232 :     *ptu = FlxqX_div_pre(FlxX_sub(d,FlxqX_mul_pre(b,v, T,p,pi), p), a, T,p,pi);
    1521       134246 :   *ptv = v; return d;
    1522              : }
    1523              : 
    1524              : static GEN
    1525          143 : FlxqX_extgcd_halfgcd(GEN x, GEN y, GEN T, ulong p, ulong pi, GEN *ptu, GEN *ptv)
    1526              : {
    1527              :   GEN u,v;
    1528          143 :   GEN V = cgetg(expu(lgpol(y))+2,t_VEC);
    1529          143 :   long i, n = 0, vs = varn(x), vT = get_Flx_var(T);
    1530          298 :   while (lgpol(y) >= FlxqX_EXTGCD_LIMIT)
    1531              :   {
    1532          155 :     if (lgpol(y)<=(lgpol(x)>>1))
    1533              :     {
    1534            0 :       GEN r, q = FlxqX_divrem_pre(x, y, T, p, pi, &r);
    1535            0 :       x = y; y = r;
    1536            0 :       gel(V,++n) = mkmat22(pol_0(vs),pol1_FlxX(vs,vT),pol1_FlxX(vs,vT),FlxX_neg(q,p));
    1537              :     } else
    1538          155 :       gel(V,++n) = FlxqX_halfgcd_all_pre(x, y, T, p, pi, &x, &y);
    1539              :   }
    1540          143 :   y = FlxqX_extgcd_basecase(x,y, T, p, pi, &u,&v);
    1541          155 :   for (i = n; i>1; i--)
    1542              :   {
    1543           12 :     GEN R = gel(V,i);
    1544           12 :     GEN u1 = FlxqX_addmulmul(u, v, gcoeff(R,1,1), gcoeff(R,2,1), T, p, pi);
    1545           12 :     GEN v1 = FlxqX_addmulmul(u, v, gcoeff(R,1,2), gcoeff(R,2,2), T, p, pi);
    1546           12 :     u = u1; v = v1;
    1547              :   }
    1548              :   {
    1549          143 :     GEN R = gel(V,1);
    1550          143 :     if (ptu)
    1551          143 :       *ptu = FlxqX_addmulmul(u, v, gcoeff(R,1,1), gcoeff(R,2,1), T, p, pi);
    1552          143 :     *ptv   = FlxqX_addmulmul(u, v, gcoeff(R,1,2), gcoeff(R,2,2), T, p, pi);
    1553              :   }
    1554          143 :   return y;
    1555              : }
    1556              : 
    1557              : /* x and y in Z[Y][X], return lift(gcd(x mod T,p, y mod T,p)). Set u and v st
    1558              :  * ux + vy = gcd (mod T,p) */
    1559              : GEN
    1560       134246 : FlxqX_extgcd_pre(GEN x, GEN y, GEN T, ulong p, ulong pi, GEN *ptu, GEN *ptv)
    1561              : {
    1562       134246 :   pari_sp av = avma;
    1563              :   GEN d;
    1564       134246 :   x = FlxqX_red_pre(x, T, p, pi);
    1565       134246 :   y = FlxqX_red_pre(y, T, p, pi);
    1566       134246 :   if (lgpol(y)>=FlxqX_EXTGCD_LIMIT)
    1567          143 :     d = FlxqX_extgcd_halfgcd(x, y, T, p, pi, ptu, ptv);
    1568              :   else
    1569       134103 :     d = FlxqX_extgcd_basecase(x, y, T, p, pi, ptu, ptv);
    1570       134246 :   return gc_all(av, ptu?3:2, &d, ptv, ptu);
    1571              : }
    1572              : GEN
    1573       134232 : FlxqX_extgcd(GEN x, GEN y, GEN T, ulong p, GEN *ptu, GEN *ptv)
    1574              : {
    1575       134232 :   ulong pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
    1576       134232 :   return FlxqX_extgcd_pre(x, y, T, p, pi, ptu, ptv);
    1577              : }
    1578              : 
    1579              : static GEN
    1580       385148 : FlxqX_saferem(GEN P, GEN Q, GEN T, ulong p, ulong pi)
    1581              : {
    1582       385148 :   GEN U = Flxq_invsafe_pre(leading_coeff(Q), T, p, pi);
    1583       385148 :   if (!U) return NULL;
    1584       385148 :   Q = FlxqX_Flxq_mul_to_monic_pre(Q,U,T,p,pi);
    1585       385148 :   return FlxqX_rem_pre(P,Q,T,p,pi);
    1586              : }
    1587              : 
    1588              : GEN
    1589            0 : FlxqX_eval(GEN x, GEN y, GEN T, ulong p)
    1590              : {
    1591              :   pari_sp av;
    1592              :   GEN p1, r;
    1593            0 :   long j, i=lg(x)-1;
    1594            0 :   if (i<=2)
    1595            0 :     return (i==2)? gcopy(gel(x,2)): pol0_Flx(get_Flx_var(T));
    1596            0 :   av=avma; p1=gel(x,i);
    1597              :   /* specific attention to sparse polynomials (see poleval)*/
    1598              :   /*You've guessed it! It's a copy-paste(tm)*/
    1599            0 :   for (i--; i>=2; i=j-1)
    1600              :   {
    1601            0 :     for (j=i; lg(gel(x,j))==1; j--)
    1602            0 :       if (j==2)
    1603              :       {
    1604            0 :         if (i!=j) y = Flxq_powu(y, i-j+1, T, p);
    1605            0 :         return gc_upto(av, Flxq_mul(p1,y, T, p));
    1606              :       }
    1607            0 :     r = (i==j)? y: Flxq_powu(y, i-j+1, T, p);
    1608            0 :     p1 = Flx_add(Flxq_mul(p1,r,T,p), gel(x,j), p);
    1609              :   }
    1610            0 :   return gc_upto(av, p1);
    1611              : }
    1612              : 
    1613              : GEN
    1614        97923 : FlxqX_safegcd(GEN P, GEN Q, GEN T, ulong p)
    1615              : {
    1616        97923 :   pari_sp av = avma;
    1617              :   ulong pi;
    1618              :   GEN U;
    1619        97923 :   if (!signe(P)) return gcopy(Q);
    1620        97923 :   if (!signe(Q)) return gcopy(P);
    1621        97923 :   pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
    1622        97923 :   T = Flx_get_red_pre(T,p,pi);
    1623              :   for(;;)
    1624              :   {
    1625       331044 :     P = FlxqX_saferem(P,Q,T,p,pi);
    1626       331044 :     if (!P) return gc_NULL(av);
    1627       331044 :     if (!signe(P)) break;
    1628       233121 :     if (gc_needed(av, 1))
    1629              :     {
    1630            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_safegcd");
    1631            0 :       (void)gc_all(av, 2, &P,&Q);
    1632              :     }
    1633       233121 :     swap(P, Q);
    1634              :   }
    1635        97923 :   U = Flxq_invsafe_pre(leading_coeff(Q), T, p, pi);
    1636        97923 :   if (!U) return gc_NULL(av);
    1637        97923 :   Q = FlxqX_Flxq_mul_to_monic_pre(Q,U,T,p,pi);
    1638        97923 :   return gc_upto(av, Q);
    1639              : }
    1640              : 
    1641              : /* Res(A,B) = Res(B,R) * lc(B)^(a-r) * (-1)^(ab), with R=A%B, a=deg(A) ...*/
    1642              : GEN
    1643        11041 : FlxqX_saferesultant(GEN a, GEN b, GEN T, ulong p)
    1644              : {
    1645        11041 :   long vT = get_Flx_var(T), da,db,dc;
    1646              :   ulong pi;
    1647              :   pari_sp av;
    1648        11041 :   GEN c,lb, res = pol1_Flx(vT);
    1649              : 
    1650        11041 :   if (!signe(a) || !signe(b)) return pol0_Flx(vT);
    1651              : 
    1652        11041 :   da = degpol(a);
    1653        11041 :   db = degpol(b);
    1654        11041 :   if (db > da)
    1655              :   {
    1656            0 :     swapspec(a,b, da,db);
    1657            0 :     if (both_odd(da,db)) res = Flx_neg(res, p);
    1658              :   }
    1659        11041 :   if (!da) return pol1_Flx(vT); /* = res * a[2] ^ db, since 0 <= db <= da = 0 */
    1660        11041 :   pi = SMALL_ULONG(p)? 0: get_Fl_red(p); av = avma;
    1661        65131 :   while (db)
    1662              :   {
    1663        54104 :     lb = gel(b,db+2);
    1664        54104 :     c = FlxqX_saferem(a,b, T,p,pi);
    1665        54104 :     if (!c) return gc_NULL(av);
    1666        54104 :     a = b; b = c; dc = degpol(c);
    1667        54104 :     if (dc < 0) { set_avma(av); return pol0_Flx(vT); }
    1668              : 
    1669        54090 :     if (both_odd(da,db)) res = Flx_neg(res, p);
    1670        54090 :     if (!Flx_equal1(lb))
    1671        54034 :       res = Flxq_mul_pre(res, Flxq_powu_pre(lb, da - dc, T, p, pi), T, p, pi);
    1672        54090 :     if (gc_needed(av,2))
    1673              :     {
    1674            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_resultant (da = %ld)",da);
    1675            0 :       (void)gc_all(av,3, &a,&b,&res);
    1676              :     }
    1677        54090 :     da = db; /* = degpol(a) */
    1678        54090 :     db = dc; /* = degpol(b) */
    1679              :   }
    1680        11027 :   res = Flxq_mul_pre(res, Flxq_powu_pre(gel(b,2), da, T, p, pi), T, p, pi);
    1681        11027 :   return gc_upto(av, res);
    1682              : }
    1683              : 
    1684              : static GEN
    1685            0 : FlxqX_halfres(GEN x, GEN y, GEN T, ulong p, ulong pi, GEN *a, GEN *b, GEN *r)
    1686              : {
    1687              :   struct FlxqX_res res;
    1688              :   GEN V;
    1689              :   long dB;
    1690              : 
    1691            0 :   res.res  = *r;
    1692            0 :   res.lc   = leading_coeff(y);
    1693            0 :   res.deg0 = degpol(x);
    1694            0 :   res.deg1 = degpol(y);
    1695            0 :   res.off = 0;
    1696            0 :   V = FlxqX_halfres_i(x, y, T, p, pi, a, b, &res);
    1697            0 :   dB = degpol(*b);
    1698            0 :   if (dB < degpol(y))
    1699            0 :     FlxqX_halfres_update(res.deg0, res.deg1, dB, T, p, pi, &res);
    1700            0 :   *r = res.res;
    1701            0 :   return V;
    1702              : }
    1703              : 
    1704              : static GEN
    1705           56 : FlxqX_resultant_basecase(GEN a, GEN b, GEN T, ulong p, ulong pi)
    1706              : {
    1707           56 :   pari_sp av = avma;
    1708           56 :   long vT = get_Flx_var(T), da,db,dc;
    1709           56 :   GEN c,lb, res = pol1_Flx(vT);
    1710              : 
    1711           56 :   if (!signe(a) || !signe(b)) return pol0_Flx(vT);
    1712              : 
    1713           56 :   da = degpol(a);
    1714           56 :   db = degpol(b);
    1715           56 :   if (db > da)
    1716              :   {
    1717            0 :     swapspec(a,b, da,db);
    1718            0 :     if (both_odd(da,db)) res = Flx_neg(res, p);
    1719              :   }
    1720           56 :   if (!da) return pol1_Flx(vT); /* = res * a[2] ^ db, since 0 <= db <= da = 0 */
    1721          147 :   while (db)
    1722              :   {
    1723           91 :     lb = gel(b,db+2);
    1724           91 :     c = FlxqX_rem_pre(a,b, T,p,pi);
    1725           91 :     a = b; b = c; dc = degpol(c);
    1726           91 :     if (dc < 0) { set_avma(av); return pol0_Flx(vT); }
    1727              : 
    1728           91 :     if (both_odd(da,db)) res = Flx_neg(res, p);
    1729           91 :     if (!Flx_equal1(lb))
    1730           63 :       res = Flxq_mul_pre(res, Flxq_powu_pre(lb, da - dc, T,p,pi), T,p,pi);
    1731           91 :     if (gc_needed(av,2))
    1732              :     {
    1733            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_resultant (da = %ld)",da);
    1734            0 :       (void)gc_all(av,3, &a,&b,&res);
    1735              :     }
    1736           91 :     da = db; /* = degpol(a) */
    1737           91 :     db = dc; /* = degpol(b) */
    1738              :   }
    1739           56 :   res = Flxq_mul_pre(res, Flxq_powu_pre(gel(b,2), da, T,p,pi), T,p,pi);
    1740           56 :   return gc_upto(av, res);
    1741              : }
    1742              : 
    1743              : /* Res(A,B) = Res(B,R) * lc(B)^(a-r) * (-1)^(ab), with R=A%B, a=deg(A) ...*/
    1744              : GEN
    1745           56 : FlxqX_resultant_pre(GEN x, GEN y, GEN T, ulong p, ulong pi)
    1746              : {
    1747           56 :   pari_sp av = avma;
    1748           56 :   long dx, dy, vT = get_Flx_var(T);
    1749           56 :   GEN res = pol1_Flx(vT);
    1750           56 :   if (!signe(x) || !signe(y)) return pol0_Flx(vT);
    1751           56 :   dx = degpol(x); dy = degpol(y);
    1752           56 :   if (dx < dy)
    1753              :   {
    1754           21 :     swap(x,y);
    1755           21 :     if (both_odd(dx, dy))
    1756            0 :       res = Flx_neg(res, p);
    1757              :   }
    1758           56 :   while (lgpol(y) >= FlxqX_GCD_LIMIT)
    1759              :   {
    1760            0 :     if (lgpol(y)<=(lgpol(x)>>1))
    1761              :     {
    1762            0 :       GEN r = FlxqX_rem_pre(x, y, T, p, pi);
    1763            0 :       long dx = degpol(x), dy = degpol(y), dr = degpol(r);
    1764            0 :       GEN ly = gel(y,dy+2);
    1765            0 :       if (!Flx_equal1(ly))
    1766            0 :         res = Flxq_mul_pre(res, Flxq_powu_pre(ly, dx - dr, T, p, pi), T, p, pi);
    1767            0 :       if (both_odd(dx, dy))
    1768            0 :         res = Flx_neg(res, p);
    1769            0 :       x = y; y = r;
    1770              :     }
    1771            0 :     (void) FlxqX_halfres(x, y, T, p, pi, &x, &y, &res);
    1772            0 :     if (gc_needed(av,2))
    1773              :     {
    1774            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FlxqX_resultant (y = %ld)",degpol(y));
    1775            0 :       (void)gc_all(av,3,&x,&y,&res);
    1776              :     }
    1777              :   }
    1778           56 :   res = Flxq_mul_pre(res, FlxqX_resultant_basecase(x, y, T, p, pi), T, p, pi);
    1779           56 :   return gc_upto(av, res);
    1780              : }
    1781              : GEN
    1782           56 : FlxqX_resultant(GEN x, GEN y, GEN T, ulong p)
    1783           56 : { return FlxqX_resultant_pre(x, y, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    1784              : 
    1785              : /* disc P = (-1)^(n(n-1)/2) lc(P)^(n - deg P' - 2) Res(P,P'), n = deg P */
    1786              : GEN
    1787           14 : FlxqX_disc(GEN P, GEN T, ulong p)
    1788              : {
    1789           14 :   pari_sp av = avma;
    1790           14 :   GEN L, dP = FlxX_deriv(P, p), D = FlxqX_resultant(P, dP, T, p);
    1791              :   long dd;
    1792           14 :   if (!lgpol(D)) return pol0_Flx(get_Flx_var(T));
    1793           14 :   dd = degpol(P) - 2 - degpol(dP); /* >= -1; > -1 iff p | deg(P) */
    1794           14 :   L = leading_coeff(P);
    1795           14 :   if (dd && !Flx_equal1(L))
    1796              :   {
    1797            0 :     ulong pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
    1798            0 :     D = (dd == -1)? Flxq_div_pre(D,L,T,p,pi)
    1799            0 :                   : Flxq_mul_pre(D, Flxq_powu_pre(L, dd, T,p,pi), T,p,pi); }
    1800           14 :   if (degpol(P) & 2) D = Flx_neg(D, p);
    1801           14 :   return gc_upto(av, D);
    1802              : }
    1803              : 
    1804              : INLINE GEN
    1805         6080 : FlxXn_recip(GEN x, long n, long v)
    1806         6080 : { return FlxX_recipspec(x+2, minss(lgpol(x), n), n, v); }
    1807              : 
    1808              : GEN
    1809         2432 : FlxqX_Newton_pre(GEN P, long n, GEN T, ulong p, ulong pi)
    1810              : {
    1811         2432 :   pari_sp av = avma;
    1812         2432 :   long d = degpol(P), vT = get_Flx_var(T);
    1813         2432 :   GEN dP = FlxXn_recip(FlxX_deriv(P, p), d, vT);
    1814         2432 :   GEN Q = FlxqXn_mul_pre(FlxqXn_inv_pre(FlxXn_recip(P, d+1, vT), n, T,p,pi),
    1815              :                          dP, n, T, p, pi);
    1816         2432 :   return gc_GEN(av, Q);
    1817              : }
    1818              : GEN
    1819            0 : FlxqX_Newton(GEN P, long n, GEN T, ulong p)
    1820            0 : { return FlxqX_Newton_pre(P, n, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    1821              : 
    1822              : GEN
    1823         1216 : FlxqX_fromNewton_pre(GEN P, GEN T, ulong p, ulong pi)
    1824              : {
    1825         1216 :   pari_sp av = avma;
    1826         1216 :   long vT = get_Flx_var(T);
    1827         1216 :   long n = Flx_constant(constant_coeff(P))+1;
    1828         1216 :   GEN z = FlxX_neg(FlxX_shift(P, -1, vT), p);
    1829         1216 :   GEN Q = FlxXn_recip(FlxqXn_expint_pre(z, n, T, p, pi), n, vT);
    1830         1216 :   return gc_GEN(av, Q);
    1831              : }
    1832              : GEN
    1833            0 : FlxqX_fromNewton(GEN P, GEN T, ulong p)
    1834            0 : { return FlxqX_fromNewton_pre(P, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    1835              : 
    1836              : GEN
    1837         1216 : FlxqX_composedsum(GEN P, GEN Q, GEN T, ulong p)
    1838              : {
    1839         1216 :   pari_sp av = avma;
    1840         1216 :   ulong pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
    1841         1216 :   long n = 1+ degpol(P)*degpol(Q);
    1842         1216 :   GEN Pl = FlxX_invLaplace(FlxqX_Newton_pre(P,n, T,p,pi), p);
    1843         1216 :   GEN Ql = FlxX_invLaplace(FlxqX_Newton_pre(Q,n, T,p,pi), p);
    1844         1216 :   GEN L = FlxX_Laplace(FlxqXn_mul_pre(Pl, Ql, n, T,p,pi), p);
    1845         1216 :   GEN R = FlxqX_fromNewton_pre(L, T, p, pi);
    1846         1216 :   GEN lead = Flxq_mul_pre(Flxq_powu_pre(leading_coeff(P),degpol(Q), T,p,pi),
    1847         1216 :                           Flxq_powu_pre(leading_coeff(Q),degpol(P), T,p,pi),
    1848              :                           T, p, pi);
    1849         1216 :   return gc_upto(av, FlxqX_Flxq_mul_pre(R, lead, T, p, pi));
    1850              : }
    1851              : 
    1852              : GEN
    1853       223086 : FlxqXV_prod(GEN V, GEN T, ulong p)
    1854              : {
    1855       223086 :   struct _FlxqXQ d; d.p=p; d.T=T; d.pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
    1856       223086 :   return gen_product(V, (void*)&d, &_FlxqX_mul);
    1857              : }
    1858              : 
    1859              : static GEN
    1860        32144 : FlxqV_roots_to_deg1(GEN x, GEN T, ulong p, long v)
    1861              : {
    1862        32144 :   long sv = get_Flx_var(T);
    1863       124197 :   pari_APPLY_same(deg1pol_shallow(pol1_Flx(sv),Flx_neg(gel(x,i),p),v))
    1864              : }
    1865              : 
    1866              : GEN
    1867        32144 : FlxqV_roots_to_pol(GEN V, GEN T, ulong p, long v)
    1868              : {
    1869        32144 :   pari_sp ltop = avma;
    1870        32144 :   GEN W = FlxqV_roots_to_deg1(V, T, p, v);
    1871        32144 :   return gc_upto(ltop, FlxqXV_prod(W, T, p));
    1872              : }
    1873              : 
    1874              : /*******************************************************************/
    1875              : /*                                                                 */
    1876              : /*                       (Fl[X]/T(X))[Y] / S(Y)                    */
    1877              : /*                                                                 */
    1878              : /*******************************************************************/
    1879              : 
    1880              : GEN
    1881       487855 : FlxqXQ_mul_pre(GEN x, GEN y, GEN S, GEN T, ulong p, ulong pi)
    1882       487855 : { return FlxqX_rem_pre(FlxqX_mul_pre(x,y,T,p,pi),S,T,p,pi); }
    1883              : GEN
    1884         1800 : FlxqXQ_mul(GEN x, GEN y, GEN S, GEN T, ulong p)
    1885         1800 : { return FlxqXQ_mul_pre(x, y, S, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    1886              : 
    1887              : GEN
    1888       271535 : FlxqXQ_sqr_pre(GEN x, GEN S, GEN T, ulong p, ulong pi)
    1889       271535 : { return FlxqX_rem_pre(FlxqX_sqr_pre(x,T,p,pi),S,T,p,pi); }
    1890              : GEN
    1891            0 : FlxqXQ_sqr(GEN x, GEN S, GEN T, ulong p)
    1892            0 : { return FlxqXQ_sqr_pre(x, S, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    1893              : 
    1894              : GEN
    1895           14 : FlxqXQ_invsafe_pre(GEN x, GEN S, GEN T, ulong p, ulong pi)
    1896              : {
    1897           14 :   GEN V, z = FlxqX_extgcd_pre(get_FlxqX_mod(S), x, T, p, pi, NULL, &V);
    1898           14 :   if (degpol(z)) return NULL;
    1899           14 :   z = Flxq_invsafe_pre(gel(z,2),T,p,pi);
    1900           14 :   if (!z) return NULL;
    1901           14 :   return FlxqX_Flxq_mul_pre(V, z, T, p, pi);
    1902              : }
    1903              : GEN
    1904            0 : FlxqXQ_invsafe(GEN x, GEN S, GEN T, ulong p)
    1905            0 : { return FlxqXQ_invsafe_pre(x, S, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    1906              : 
    1907              : GEN
    1908           14 : FlxqXQ_inv_pre(GEN x, GEN S, GEN T, ulong p, ulong pi)
    1909              : {
    1910           14 :   pari_sp av = avma;
    1911           14 :   GEN U = FlxqXQ_invsafe_pre(x, S, T, p, pi);
    1912           14 :   if (!U) pari_err_INV("FlxqXQ_inv",x);
    1913           14 :   return gc_upto(av, U);
    1914              : }
    1915              : GEN
    1916           14 : FlxqXQ_inv(GEN x, GEN S, GEN T,ulong p)
    1917           14 : { return FlxqXQ_inv_pre(x, S, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    1918              : 
    1919              : GEN
    1920            0 : FlxqXQ_div_pre(GEN x, GEN y, GEN S, GEN T, ulong p, ulong pi)
    1921            0 : { return FlxqXQ_mul_pre(x, FlxqXQ_inv_pre(y,S,T,p,pi),S,T,p,pi); }
    1922              : GEN
    1923            0 : FlxqXQ_div(GEN x, GEN y, GEN S, GEN T, ulong p)
    1924            0 : { return FlxqXQ_div_pre(x, y, S, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    1925              : 
    1926              : static GEN
    1927            0 : _FlxqX_add(void *data, GEN x, GEN y) {
    1928            0 :   struct _FlxqXQ *d = (struct _FlxqXQ*) data;
    1929            0 :   return FlxX_add(x,y, d->p);
    1930              : }
    1931              : static GEN
    1932         4868 : _FlxqX_sub(void *data, GEN x, GEN y) {
    1933         4868 :   struct _FlxqXQ *d = (struct _FlxqXQ*) data;
    1934         4868 :   return FlxX_sub(x,y, d->p);
    1935              : }
    1936              : #if 0
    1937              : static GEN
    1938              : _FlxqXQ_cmul(void *data, GEN P, long a, GEN x) {
    1939              :   struct _FlxqXQ *d = (struct _FlxqXQ*) data;
    1940              :   return FlxY_Flx_mul_pre(x,gel(P,a+2), d->p, d->pi);
    1941              : }
    1942              : #endif
    1943              : static GEN
    1944         1248 : _FlxqXQ_red(void *data, GEN x) {
    1945         1248 :   struct _FlxqXQ *d = (struct _FlxqXQ*) data;
    1946         1248 :   return FlxqX_red_pre(x, d->T, d->p, d->pi);
    1947              : }
    1948              : static GEN
    1949       184836 : _FlxqXQ_mul(void *data, GEN x, GEN y) {
    1950       184836 :   struct _FlxqXQ *d = (struct _FlxqXQ*) data;
    1951       184836 :   return FlxqXQ_mul_pre(x,y, d->S,d->T, d->p, d->pi);
    1952              : }
    1953              : static GEN
    1954       271087 : _FlxqXQ_sqr(void *data, GEN x) {
    1955       271087 :   struct _FlxqXQ *d = (struct _FlxqXQ*) data;
    1956       271087 :   return FlxqXQ_sqr_pre(x, d->S,d->T, d->p, d->pi);
    1957              : }
    1958              : 
    1959              : static GEN
    1960       112026 : _FlxqXQ_one(void *data) {
    1961       112026 :   struct _FlxqXQ *d = (struct _FlxqXQ*) data;
    1962       112026 :   return pol1_FlxX(get_FlxqX_var(d->S),get_Flx_var(d->T));
    1963              : }
    1964              : 
    1965              : static GEN
    1966          281 : _FlxqXQ_zero(void *data) {
    1967          281 :   struct _FlxqXQ *d = (struct _FlxqXQ*) data;
    1968          281 :   return pol_0(get_FlxqX_var(d->S));
    1969              : }
    1970              : 
    1971              : static struct bb_algebra FlxqXQ_algebra = { _FlxqXQ_red, _FlxqX_add,
    1972              :        _FlxqX_sub, _FlxqXQ_mul, _FlxqXQ_sqr, _FlxqXQ_one, _FlxqXQ_zero };
    1973              : 
    1974              : const struct bb_algebra *
    1975          684 : get_FlxqXQ_algebra(void **E, GEN S, GEN T, ulong p)
    1976              : {
    1977          684 :   ulong pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
    1978          684 :   GEN z = new_chunk(sizeof(struct _FlxqXQ));
    1979          684 :   struct _FlxqXQ *e = (struct _FlxqXQ *) z;
    1980          684 :   e->T = Flx_get_red_pre(T, p, pi);
    1981          684 :   e->S = FlxqX_get_red_pre(S, e->T, p, pi);
    1982          684 :   e->p = p;
    1983          684 :   e->pi= pi; *E = (void*)e;
    1984          684 :   return &FlxqXQ_algebra;
    1985              : }
    1986              : 
    1987              : static struct bb_algebra FlxqX_algebra = { _FlxqXQ_red, _FlxqX_add,
    1988              :        _FlxqX_sub, _FlxqX_mul, _FlxqX_sqr, _FlxqXQ_one, _FlxqXQ_zero };
    1989              : 
    1990              : const struct bb_algebra *
    1991            0 : get_FlxqX_algebra(void **E, GEN T, ulong p, long v)
    1992              : {
    1993            0 :   ulong pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
    1994            0 :   GEN z = new_chunk(sizeof(struct _FlxqXQ));
    1995            0 :   struct _FlxqXQ *e = (struct _FlxqXQ *) z;
    1996            0 :   e->T = Flx_get_red(T, p);
    1997            0 :   e->S = pol_x(v);
    1998            0 :   e->p = p;
    1999            0 :   e->pi= pi; *E = (void*)e;
    2000            0 :   return &FlxqX_algebra;
    2001              : }
    2002              : 
    2003              : /* x over Fq, return lift(x^n) mod S */
    2004              : GEN
    2005          105 : FlxqXQ_pow_pre(GEN x, GEN n, GEN S, GEN T, ulong p, ulong pi)
    2006              : {
    2007          105 :   pari_sp av = avma;
    2008              :   struct _FlxqXQ D;
    2009          105 :   long s = signe(n);
    2010          105 :   if (!s) return pol1_FlxX(get_FlxqX_var(S),get_Flx_var(T));
    2011          105 :   if (s < 0) x = FlxqXQ_inv_pre(x,S,T,p,pi);
    2012          105 :   if (is_pm1(n)) return s < 0 ? x : gcopy(x);
    2013          105 :   if (degpol(x) >= get_FlxqX_degree(S)) x = FlxqX_rem_pre(x,S,T,p,pi);
    2014          105 :   T = Flx_get_red_pre(T, p, pi);
    2015          105 :   S = FlxqX_get_red_pre(S, T, p, pi);
    2016          105 :   D.S = S; D.T = T; D.p = p; D.pi = pi;
    2017          105 :   x = gen_pow_i(x, n, (void*)&D, &_FlxqXQ_sqr, &_FlxqXQ_mul);
    2018          105 :   return gc_GEN(av, x);
    2019              : }
    2020              : GEN
    2021           35 : FlxqXQ_pow(GEN x, GEN n, GEN S, GEN T, ulong p)
    2022           35 : { return FlxqXQ_pow_pre(x, n, S, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    2023              : 
    2024              : /* x over Fq, return lift(x^n) mod S */
    2025              : GEN
    2026        82722 : FlxqXQ_powu_pre(GEN x, ulong n, GEN S, GEN T, ulong p, ulong pi)
    2027              : {
    2028        82722 :   pari_sp av = avma;
    2029              :   struct _FlxqXQ D;
    2030        82722 :   switch(n)
    2031              :   {
    2032            0 :     case 0: return pol1_FlxX(get_FlxqX_var(S),get_Flx_var(T));
    2033         7690 :     case 1: return gcopy(x);
    2034          448 :     case 2: return FlxqXQ_sqr_pre(x, S, T, p, pi);
    2035              :   }
    2036        74584 :   T = Flx_get_red_pre(T, p, pi);
    2037        74584 :   S = FlxqX_get_red_pre(S, T, p, pi);
    2038        74584 :   D.S = S; D.T = T; D.p = p; D.pi = pi;
    2039        74584 :   x = gen_powu_i(x, n, (void*)&D, &_FlxqXQ_sqr, &_FlxqXQ_mul);
    2040        74584 :   return gc_GEN(av, x);
    2041              : }
    2042              : GEN
    2043            0 : FlxqXQ_powu(GEN x, ulong n, GEN S, GEN T, ulong p)
    2044            0 : { return FlxqXQ_powu_pre(x, n, S, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    2045              : 
    2046              : GEN
    2047       109278 : FlxqXQ_powers_pre(GEN x, long l, GEN S, GEN T, ulong p, ulong pi)
    2048              : {
    2049              :   struct _FlxqXQ D;
    2050       109278 :   int use_sqr = 2*degpol(x) >= get_FlxqX_degree(S);
    2051       109278 :   T = Flx_get_red_pre(T, p, pi);
    2052       109278 :   S = FlxqX_get_red_pre(S, T, p, pi);
    2053       109278 :   D.S = S; D.T = T; D.p = p; D.pi = pi;
    2054       109278 :   return gen_powers(x, l, use_sqr, (void*)&D, &_FlxqXQ_sqr, &_FlxqXQ_mul,&_FlxqXQ_one);
    2055              : }
    2056              : GEN
    2057            0 : FlxqXQ_powers(GEN x, long l, GEN S, GEN T, ulong p)
    2058            0 : { return FlxqXQ_powers_pre(x, l, S, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    2059              : 
    2060              : /* Let v a linear form, return the linear form z->v(tau*z)
    2061              :    that is, v*(M_tau) */
    2062              : static GEN
    2063          508 : FlxqXQ_transmul_init(GEN tau, GEN S, GEN T, ulong p, ulong pi)
    2064              : {
    2065              :   GEN bht;
    2066          508 :   GEN h, Sp = get_FlxqX_red(S, &h);
    2067          508 :   long n = degpol(Sp), vS = varn(Sp), vT = get_Flx_var(T);
    2068          508 :   GEN ft = FlxX_recipspec(Sp+2, n+1, n+1, vT);
    2069          508 :   GEN bt = FlxX_recipspec(tau+2, lgpol(tau), n, vT);
    2070          508 :   setvarn(ft, vS); setvarn(bt, vS);
    2071          508 :   if (h)
    2072            0 :     bht = FlxqXn_mul_pre(bt, h, n-1, T, p, pi);
    2073              :   else
    2074              :   {
    2075          508 :     GEN bh = FlxqX_div_pre(FlxX_shift(tau, n-1, vT), S, T, p, pi);
    2076          508 :     bht = FlxX_recipspec(bh+2, lgpol(bh), n-1, vT);
    2077          508 :     setvarn(bht, vS);
    2078              :   }
    2079          508 :   return mkvec3(bt, bht, ft);
    2080              : }
    2081              : 
    2082              : static GEN
    2083         1077 : FlxqXQ_transmul(GEN tau, GEN a, long n, GEN T, ulong p, ulong pi)
    2084              : {
    2085         1077 :   pari_sp ltop = avma;
    2086              :   GEN t1, t2, t3, vec;
    2087         1077 :   GEN bt = gel(tau, 1), bht = gel(tau, 2), ft = gel(tau, 3);
    2088         1077 :   long vT = get_Flx_var(T);
    2089         1077 :   if (signe(a)==0) return pol_0(varn(a));
    2090         1067 :   t2 = FlxX_shift(FlxqX_mul_pre(bt, a, T, p, pi),1-n,vT);
    2091         1067 :   if (signe(bht)==0) return gc_GEN(ltop, t2);
    2092          772 :   t1 = FlxX_shift(FlxqX_mul_pre(ft, a, T, p, pi),-n,vT);
    2093          772 :   t3 = FlxqXn_mul_pre(t1, bht, n-1, T, p, pi);
    2094          772 :   vec = FlxX_sub(t2, FlxX_shift(t3, 1, vT), p);
    2095          772 :   return gc_upto(ltop, vec);
    2096              : }
    2097              : 
    2098              : static GEN
    2099          254 : polxn_FlxX(long n, long v, long vT)
    2100              : {
    2101          254 :   long i, a = n+2;
    2102          254 :   GEN p = cgetg(a+1, t_POL);
    2103          254 :   p[1] = evalsigne(1)|evalvarn(v);
    2104         2186 :   for (i = 2; i < a; i++) gel(p,i) = pol0_Flx(vT);
    2105          254 :   gel(p,a) = pol1_Flx(vT); return p;
    2106              : }
    2107              : 
    2108              : GEN
    2109          225 : FlxqXQ_minpoly_pre(GEN x, GEN S, GEN T, ulong p, ulong pi)
    2110              : {
    2111          225 :   pari_sp ltop = avma;
    2112              :   long vS, vT, n;
    2113              :   GEN v_x, g, tau;
    2114          225 :   vS = get_FlxqX_var(S);
    2115          225 :   vT = get_Flx_var(T);
    2116          225 :   n = get_FlxqX_degree(S);
    2117          225 :   g = pol1_FlxX(vS,vT);
    2118          225 :   tau = pol1_FlxX(vS,vT);
    2119          225 :   S = FlxqX_get_red_pre(S, T, p, pi);
    2120          225 :   v_x = FlxqXQ_powers_pre(x, usqrt(2*n), S, T, p, pi);
    2121          479 :   while(signe(tau) != 0)
    2122              :   {
    2123              :     long i, j, m, k1;
    2124              :     GEN M, v, tr;
    2125              :     GEN g_prime, c;
    2126          254 :     if (degpol(g) == n) { tau = pol1_FlxX(vS, vT); g = pol1_FlxX(vS, vT); }
    2127          254 :     v = random_FlxqX(n, vS, T, p);
    2128          254 :     tr = FlxqXQ_transmul_init(tau, S, T, p, pi);
    2129          254 :     v = FlxqXQ_transmul(tr, v, n, T, p, pi);
    2130          254 :     m = 2*(n-degpol(g));
    2131          254 :     k1 = usqrt(m);
    2132          254 :     tr = FlxqXQ_transmul_init(gel(v_x,k1+1), S, T, p, pi);
    2133          254 :     c = cgetg(m+2,t_POL);
    2134          254 :     c[1] = evalsigne(1)|evalvarn(vS);
    2135         1077 :     for (i=0; i<m; i+=k1)
    2136              :     {
    2137          823 :       long mj = minss(m-i, k1);
    2138         2755 :       for (j=0; j<mj; j++)
    2139         1932 :         gel(c,m+1-(i+j)) = FlxqX_dotproduct(v, gel(v_x,j+1), T, p);
    2140          823 :       v = FlxqXQ_transmul(tr, v, n, T, p, pi);
    2141              :     }
    2142          254 :     c = FlxX_renormalize(c, m+2);
    2143              :     /* now c contains <v,x^i>, i = 0..m-1  */
    2144          254 :     M = FlxqX_halfgcd_pre(polxn_FlxX(m, vS, vT), c, T, p, pi);
    2145          254 :     g_prime = gmael(M, 2, 2);
    2146          254 :     if (degpol(g_prime) < 1) continue;
    2147          253 :     g = FlxqX_mul_pre(g, g_prime, T, p, pi);
    2148          253 :     tau = FlxqXQ_mul_pre(tau, FlxqX_FlxqXQV_eval_pre(g_prime, v_x, S, T,p,pi),
    2149              :                          S, T, p,pi);
    2150              :   }
    2151          225 :   g = FlxqX_normalize_pre(g,T,p,pi);
    2152          225 :   return gc_GEN(ltop,g);
    2153              : }
    2154              : GEN
    2155           62 : FlxqXQ_minpoly(GEN x, GEN S, GEN T, ulong p)
    2156           62 : { return FlxqXQ_minpoly_pre(x, S, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    2157              : 
    2158              : GEN
    2159            0 : FlxqXQ_matrix_pow(GEN y, long n, long m, GEN S, GEN T, ulong p)
    2160            0 : { return FlxXV_to_FlxM(FlxqXQ_powers(y,m-1,S,T,p), n, get_Flx_var(T)); }
    2161              : 
    2162              : static GEN
    2163       139112 : FlxX_blocks_FlxM(GEN P, long n, long m, long v)
    2164              : {
    2165       139112 :   GEN z = cgetg(m+1,t_MAT);
    2166       139112 :   long i,j, k=2, l = lg(P);
    2167       549361 :   for(i=1; i<=m; i++)
    2168              :   {
    2169       410249 :     GEN zi = cgetg(n+1,t_COL);
    2170       410249 :     gel(z,i) = zi;
    2171      1383145 :     for(j=1; j<=n; j++)
    2172       972896 :       gel(zi, j) = k==l ? pol0_Flx(v) : gel(P,k++);
    2173              :   }
    2174       139112 :   return z;
    2175              : }
    2176              : 
    2177              : GEN
    2178       139112 : FlxqX_FlxqXQV_eval_pre(GEN Q, GEN x, GEN S, GEN T, ulong p, ulong pi)
    2179              : {
    2180       139112 :   pari_sp btop, av = avma;
    2181       139112 :   long v = get_FlxqX_var(S), m = get_FlxqX_degree(S);
    2182       139112 :   long vT = get_Flx_var(T);
    2183       139112 :   long i, l = lg(x)-1, lQ = lgpol(Q), n,  d;
    2184              :   GEN A, B, C, R, g;
    2185       139112 :   if (lQ == 0) return pol_0(v);
    2186       139112 :   if (lQ <= l)
    2187              :   {
    2188        43778 :     n = l;
    2189        43778 :     d = 1;
    2190              :   }
    2191              :   else
    2192              :   {
    2193        95334 :     n = l-1;
    2194        95334 :     d = (lQ+n-1)/n;
    2195              :   }
    2196       139112 :   A = FlxXV_to_FlxM_lg(x, m, n, vT);
    2197       139112 :   B = FlxX_blocks_FlxM(Q, n, d, vT);
    2198       139112 :   C = gc_upto(av, FlxqM_mul(A, B, T, p));
    2199       139112 :   g = gel(x, l);
    2200       139112 :   T = Flx_get_red_pre(T, p, pi);
    2201       139112 :   S = FlxqX_get_red_pre(S, T, p, pi);
    2202       139112 :   btop = avma;
    2203       139112 :   R = FlxV_to_FlxX(gel(C, d), v);
    2204       410249 :   for (i = d-1; i>0; i--)
    2205              :   {
    2206       271137 :     R = FlxX_add(FlxqXQ_mul_pre(R, g, S, T,p,pi), FlxV_to_FlxX(gel(C,i), v), p);
    2207       271137 :     if (gc_needed(btop,1))
    2208            6 :       R = gc_upto(btop, R);
    2209              :   }
    2210       139112 :   return gc_GEN(av, R);
    2211              : }
    2212              : GEN
    2213            0 : FlxqX_FlxqXQV_eval(GEN Q, GEN x, GEN S, GEN T, ulong p)
    2214            0 : { return FlxqX_FlxqXQV_eval_pre(Q,x,S,T,p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    2215              : 
    2216              : GEN
    2217        78081 : FlxqX_FlxqXQ_eval_pre(GEN Q, GEN x, GEN S, GEN T, ulong p, ulong pi)
    2218              : {
    2219        78081 :   pari_sp av = avma;
    2220              :   GEN z, V;
    2221        78081 :   long d = degpol(Q), rtd;
    2222        78081 :   if (d < 0) return pol_0(get_FlxqX_var(S));
    2223        78081 :   rtd = (long) sqrt((double)d);
    2224        78081 :   T = Flx_get_red_pre(T, p, pi);
    2225        78081 :   S = FlxqX_get_red_pre(S, T, p, pi);
    2226        78081 :   V = FlxqXQ_powers_pre(x, rtd, S, T, p, pi);
    2227        78081 :   z = FlxqX_FlxqXQV_eval_pre(Q, V, S, T, p, pi);
    2228        78081 :   return gc_upto(av, z);
    2229              : }
    2230              : GEN
    2231            0 : FlxqX_FlxqXQ_eval(GEN Q, GEN x, GEN S, GEN T, ulong p)
    2232            0 : { return FlxqX_FlxqXQ_eval_pre(Q, x, S, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    2233              : 
    2234              : GEN
    2235            0 : FlxqXC_FlxqXQV_eval_pre(GEN x, GEN v, GEN S, GEN T, ulong p, ulong pi)
    2236            0 : { pari_APPLY_type(t_COL, FlxqX_FlxqXQV_eval_pre(gel(x,i), v, S, T, p, pi)) }
    2237              : GEN
    2238            0 : FlxqXC_FlxqXQV_eval(GEN x, GEN v, GEN S, GEN T, ulong p)
    2239            0 : { return FlxqXC_FlxqXQV_eval_pre(x, v, S, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    2240              : 
    2241              : GEN
    2242            0 : FlxqXC_FlxqXQ_eval(GEN x, GEN F, GEN S, GEN T, ulong p)
    2243              : {
    2244            0 :   long d = brent_kung_optpow(get_FlxqX_degree(S)-1,lg(x)-1,1);
    2245            0 :   ulong pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
    2246            0 :   GEN Fp = FlxqXQ_powers_pre(F, d, S, T, p, pi);
    2247            0 :   return FlxqXC_FlxqXQV_eval_pre(x, Fp, S, T, p, pi);
    2248              : }
    2249              : 
    2250              : static GEN
    2251        73445 : FlxqXQ_autpow_sqr(void * E, GEN x)
    2252              : {
    2253        73445 :   struct _FlxqXQ *D = (struct _FlxqXQ *)E;
    2254        73445 :   GEN S = D->S, T = D->T;
    2255        73445 :   ulong p = D->p, pi = D->pi;
    2256        73445 :   GEN phi = gel(x,1), S1 = gel(x,2);
    2257        73445 :   long n = brent_kung_optpow(get_Flx_degree(T)-1,lgpol(S1)+1,1);
    2258        73445 :   GEN V = Flxq_powers_pre(phi, n, T, p, pi);
    2259        73445 :   GEN phi2 = Flx_FlxqV_eval_pre(phi, V, T, p, pi);
    2260        73445 :   GEN Sphi = FlxY_FlxqV_evalx_pre(S1, V, T, p, pi);
    2261        73445 :   GEN S2 = FlxqX_FlxqXQ_eval_pre(Sphi, S1, S, T, p, pi);
    2262        73445 :   return mkvec2(phi2, S2);
    2263              : }
    2264              : 
    2265              : static GEN
    2266         4274 : FlxqXQ_autpow_mul(void * E, GEN x, GEN y)
    2267              : {
    2268         4274 :   struct _FlxqXQ *D = (struct _FlxqXQ *)E;
    2269         4274 :   GEN S = D->S, T = D->T;
    2270         4274 :   ulong p = D->p, pi = D->pi;
    2271         4274 :   GEN phi1 = gel(x,1), S1 = gel(x,2);
    2272         4274 :   GEN phi2 = gel(y,1), S2 = gel(y,2);
    2273         4274 :   long n = brent_kung_optpow(get_Flx_degree(T)-1,lgpol(S1)+1,1);
    2274         4274 :   GEN V = Flxq_powers_pre(phi2, n, T, p, pi);
    2275         4274 :   GEN phi3 = Flx_FlxqV_eval_pre(phi1, V, T, p, pi);
    2276         4274 :   GEN Sphi = FlxY_FlxqV_evalx_pre(S1, V, T, p, pi);
    2277         4274 :   GEN S3 = FlxqX_FlxqXQ_eval_pre(Sphi, S2, S, T, p, pi);
    2278         4274 :   return mkvec2(phi3, S3);
    2279              : }
    2280              : 
    2281              : GEN
    2282        69996 : FlxqXQ_autpow_pre(GEN aut, long n, GEN S, GEN T, ulong p, ulong pi)
    2283              : {
    2284        69996 :   pari_sp av = avma;
    2285              :   struct _FlxqXQ D;
    2286        69996 :   T = Flx_get_red_pre(T, p, pi);
    2287        69996 :   S = FlxqX_get_red_pre(S, T, p, pi);
    2288        69996 :   D.S = S; D.T = T; D.p = p; D.pi = pi;
    2289        69996 :   aut = gen_powu_i(aut,n,&D,FlxqXQ_autpow_sqr,FlxqXQ_autpow_mul);
    2290        69996 :   return gc_GEN(av, aut);
    2291              : }
    2292              : GEN
    2293            0 : FlxqXQ_autpow(GEN aut, long n, GEN S, GEN T, ulong p)
    2294            0 : { return FlxqXQ_autpow_pre(aut, n, S, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    2295              : 
    2296              : static GEN
    2297        29759 : FlxqXQ_autsum_mul(void *E, GEN x, GEN y)
    2298              : {
    2299        29759 :   struct _FlxqXQ *D = (struct _FlxqXQ *)E;
    2300        29759 :   GEN S = D->S, T = D->T;
    2301        29759 :   ulong p = D->p, pi = D->pi;
    2302        29759 :   GEN phi1 = gel(x,1), S1 = gel(x,2), a1 = gel(x,3);
    2303        29759 :   GEN phi2 = gel(y,1), S2 = gel(y,2), a2 = gel(y,3);
    2304        29759 :   long n2 = brent_kung_optpow(get_Flx_degree(T)-1, lgpol(S1)+lgpol(a1)+1,1);
    2305        29759 :   GEN V2 = Flxq_powers_pre(phi2, n2, T, p, pi);
    2306        29759 :   GEN phi3 = Flx_FlxqV_eval_pre(phi1, V2, T, p, pi);
    2307        29759 :   GEN Sphi = FlxY_FlxqV_evalx_pre(S1, V2, T, p, pi);
    2308        29759 :   GEN aphi = FlxY_FlxqV_evalx_pre(a1, V2, T, p, pi);
    2309        29759 :   long n = brent_kung_optpow(maxss(degpol(Sphi),degpol(aphi)),2,1);
    2310        29759 :   GEN V = FlxqXQ_powers_pre(S2, n, S, T, p, pi);
    2311        29759 :   GEN S3 = FlxqX_FlxqXQV_eval_pre(Sphi, V, S, T, p, pi);
    2312        29759 :   GEN aS = FlxqX_FlxqXQV_eval_pre(aphi, V, S, T, p, pi);
    2313        29759 :   GEN a3 = FlxqXQ_mul_pre(aS, a2, S, T, p, pi);
    2314        29759 :   return mkvec3(phi3, S3, a3);
    2315              : }
    2316              : 
    2317              : static GEN
    2318        18401 : FlxqXQ_autsum_sqr(void * T, GEN x)
    2319        18401 : { return FlxqXQ_autsum_mul(T, x, x); }
    2320              : 
    2321              : GEN
    2322        12110 : FlxqXQ_autsum_pre(GEN aut, long n, GEN S, GEN T, ulong p, ulong pi)
    2323              : {
    2324        12110 :   pari_sp av = avma;
    2325              :   struct _FlxqXQ D;
    2326        12110 :   T = Flx_get_red_pre(T, p, pi);
    2327        12110 :   S = FlxqX_get_red_pre(S, T, p, pi);
    2328        12110 :   D.S=S; D.T=T; D.p=p; D.pi=pi;
    2329        12110 :   aut = gen_powu_i(aut,n,&D,FlxqXQ_autsum_sqr,FlxqXQ_autsum_mul);
    2330        12110 :   return gc_GEN(av, aut);
    2331              : }
    2332              : GEN
    2333            0 : FlxqXQ_autsum(GEN aut, long n, GEN S, GEN T, ulong p)
    2334            0 : { return FlxqXQ_autsum_pre(aut, n, S, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    2335              : 
    2336              : static GEN
    2337           27 : FlxqXQ_auttrace_mul(void *E, GEN x, GEN y)
    2338              : {
    2339           27 :   struct _FlxqXQ *D = (struct _FlxqXQ *)E;
    2340           27 :   GEN S = D->S, T = D->T;
    2341           27 :   ulong p = D->p, pi = D->pi;
    2342           27 :   GEN S1 = gel(x,1), a1 = gel(x,2);
    2343           27 :   GEN S2 = gel(y,1), a2 = gel(y,2);
    2344           27 :   long n = brent_kung_optpow(maxss(degpol(S1),degpol(a1)),2,1);
    2345           27 :   GEN V = FlxqXQ_powers_pre(S2, n, S, T, p, pi);
    2346           27 :   GEN S3 = FlxqX_FlxqXQV_eval_pre(S1, V, S, T, p, pi);
    2347           27 :   GEN aS = FlxqX_FlxqXQV_eval_pre(a1, V, S, T, p, pi);
    2348           27 :   GEN a3 = FlxX_add(aS, a2, p);
    2349           27 :   return mkvec2(S3, a3);
    2350              : }
    2351              : 
    2352              : static GEN
    2353           20 : FlxqXQ_auttrace_sqr(void *E, GEN x)
    2354           20 : { return FlxqXQ_auttrace_mul(E, x, x); }
    2355              : 
    2356              : GEN
    2357          338 : FlxqXQ_auttrace_pre(GEN x, ulong n, GEN S, GEN T, ulong p, ulong pi)
    2358              : {
    2359          338 :   pari_sp av = avma;
    2360              :   struct _FlxqXQ D;
    2361          338 :   T = Flx_get_red_pre(T, p, pi);
    2362          338 :   S = FlxqX_get_red_pre(S, T, p, pi);
    2363          338 :   D.S=S; D.T=T; D.p=p; D.pi = pi;
    2364          338 :   x = gen_powu_i(x,n,(void*)&D,FlxqXQ_auttrace_sqr,FlxqXQ_auttrace_mul);
    2365          338 :   return gc_GEN(av, x);
    2366              : }
    2367              : GEN
    2368            0 : FlxqXQ_auttrace(GEN x, ulong n, GEN S, GEN T, ulong p)
    2369            0 : { return FlxqXQ_auttrace_pre(x, n, S, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    2370              : 
    2371              : /*******************************************************************/
    2372              : /*                                                                 */
    2373              : /*                      FlxYqQ                                     */
    2374              : /*                                                                 */
    2375              : /*******************************************************************/
    2376              : 
    2377              : /*Preliminary implementation to speed up FpX_ffisom*/
    2378              : typedef struct {
    2379              :   GEN S, T;
    2380              :   ulong p, pi;
    2381              : } FlxYqq_muldata;
    2382              : 
    2383              : /* reduce x in Fl[X, Y] in the algebra Fl[X, Y]/ (P(X),Q(Y)) */
    2384              : static GEN
    2385        90960 : FlxYqq_redswap(GEN x, GEN S, GEN T, ulong p, ulong pi)
    2386              : {
    2387        90960 :   pari_sp ltop=avma;
    2388        90960 :   long n = get_Flx_degree(S);
    2389        90960 :   long m = get_Flx_degree(T);
    2390        90960 :   long w = get_Flx_var(T);
    2391        90960 :   GEN V = FlxX_swap(x,m,w);
    2392        90960 :   V = FlxqX_red_pre(V,S,p,pi);
    2393        90960 :   V = FlxX_swap(V,n,w);
    2394        90960 :   return gc_GEN(ltop,V);
    2395              : }
    2396              : static GEN
    2397        80554 : FlxYqq_sqr(void *data, GEN x)
    2398              : {
    2399        80554 :   FlxYqq_muldata *D = (FlxYqq_muldata*)data;
    2400        80554 :   return FlxYqq_redswap(FlxqX_sqr_pre(x,D->T,D->p,D->pi),D->S,D->T,D->p,D->pi);
    2401              : }
    2402              : 
    2403              : static GEN
    2404        10406 : FlxYqq_mul(void *data, GEN x, GEN y)
    2405              : {
    2406        10406 :   FlxYqq_muldata *D = (FlxYqq_muldata*)data;
    2407        10406 :   return FlxYqq_redswap(FlxqX_mul_pre(x,y, D->T,D->p,D->pi),D->S,D->T,D->p,D->pi);
    2408              : }
    2409              : 
    2410              : /* x in Z[X,Y], S in Z[X] over Fq = Z[Y]/(p,T); compute lift(x^n mod (S,T,p)) */
    2411              : GEN
    2412        39264 : FlxYqq_pow(GEN x, GEN n, GEN S, GEN T, ulong p)
    2413              : {
    2414              :   FlxYqq_muldata D;
    2415        39264 :   D.S = S; D.T = T; D.p = p; D.pi = SMALL_ULONG(p)? 0: get_Fl_red(p);
    2416        39264 :   return gen_pow(x, n, (void*)&D, &FlxYqq_sqr, &FlxYqq_mul);
    2417              : }
    2418              : 
    2419              : /*******************************************************************/
    2420              : /*                                                                 */
    2421              : /*                      FlxqXn                                     */
    2422              : /*                                                                 */
    2423              : /*******************************************************************/
    2424              : 
    2425              : GEN
    2426        66188 : FlxXn_red(GEN a, long n)
    2427              : {
    2428        66188 :   long i, L = n+2, l = lg(a);
    2429              :   GEN  b;
    2430        66188 :   if (L >= l) return a; /* deg(x) < n */
    2431        36749 :   b = cgetg(L, t_POL); b[1] = a[1];
    2432       392028 :   for (i=2; i<L; i++) gel(b,i) = gel(a,i);
    2433        36749 :   return FlxX_renormalize(b,L);
    2434              : }
    2435              : 
    2436              : GEN
    2437        40420 : FlxqXn_mul_pre(GEN a, GEN b, long n, GEN T, ulong p, ulong pi)
    2438        40420 : { return FlxXn_red(FlxqX_mul_pre(a, b, T, p, pi), n); }
    2439              : GEN
    2440            0 : FlxqXn_mul(GEN a, GEN b, long n, GEN T, ulong p)
    2441            0 : { return FlxqXn_mul_pre(a, b, n, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    2442              : 
    2443              : GEN
    2444            0 : FlxqXn_sqr_pre(GEN a, long n, GEN T, ulong p, ulong pi)
    2445            0 : { return FlxXn_red(FlxqX_sqr_pre(a, T, p, pi), n); }
    2446              : GEN
    2447            0 : FlxqXn_sqr(GEN a, long n, GEN T, ulong p)
    2448            0 : { return FlxqXn_sqr_pre(a, n, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    2449              : 
    2450              : /* (f*g) \/ x^n */
    2451              : static GEN
    2452        18000 : FlxqX_mulhigh_i(GEN f, GEN g, long n, GEN T, ulong p, ulong pi)
    2453        18000 : { return FlxX_shift(FlxqX_mul_pre(f, g, T, p, pi), -n, get_Flx_var(T)); }
    2454              : 
    2455              : static GEN
    2456        13196 : FlxqXn_mulhigh(GEN f, GEN g, long n2, long n, GEN T, ulong p, ulong pi)
    2457              : {
    2458        13196 :   long vT = get_Flx_var(T);
    2459        13196 :   GEN F = FlxX_blocks(f, n2, 2, vT), fl = gel(F,1), fh = gel(F,2);
    2460        13196 :   return FlxX_add(FlxqX_mulhigh_i(fl, g, n2, T, p, pi),
    2461              :                   FlxqXn_mul_pre(fh, g, n - n2, T, p, pi), p);
    2462              : }
    2463              : 
    2464              : GEN
    2465         2432 : FlxqXn_div_pre(GEN g, GEN f, long e, GEN T, ulong p, ulong pi)
    2466              : {
    2467         2432 :   pari_sp av = avma, av2;
    2468              :   ulong mask;
    2469              :   GEN W, a;
    2470         2432 :   long v = varn(f), n = 1, vT = get_Flx_var(T);
    2471              : 
    2472         2432 :   if (!signe(f)) pari_err_INV("FlxqXn_inv",f);
    2473         2432 :   a = Flxq_inv_pre(gel(f,2), T, p, pi);
    2474         2432 :   if (e == 1 && !g) return scalarpol(a, v);
    2475         2432 :   else if (e == 2 && !g)
    2476              :   {
    2477              :     GEN b;
    2478            0 :     if (degpol(f) <= 0) return scalarpol(a, v);
    2479            0 :     b = Flx_neg(gel(f,3), p);
    2480            0 :     if (lgpol(b)==0) return scalarpol(a, v);
    2481            0 :     b = Flxq_mul_pre(b, Flxq_sqr_pre(a, T, p, pi), T, p, pi);
    2482            0 :     W = deg1pol_shallow(b, a, v);
    2483            0 :     return gc_GEN(av, W);
    2484              :   }
    2485         2432 :   W = scalarpol_shallow(Flxq_inv_pre(gel(f,2), T, p, pi), v);
    2486         2432 :   mask = quadratic_prec_mask(e);
    2487         2432 :   av2 = avma;
    2488        12040 :   for (;mask>1;)
    2489              :   {
    2490              :     GEN u, fr;
    2491         9608 :     long n2 = n;
    2492         9608 :     n<<=1; if (mask & 1) n--;
    2493         9608 :     mask >>= 1;
    2494         9608 :     fr = FlxXn_red(f, n);
    2495         9608 :     if (mask>1 || !g)
    2496              :     {
    2497         9608 :       u = FlxqXn_mul_pre(W, FlxqXn_mulhigh(fr, W, n2, n, T, p, pi), n-n2, T, p, pi);
    2498         9608 :       W = FlxX_sub(W, FlxX_shift(u, n2, vT), p);
    2499              :     }
    2500              :     else
    2501              :     {
    2502            0 :       GEN y = FlxqXn_mul_pre(g, W, n, T, p, pi), yt =  FlxXn_red(y, n-n2);
    2503            0 :       u = FlxqXn_mul_pre(yt, FlxqXn_mulhigh(fr,  W, n2, n, T, p, pi), n-n2, T, p, pi);
    2504            0 :       W = FlxX_sub(y, FlxX_shift(u, n2, vT), p);
    2505              :     }
    2506         9608 :     if (gc_needed(av2,2))
    2507              :     {
    2508            0 :       if(DEBUGMEM>1) pari_warn(warnmem,"FlxqXn_inv, e = %ld", n);
    2509            0 :       W = gc_upto(av2, W);
    2510              :     }
    2511              :   }
    2512         2432 :   return gc_upto(av, W);
    2513              : }
    2514              : 
    2515              : GEN
    2516            0 : FlxqXn_div(GEN f, GEN g, long e, GEN T, ulong p)
    2517            0 : { return FlxqXn_div_pre(f, g, e, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    2518              : 
    2519              : GEN
    2520         2432 : FlxqXn_inv_pre(GEN f, long e, GEN T, ulong p, ulong pi)
    2521         2432 : { return FlxqXn_div_pre(NULL, f, e, T, p, pi); }
    2522              : 
    2523              : GEN
    2524            0 : FlxqXn_inv(GEN f, long e, GEN T, ulong p)
    2525            0 : { return FlxqXn_div_pre(NULL, f, e, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
    2526              : 
    2527              : /* Compute intformal(x^n*S)/x^(n+1) */
    2528              : static GEN
    2529         4804 : FlxX_integXn(GEN x, long n, ulong p)
    2530              : {
    2531         4804 :   long i, lx = lg(x);
    2532              :   GEN y;
    2533         4804 :   if (lx == 2) return gcopy(x);
    2534         3998 :   y = cgetg(lx, t_POL); y[1] = x[1];
    2535        26760 :   for (i=2; i<lx; i++)
    2536              :   {
    2537        22762 :     GEN xi = gel(x,i);
    2538        22762 :     gel(y,i) = Flx_Fl_mul(xi, Fl_inv((n+i-1)%p, p), p);
    2539              :   }
    2540         3998 :   return FlxX_renormalize(y, lx);;
    2541              : }
    2542              : 
    2543              : GEN
    2544         1216 : FlxqXn_expint_pre(GEN h, long e, GEN T, ulong p, ulong pi)
    2545              : {
    2546         1216 :   pari_sp av = avma, av2;
    2547         1216 :   long v = varn(h), n = 1, vT = get_Flx_var(T);
    2548         1216 :   GEN f = pol1_FlxX(v, vT), g = pol1_FlxX(v, vT);
    2549         1216 :   ulong mask = quadratic_prec_mask(e);
    2550         1216 :   av2 = avma;
    2551         4804 :   for (;mask>1;)
    2552              :   {
    2553              :     GEN u, w;
    2554         4804 :     long n2 = n;
    2555         4804 :     n<<=1; if (mask & 1) n--;
    2556         4804 :     mask >>= 1;
    2557         4804 :     u = FlxqXn_mul_pre(g, FlxqX_mulhigh_i(f, FlxXn_red(h, n2-1), n2-1, T,p,pi), n-n2, T,p,pi);
    2558         4804 :     u = FlxX_add(u, FlxX_shift(FlxXn_red(h, n-1), 1-n2, vT), p);
    2559         4804 :     w = FlxqXn_mul_pre(f, FlxX_integXn(u, n2-1, p), n-n2, T, p, pi);
    2560         4804 :     f = FlxX_add(f, FlxX_shift(w, n2, vT), p);
    2561         4804 :     if (mask<=1) break;
    2562         3588 :     u = FlxqXn_mul_pre(g, FlxqXn_mulhigh(f, g, n2, n, T,p,pi), n-n2, T,p,pi);
    2563         3588 :     g = FlxX_sub(g, FlxX_shift(u, n2, vT), p);
    2564         3588 :     if (gc_needed(av2,2))
    2565              :     {
    2566            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"FlxqXn_exp, e = %ld", n);
    2567            0 :       (void)gc_all(av2, 2, &f, &g);
    2568              :     }
    2569              :   }
    2570         1216 :   return gc_upto(av, f);
    2571              : }
    2572              : GEN
    2573            0 : FlxqXn_expint(GEN h, long e, GEN T, ulong p)
    2574            0 : { return FlxqXn_expint_pre(h, e, T, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
        

Generated by: LCOV version 2.0-1