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 - F2x.c (source / functions) Coverage Total Hit
Test: PARI/GP v2.18.1 lcov report (development 31053-95e3b72995) Lines: 83.5 % 1838 1534
Test Date: 2026-07-24 17:03:07 Functions: 89.3 % 214 191
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Copyright (C) 2007  The PARI group.
       2              : 
       3              : This file is part of the PARI/GP package.
       4              : 
       5              : PARI/GP is free software; you can redistribute it and/or modify it under the
       6              : terms of the GNU General Public License as published by the Free Software
       7              : Foundation; either version 2 of the License, or (at your option) any later
       8              : version. It is distributed in the hope that it will be useful, but WITHOUT
       9              : ANY WARRANTY WHATSOEVER.
      10              : 
      11              : Check the License for details. You should have received a copy of it, along
      12              : with the package; see the file 'COPYING'. If not, write to the Free Software
      13              : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      14              : 
      15              : #include "pari.h"
      16              : #include "paripriv.h"
      17              : 
      18              : #define DEBUGLEVEL DEBUGLEVEL_fflog
      19              : 
      20              : /* Not so fast arithmetic with polynomials over F_2 */
      21              : 
      22              : /***********************************************************************/
      23              : /**                                                                   **/
      24              : /**                             F2x                                   **/
      25              : /**                                                                   **/
      26              : /***********************************************************************/
      27              : /* F2x objects are defined as follows:
      28              :    An F2x is a t_VECSMALL:
      29              :    x[0] = codeword
      30              :    x[1] = evalvarn(variable number)  (signe is not stored).
      31              :    x[2] = a_0...a_31 x[3] = a_32..a_63, etc.  on 32bit
      32              :    x[2] = a_0...a_63 x[3] = a_64..a_127, etc. on 64bit
      33              : 
      34              :    where the a_i are bits.
      35              : 
      36              :    signe(x) is not valid. Use lgpol(x)!=0 instead.
      37              :    Note: pol0_F2x=pol0_Flx and pol1_F2x=pol1_Flx
      38              : */
      39              : 
      40              : INLINE long
      41          264 : F2x_degreespec(GEN x, long l)
      42              : {
      43          264 :   return (l==0)?-1:l*BITS_IN_LONG-bfffo(x[l-1])-1;
      44              : }
      45              : 
      46              : INLINE long
      47    287156518 : F2x_degree_lg(GEN x, long l)
      48              : {
      49    287156518 :   return (l==2)?-1:bit_accuracy(l)-bfffo(x[l-1])-1;
      50              : }
      51              : 
      52              : long
      53     87954256 : F2x_degree(GEN x)
      54              : {
      55     87954256 :   return F2x_degree_lg(x, lg(x));
      56              : }
      57              : 
      58              : GEN
      59         2751 : monomial_F2x(long d, long vs)
      60              : {
      61         2751 :   long l=nbits2lg(d+1);
      62         2751 :   GEN z = zero_zv(l-1);
      63         2751 :   z[1] = vs;
      64         2751 :   F2x_set(z,d);
      65         2751 :   return z;
      66              : }
      67              : 
      68              : GEN
      69      1536921 : F2x_to_ZX(GEN x)
      70              : {
      71      1536921 :   long l = 3+F2x_degree(x), lx = lg(x);
      72      1536921 :   GEN z = cgetg(l,t_POL);
      73              :   long i, j, k;
      74      3071845 :   for (i=2, k=2; i<lx; i++)
      75      6020501 :     for (j=0; j<BITS_IN_LONG && k<l; j++,k++)
      76      4485577 :       gel(z,k) = (x[i]&(1UL<<j))?gen_1:gen_0;
      77      1536921 :   z[1]=evalsigne(l>=3)|x[1];
      78      1536921 :   return z;
      79              : }
      80              : 
      81              : GEN
      82       133032 : F2x_to_Flx(GEN x)
      83              : {
      84       133032 :   long l = 3+F2x_degree(x), lx = lg(x);
      85       133032 :   GEN z = cgetg(l,t_VECSMALL);
      86              :   long i, j, k;
      87       133032 :   z[1] = x[1];
      88       298634 :   for (i=2, k=2; i<lx; i++)
      89      4553894 :     for (j=0; j<BITS_IN_LONG && k<l; j++,k++)
      90      4388292 :       z[k] = (x[i]>>j)&1UL;
      91       133032 :   return z;
      92              : }
      93              : 
      94              : GEN
      95          378 : F2x_to_F2xX(GEN z, long sv)
      96              : {
      97          378 :   long i, d = F2x_degree(z);
      98          378 :   GEN x = cgetg(d+3,t_POL);
      99         6769 :   for (i=0; i<=d; i++)
     100         6391 :     gel(x,i+2) = F2x_coeff(z,i) ? pol1_F2x(sv): pol0_F2x(sv);
     101          378 :   x[1] = evalsigne(d+1!=0)| z[1]; return x;
     102              : }
     103              : 
     104              : GEN
     105       213618 : Z_to_F2x(GEN x, long sv)
     106              : {
     107       213618 :   return mpodd(x) ? pol1_F2x(sv): pol0_F2x(sv);
     108              : }
     109              : 
     110              : GEN
     111      3168710 : ZX_to_F2x(GEN x)
     112              : {
     113      3168710 :   long lx = lg(x), l = nbits2lg(lx-2);
     114      3168710 :   GEN z = cgetg(l,t_VECSMALL);
     115              :   long i, j, k;
     116      3168710 :   z[1] = ((ulong)x[1])&VARNBITS;
     117     11324389 :   for (i=2, k=1,j=BITS_IN_LONG; i<lx; i++,j++)
     118              :   {
     119      8155679 :     if (j==BITS_IN_LONG)
     120              :     {
     121      3149289 :       j=0; z[++k]=0;
     122              :     }
     123      8155679 :     if (mpodd(gel(x,i)))
     124      6130509 :       z[k] |= 1UL<<j;
     125              :   }
     126      3168710 :   return F2x_renormalize(z,l);
     127              : }
     128              : 
     129              : GEN
     130       157398 : Flx_to_F2x(GEN x)
     131              : {
     132       157398 :   long lx = lg(x), l = nbits2lg(lx-2);
     133       157398 :   GEN z = cgetg(l,t_VECSMALL);
     134              :   long i, j, k;
     135       157398 :   z[1] = x[1];
     136      4762905 :   for (i=2, k=1, j=BITS_IN_LONG; i<lx; i++,j++)
     137              :   {
     138      4605507 :     if (j==BITS_IN_LONG)
     139              :     {
     140       183878 :       j=0; z[++k] = 0;
     141              :     }
     142      4605507 :     if (x[i]&1UL)
     143      2360432 :       z[k] |= 1UL<<j;
     144              :   }
     145       157398 :   return F2x_renormalize(z,l);
     146              : }
     147              : 
     148              : GEN
     149      1563825 : F2x_to_F2v(GEN x, long N)
     150              : {
     151      1563825 :   long i, l = lg(x);
     152      1563825 :   long n = nbits2lg(N);
     153      1563825 :   GEN z = cgetg(n,t_VECSMALL);
     154      1563825 :   z[1] = N;
     155      3357802 :   for (i=2; i<l ; i++) z[i]=x[i];
     156      1656257 :   for (   ; i<n; i++) z[i]=0;
     157      1563825 :   return z;
     158              : }
     159              : 
     160              : GEN
     161         3087 : RgX_to_F2x(GEN x)
     162              : {
     163         3087 :   long l=nbits2lg(lgpol(x));
     164         3087 :   GEN z=cgetg(l,t_VECSMALL);
     165              :   long i,j,k;
     166         3087 :   z[1]=((ulong)x[1])&VARNBITS;
     167         8883 :   for(i=2, k=1,j=BITS_IN_LONG;i<lg(x);i++,j++)
     168              :   {
     169         5796 :     if (j==BITS_IN_LONG)
     170              :     {
     171         2198 :       j=0; k++; z[k]=0;
     172              :     }
     173         5796 :     if (Rg_to_F2(gel(x,i)))
     174         3248 :       z[k]|=1UL<<j;
     175              :   }
     176         3087 :   return F2x_renormalize(z,l);
     177              : }
     178              : 
     179              : /* If x is a POLMOD, assume modulus is a multiple of T. */
     180              : GEN
     181       801164 : Rg_to_F2xq(GEN x, GEN T)
     182              : {
     183       801164 :   long ta, tx = typ(x), v = get_F2x_var(T);
     184              :   GEN a, b;
     185       801164 :   if (is_const_t(tx))
     186              :   {
     187       798910 :     if (tx == t_FFELT) return FF_to_F2xq(x);
     188       249103 :     return Rg_to_F2(x)? pol1_F2x(v): pol0_F2x(v);
     189              :   }
     190         2254 :   switch(tx)
     191              :   {
     192            0 :     case t_POLMOD:
     193            0 :       b = gel(x,1);
     194            0 :       a = gel(x,2); ta = typ(a);
     195            0 :       if (is_const_t(ta)) return Rg_to_F2(a)? pol1_F2x(v): pol0_F2x(v);
     196            0 :       b = RgX_to_F2x(b); if (b[1] != v) break;
     197            0 :       a = RgX_to_F2x(a); if (F2x_equal(b,T)) return a;
     198            0 :       if (lgpol(F2x_rem(b,T))==0) return F2x_rem(a, T);
     199            0 :       break;
     200         2254 :     case t_POL:
     201         2254 :       x = RgX_to_F2x(x);
     202         2254 :       if (x[1] != v) break;
     203         2254 :       return F2x_rem(x, T);
     204            0 :     case t_RFRAC:
     205            0 :       a = Rg_to_F2xq(gel(x,1), T);
     206            0 :       b = Rg_to_F2xq(gel(x,2), T);
     207            0 :       return F2xq_div(a,b, T);
     208              :   }
     209            0 :   pari_err_TYPE("Rg_to_F2xq",x);
     210              :   return NULL; /* LCOV_EXCL_LINE */
     211              : }
     212              : 
     213              : ulong
     214        14350 : F2x_eval(GEN P, ulong x)
     215              : {
     216        14350 :   if (lgpol(P)==0) return 0;
     217        10674 :   if (odd(x))
     218              :   {
     219         3313 :     long i, lP = lg(P);
     220         3313 :     ulong c = 0;
     221         6626 :     for (i=2; i<lP; i++)
     222         3313 :       c ^= P[i];
     223         3313 :     return thuemorseu(c);
     224              :   }
     225         7361 :   else return F2x_coeff(P,0);
     226              : }
     227              : 
     228              : GEN
     229     41374721 : F2x_add(GEN x, GEN y)
     230              : {
     231              :   long i,lz;
     232              :   GEN z;
     233     41374721 :   long lx=lg(x);
     234     41374721 :   long ly=lg(y);
     235     41374721 :   if (ly>lx) swapspec(x,y, lx,ly);
     236     41374721 :   lz = lx; z = cgetg(lz, t_VECSMALL); z[1]=x[1];
     237     74475358 :   for (i=2; i<ly; i++) z[i] = x[i]^y[i];
     238     55957495 :   for (   ; i<lx; i++) z[i] = x[i];
     239     41374721 :   return F2x_renormalize(z, lz);
     240              : }
     241              : 
     242              : static GEN
     243        73287 : F2x_addspec(GEN x, GEN y, long lx, long ly)
     244              : {
     245              :   long i,lz;
     246              :   GEN z;
     247              : 
     248        73287 :   if (ly>lx) swapspec(x,y, lx,ly);
     249        73287 :   lz = lx+2; z = cgetg(lz, t_VECSMALL) + 2;
     250       205589 :   for (i=0; i<ly-3; i+=4)
     251              :   {
     252       132302 :     z[i] = x[i]^y[i];
     253       132302 :     z[i+1] = x[i+1]^y[i+1];
     254       132302 :     z[i+2] = x[i+2]^y[i+2];
     255       132302 :     z[i+3] = x[i+3]^y[i+3];
     256              :   }
     257       132603 :   for (; i<ly; i++)
     258        59316 :     z[i] = x[i]^y[i];
     259       631504 :   for (   ; i<lx; i++) z[i] = x[i];
     260        73287 :   z -= 2; z[1] = 0; return F2x_renormalize(z, lz);
     261              : }
     262              : 
     263              : GEN
     264       190463 : F2x_1_add(GEN y)
     265              : {
     266              :   GEN z;
     267              :   long lz, i;
     268       190463 :   if (!lgpol(y))
     269        90418 :     return pol1_F2x(y[1]);
     270       100045 :   lz=lg(y);
     271       100045 :   z=cgetg(lz,t_VECSMALL);
     272       100045 :   z[1] = y[1];
     273       100045 :   z[2] = y[2]^1UL;
     274       100045 :   for(i=3;i<lz;i++)
     275            0 :     z[i] = y[i];
     276       100045 :   if (lz==3) z = F2x_renormalize(z,lz);
     277       100045 :   return z;
     278              : }
     279              : 
     280              : INLINE void
     281    167429012 : F2x_addshiftipspec(GEN x, GEN y, long ny, ulong db)
     282              : {
     283              :   long i;
     284    167429012 :   if (db)
     285              :   {
     286    141394513 :     ulong dc=BITS_IN_LONG-db;
     287    141394513 :     ulong r=0, yi;
     288    218014909 :     for(i=0; i<ny-3; i+=4)
     289              :     {
     290     76620396 :       yi = uel(y,i);   x[i]   ^= (yi<<db)|r; r = yi>>dc;
     291     76620396 :       yi = uel(y,i+1); x[i+1] ^= (yi<<db)|r; r = yi>>dc;
     292     76620396 :       yi = uel(y,i+2); x[i+2] ^= (yi<<db)|r; r = yi>>dc;
     293     76620396 :       yi = uel(y,i+3); x[i+3] ^= (yi<<db)|r; r = yi>>dc;
     294              :     }
     295    278979410 :     for(  ; i<ny; i++)
     296              :     {
     297    137584897 :       ulong yi = uel(y,i); x[i] ^= (yi<<db)|r; r = yi>>dc;
     298              :     }
     299    141394513 :     if (r) x[i] ^= r;
     300              :   }
     301              :   else
     302              :   {
     303     28672270 :     for(i=0; i<ny-3; i+=4)
     304              :     {
     305      2637771 :       x[i]   ^= y[i];
     306      2637771 :       x[i+1] ^= y[i+1];
     307      2637771 :       x[i+2] ^= y[i+2];
     308      2637771 :       x[i+3] ^= y[i+3];
     309              :     }
     310     53900049 :     for(   ; i<ny; i++)
     311     27865550 :       x[i] ^= y[i];
     312              :   }
     313    167429012 : }
     314              : 
     315              : INLINE void
     316    140799562 : F2x_addshiftip(GEN x, GEN y, ulong d)
     317              : {
     318    140799562 :   ulong db, dl=dvmduBIL(d, &db);
     319    140799562 :   F2x_addshiftipspec(x+2+dl, y+2, lgpol(y), db);
     320    140799562 : }
     321              : 
     322              : static GEN
     323     24367929 : F2x_mul1(ulong x, ulong y)
     324              : {
     325     24367929 :   ulong x1=(x&HIGHMASK)>>BITS_IN_HALFULONG;
     326     24367929 :   ulong x2=x&LOWMASK;
     327     24367929 :   ulong y1=(y&HIGHMASK)>>BITS_IN_HALFULONG;
     328     24367929 :   ulong y2=y&LOWMASK;
     329              :   ulong r1,r2,rr;
     330              :   GEN z;
     331              :   ulong i;
     332     24367929 :   rr=r1=r2=0UL;
     333     24367929 :   if (x2)
     334    749325159 :     for(i=0;i<BITS_IN_HALFULONG;i++)
     335    724996288 :       if (x2&(1UL<<i))
     336              :       {
     337     63351161 :         r2^=y2<<i;
     338     63351161 :         rr^=y1<<i;
     339              :       }
     340     24367929 :   if (x1)
     341      3465387 :     for(i=0;i<BITS_IN_HALFULONG;i++)
     342      3344416 :       if (x1&(1UL<<i))
     343              :       {
     344       913005 :         r1^=y1<<i;
     345       913005 :         rr^=y2<<i;
     346              :       }
     347     24367929 :   r2^=(rr&LOWMASK)<<BITS_IN_HALFULONG;
     348     24367929 :   r1^=(rr&HIGHMASK)>>BITS_IN_HALFULONG;
     349     24367929 :   z=cgetg((r1?4:3),t_VECSMALL);
     350     24367929 :   z[2]=r2;
     351     24367929 :   if (r1) z[3]=r1;
     352     24367929 :   return z;
     353              : }
     354              : 
     355              : static GEN
     356      3350029 : F2x_mulspec_basecase(GEN x, GEN y, long nx, long ny)
     357              : {
     358              :   long l, i, j;
     359              :   GEN z;
     360      3350029 :   l = nx + ny;
     361      3350029 :   z = zero_Flv(l+1);
     362      3957480 :   for(i=0; i < ny-1; i++)
     363              :   {
     364       607451 :     GEN zi = z+2+i;
     365       607451 :     ulong yi = uel(y,i);
     366       607451 :     if (yi)
     367     33390211 :       for(j=0; j < BITS_IN_LONG; j++)
     368     32782944 :         if (yi&(1UL<<j)) F2x_addshiftipspec(zi,x,nx,j);
     369              :   }
     370              :   {
     371      3350029 :     GEN zi = z+2+i;
     372      3350029 :     ulong yi = uel(y,i);
     373      3350029 :     long c = BITS_IN_LONG-bfffo(yi);
     374     24713079 :     for(j=0; j < c; j++)
     375     21363050 :       if (yi&(1UL<<j)) F2x_addshiftipspec(zi,x,nx,j);
     376              :   }
     377      3350029 :   return F2x_renormalize(z, l+2);
     378              : }
     379              : 
     380              : static GEN
     381        46908 : F2x_addshift(GEN x, GEN y, long d)
     382              : {
     383        46908 :   GEN xd,yd,zd = (GEN)avma;
     384        46908 :   long a,lz,ny = lgpol(y), nx = lgpol(x);
     385        46908 :   long vs = x[1];
     386        46908 :   if (nx == 0) return y;
     387        46908 :   x += 2; y += 2; a = ny-d;
     388        46908 :   if (a <= 0)
     389              :   {
     390         3255 :     lz = (a>nx)? ny+2: nx+d+2;
     391         3255 :     (void)new_chunk(lz); xd = x+nx; yd = y+ny;
     392        37981 :     while (xd > x) *--zd = *--xd;
     393         3255 :     x = zd + a;
     394         4577 :     while (zd > x) *--zd = 0;
     395              :   }
     396              :   else
     397              :   {
     398        43653 :     xd = new_chunk(d); yd = y+d;
     399        43653 :     x = F2x_addspec(x,yd,nx,a);
     400        43653 :     lz = (a>nx)? ny+2: lg(x)+d;
     401       895711 :     x += 2; while (xd > x) *--zd = *--xd;
     402              :   }
     403       525815 :   while (yd > y) *--zd = *--yd;
     404        46908 :   *--zd = vs;
     405        46908 :   *--zd = evaltyp(t_VECSMALL) | evallg(lz); return zd;
     406              : }
     407              : 
     408              : /* shift polynomial + GC; do not set evalvarn. Cf Flx_shiftip */
     409              : static GEN
     410     27750181 : F2x_shiftip(pari_sp av, GEN x, long v)
     411              : {
     412     27750181 :   long i, lx = lg(x), ly;
     413              :   GEN y;
     414     27750181 :   if (!v || lx==2) return gc_leaf(av, x);
     415        29378 :   ly = lx + v;
     416        29378 :   (void)new_chunk(ly); /* check that result fits */
     417        29378 :   x += lx; y = (GEN)av;
     418       136016 :   for (i = 2; i<lx; i++) *--y = *--x;
     419       164707 :   for (i = 0; i< v; i++) *--y = 0;
     420        29378 :   y -= 2; y[0] = evaltyp(t_VECSMALL) | evallg(ly);
     421        29378 :   return gc_const((pari_sp)y, y);
     422              : }
     423              : 
     424              : static GEN
     425          264 : F2x_to_int(GEN a, long na, long da, long bs)
     426              : {
     427          264 :   const long BIL = BITS_IN_LONG;
     428              :   GEN z, zs;
     429              :   long i,j,k,m;
     430          264 :   long lz = nbits2lg(1+da*bs);
     431          264 :   z = cgeti(lz); z[1] = evalsigne(1)|evallgefint(lz);
     432          264 :   zs = int_LSW(z); *zs = 0;
     433        16185 :   for (i=0, k=2, m=0; i<na; i++)
     434      1022781 :     for (j=0; j<BIL; j++, m+=bs)
     435              :     {
     436      1007121 :       if (m >= BIL)
     437              :       {
     438       202089 :         k++; if (k>=lz) break;
     439       201828 :         zs = int_nextW(zs);
     440       201828 :         *zs = 0;
     441       201828 :         m -= BIL;
     442              :       }
     443      1006860 :       *zs |= ((a[i]>>j)&1UL)<<m;
     444              :     }
     445          264 :   return int_normalize(z,0);
     446              : }
     447              : 
     448              : static GEN
     449          132 : int_to_F2x(GEN x, long d, long bs)
     450              : {
     451          132 :   const long BIL = BITS_IN_LONG;
     452          132 :   long lx = lgefint(x), lz = nbits2lg(d+1);
     453              :   long i,j,k,m;
     454          132 :   GEN xs = int_LSW(x);
     455          132 :   GEN z = cgetg(lz, t_VECSMALL);
     456          132 :   z[1] = 0;
     457        15924 :   for (k=2, i=2, m=0; k < lx; i++)
     458              :   {
     459        15792 :     z[i] = 0;
     460      1022217 :     for (j=0; j<BIL; j++, m+=bs)
     461              :     {
     462      1006557 :       if (m >= BIL)
     463              :       {
     464       202005 :         if (++k==lx) break;
     465       201873 :         xs = int_nextW(xs);
     466       201873 :         m -= BIL;
     467              :       }
     468      1006425 :       if ((*xs>>m)&1UL)
     469       449712 :         z[i]|=1UL<<j;
     470              :     }
     471              :   }
     472          132 :   return F2x_renormalize(z,lz);
     473              : }
     474              : 
     475              : static GEN
     476          132 : F2x_mulspec_mulii(GEN a, GEN b, long na, long nb)
     477              : {
     478          132 :   long da = F2x_degreespec(a,na), db = F2x_degreespec(b,nb);
     479          132 :   long bs = expu(1 + maxss(da, db))+1;
     480          132 :   GEN A = F2x_to_int(a,na,da,bs);
     481          132 :   GEN B = F2x_to_int(b,nb,db,bs);
     482          132 :   GEN z = mulii(A,B);
     483          132 :   return int_to_F2x(z,da+db,bs);
     484              : }
     485              : 
     486              : /* fast product (Karatsuba) of polynomials a,b. These are not real GENs, a+2,
     487              :  * b+2 were sent instead. na, nb = number of terms of a, b.
     488              :  * Only c, c0, c1, c2 are genuine GEN.
     489              :  */
     490              : static GEN
     491     34726008 : F2x_mulspec(GEN a, GEN b, long na, long nb)
     492              : {
     493              :   GEN a0,c,c0;
     494     34726008 :   long n0, n0a, i, v = 0;
     495              :   pari_sp av;
     496     34833849 :   while (na && !a[0]) { a++; na-=1; v++; }
     497     34753913 :   while (nb && !b[0]) { b++; nb-=1; v++; }
     498     34726008 :   if (na < nb) swapspec(a,b, na,nb);
     499     34726008 :   if (!nb) return pol0_F2x(0);
     500              : 
     501     27750181 :   av = avma;
     502     27750181 :   if (na == 1)
     503     24367929 :     return F2x_shiftip(av, F2x_mul1(*a,*b), v);
     504      3382252 :   if (na < F2x_MUL_KARATSUBA_LIMIT)
     505      3350029 :     return F2x_shiftip(av, F2x_mulspec_basecase(a, b, na, nb), v);
     506        32223 :   if (nb >= F2x_MUL_MULII_LIMIT)
     507          132 :     return F2x_shiftip(av, F2x_mulspec_mulii(a, b, na, nb), v);
     508        32091 :   i=(na>>1); n0=na-i; na=i;
     509        32091 :   a0=a+n0; n0a=n0;
     510        32176 :   while (n0a && !a[n0a-1]) n0a--;
     511              : 
     512        32091 :   if (nb > n0)
     513              :   {
     514              :     GEN b0,c1,c2;
     515              :     long n0b;
     516              : 
     517        14817 :     nb -= n0; b0 = b+n0; n0b = n0;
     518        14824 :     while (n0b && !b[n0b-1]) n0b--;
     519        14817 :     c =  F2x_mulspec(a,b,n0a,n0b);
     520        14817 :     c0 = F2x_mulspec(a0,b0,na,nb);
     521              : 
     522        14817 :     c2 = F2x_addspec(a0,a,na,n0a);
     523        14817 :     c1 = F2x_addspec(b0,b,nb,n0b);
     524              : 
     525        14817 :     c1 = F2x_mul(c1,c2);
     526        14817 :     c2 = F2x_add(c0,c);
     527              : 
     528        14817 :     c2 = F2x_add(c1,c2);
     529        14817 :     c0 = F2x_addshift(c0,c2,n0);
     530              :   }
     531              :   else
     532              :   {
     533        17274 :     c  = F2x_mulspec(a,b,n0a,nb);
     534        17274 :     c0 = F2x_mulspec(a0,b,na,nb);
     535              :   }
     536        32091 :   c0 = F2x_addshift(c0,c,n0);
     537        32091 :   return F2x_shiftip(av,c0, v);
     538              : }
     539              : 
     540              : GEN
     541     34661826 : F2x_mul(GEN x, GEN y)
     542              : {
     543     34661826 :   GEN z = F2x_mulspec(x+2,y+2, lgpol(x),lgpol(y));
     544     34661826 :   z[1] = x[1]; return z;
     545              : }
     546              : 
     547              : GEN
     548      6982161 : F2x_sqr(GEN x)
     549              : {
     550      6982161 :   const ulong sq[]={0,1,4,5,16,17,20,21,64,65,68,69,80,81,84,85};
     551              :   long i,ii,j,jj;
     552      6982161 :   long lx=lg(x), lz=2+((lx-2)<<1);
     553              :   GEN z;
     554      6982161 :   z = cgetg(lz, t_VECSMALL); z[1]=x[1];
     555     14032664 :   for (j=2,jj=2;j<lx;j++,jj++)
     556              :   {
     557      7050503 :     ulong x1=((ulong)x[j]&HIGHMASK)>>BITS_IN_HALFULONG;
     558      7050503 :     ulong x2=(ulong)x[j]&LOWMASK;
     559      7050503 :     z[jj]=0;
     560      7050503 :     if (x2)
     561     58877539 :       for(i=0,ii=0;i<BITS_IN_HALFULONG;i+=4,ii+=8)
     562     51878732 :         z[jj]|=sq[(x2>>i)&15UL]<<ii;
     563      7050503 :     z[++jj]=0;
     564      7050503 :     if (x1)
     565      5636685 :       for(i=0,ii=0;i<BITS_IN_HALFULONG;i+=4,ii+=8)
     566      4900676 :         z[jj]|=sq[(x1>>i)&15UL]<<ii;
     567              :   }
     568      6982161 :   return F2x_renormalize(z, lz);
     569              : }
     570              : 
     571              : static GEN
     572       165124 : F2x_pow2n(GEN x, long n)
     573              : {
     574              :   long i;
     575       495372 :   for(i=1;i<=n;i++)
     576       330248 :     x = F2x_sqr(x);
     577       165124 :   return x;
     578              : }
     579              : 
     580              : int
     581        35572 : F2x_issquare(GEN x)
     582              : {
     583        35572 :   const ulong mask = (ULONG_MAX/3UL)*2;
     584        35572 :   ulong i, lx = lg(x);
     585        71144 :   for (i=2; i<lx; i++)
     586        35572 :     if ((x[i]&mask)) return 0;
     587        35572 :   return 1;
     588              : }
     589              : 
     590              : /* Assume x is a perfect square */
     591              : GEN
     592       251667 : F2x_sqrt(GEN x)
     593              : {
     594       251667 :   const ulong sq[]={0,1,4,5,2,3,6,7,8,9,12,13,10,11,14,15};
     595              :   long i,ii,j,jj;
     596       251667 :   long lx=lg(x), lz=2+((lx-1)>>1);
     597              :   GEN z;
     598       251667 :   z = cgetg(lz, t_VECSMALL); z[1]=x[1];
     599       503358 :   for (j=2,jj=2;jj<lz;j++,jj++)
     600              :   {
     601       251691 :     ulong x2=x[j++];
     602       251691 :     z[jj]=0;
     603       251691 :     if (x2)
     604      2121407 :       for(i=0,ii=0;ii<BITS_IN_HALFULONG;i+=8,ii+=4)
     605              :       {
     606      1869716 :         ulong rl = (x2>>i)&15UL, rh = (x2>>(i+4))&15UL;
     607      1869716 :         z[jj]|=sq[rl|(rh<<1)]<<ii;
     608              :       }
     609       251691 :     if (j<lx)
     610              :     {
     611          358 :       x2 = x[j];
     612          358 :       if (x2)
     613         2291 :         for(i=0,ii=0;ii<BITS_IN_HALFULONG;i+=8,ii+=4)
     614              :         {
     615         1948 :           ulong rl = (x2>>i)&15UL, rh = (x2>>(i+4))&15UL;
     616         1948 :           z[jj]|=(sq[rl|(rh<<1)]<<ii)<<BITS_IN_HALFULONG;
     617              :         }
     618              :     }
     619              :   }
     620       251667 :   return F2x_renormalize(z, lz);
     621              : }
     622              : 
     623              : static GEN
     624          929 : F2x_shiftneg(GEN y, ulong d)
     625              : {
     626          929 :   long db, dl=dvmdsBIL(d, &db);
     627          929 :   long i, ly = lg(y), lx = ly-dl;
     628              :   GEN x;
     629          929 :   if (lx <= 2) return zero_F2x(y[1]);
     630          913 :   x = cgetg(lx, t_VECSMALL);
     631          913 :   x[1] = y[1];
     632          913 :   if (db)
     633              :   {
     634          913 :     ulong dc=BITS_IN_LONG-db;
     635          913 :     ulong r=0;
     636         1826 :     for(i=lx-1; i>=2; i--)
     637              :     {
     638          913 :       x[i] = (((ulong)y[i+dl])>>db)|r;
     639          913 :       r = ((ulong)y[i+dl])<<dc;
     640              :     }
     641              :   }
     642              :   else
     643            0 :     for(i=2; i<lx; i++)
     644            0 :       x[i] = y[i+dl];
     645          913 :   return F2x_renormalize(x,lx);
     646              : }
     647              : 
     648              : static GEN
     649       266873 : F2x_shiftpos(GEN y, ulong d)
     650              : {
     651       266873 :   long db, dl=dvmdsBIL(d, &db);
     652       266873 :   long i, ly = lg(y), lx = ly+dl+(!!db);
     653       266873 :   GEN x = cgetg(lx, t_VECSMALL);
     654       266949 :   x[1] = y[1]; for(i=0; i<dl; i++) x[i+2] = 0;
     655       266873 :   if (db)
     656              :   {
     657       265751 :     ulong dc=BITS_IN_LONG-db;
     658       265751 :     ulong r=0;
     659       534978 :     for(i=2; i<ly; i++)
     660              :     {
     661       269227 :       x[i+dl] = (((ulong)y[i])<<db)|r;
     662       269227 :       r = ((ulong)y[i])>>dc;
     663              :     }
     664       265751 :     x[i+dl] = r;
     665              :   }
     666              :   else
     667         1353 :     for(i=2; i<ly; i++)
     668          231 :       x[i+dl] = y[i];
     669       266873 :   return F2x_renormalize(x,lx);
     670              : }
     671              : 
     672              : GEN
     673       267802 : F2x_shift(GEN y, long d)
     674              : {
     675       267802 :   return d<0 ? F2x_shiftneg(y,-d): F2x_shiftpos(y,d);
     676              : }
     677              : 
     678              : #define F2x_recip2(pk,m) u = ((u&m)<<pk)|((u&(~m))>>pk);
     679              : #define F2x_recipu(pk) F2x_recip2(pk,((~0UL)/((1UL<<pk)+1)))
     680              : 
     681              : static ulong
     682           35 : F2x_recip1(ulong u)
     683              : {
     684           35 :   u = (u<<BITS_IN_HALFULONG)|(u>>BITS_IN_HALFULONG);
     685              : #ifdef LONG_IS_64BIT
     686           30 :   F2x_recipu(16);
     687              : #endif
     688           35 :   F2x_recipu(8);
     689           35 :   F2x_recipu(4);
     690           35 :   F2x_recipu(2);
     691           35 :   F2x_recipu(1);
     692           35 :   return u;
     693              : }
     694              : 
     695              : static GEN
     696            0 : F2x_recip_raw(GEN x)
     697              : {
     698              :   long i, l;
     699            0 :   GEN y = cgetg_copy(x,&l);
     700            0 :   y[1] = x[1];
     701            0 :   for (i=0; i<l-2; i++)
     702            0 :     uel(y,l-1-i) = F2x_recip1(uel(x,2+i));
     703            0 :   return y;
     704              : }
     705              : 
     706              : GEN
     707            0 : F2x_recip(GEN x)
     708              : {
     709            0 :   long lb = remsBIL(F2x_degree(x)+1);
     710            0 :   GEN y = F2x_recip_raw(x);
     711            0 :   if (lb) y = F2x_shiftneg(y,BITS_IN_LONG-lb);
     712            0 :   return y;
     713              : }
     714              : 
     715              : GEN
     716           76 : F2xn_red(GEN f, long n)
     717              : {
     718              :   GEN g;
     719              :   long i, dl, db, l;
     720           76 :   if (F2x_degree(f) < n) return zv_copy(f);
     721            0 :   dl = dvmdsBIL(n, &db); l = 2 + dl + (db>0);
     722            0 :   g = cgetg(l, t_VECSMALL);
     723            0 :   g[1] = f[1];
     724            0 :   for (i=2; i<l; i++)
     725            0 :     uel(g,i) = uel(f,i);
     726            0 :   if (db) uel(g,l-1) = uel(f,l-1)&((1UL<<db)-1);
     727            0 :   return F2x_renormalize(g, l);
     728              : }
     729              : 
     730              : static GEN
     731           39 : F2xn_mul(GEN a, GEN b, long n) { return F2xn_red(F2x_mul(a, b), n); }
     732              : 
     733              : static ulong
     734           35 : F2xn_inv_basecase1(ulong x)
     735              : {
     736              :   ulong u, v, w;
     737              :   long i;
     738           35 :   u = x>>1;
     739           35 :   v = (u&1UL)|2UL;
     740           35 :   w = u&v; w ^= w >> 1; v = (w&1UL)|(v<<1);
     741           35 :   w = u&v; w ^= w >> 2; w ^= w >> 1; v = (w&1UL)|(v<<1);
     742           35 :   w = u&v; w ^= w >> 2; w ^= w >> 1; v = (w&1UL)|(v<<1);
     743          175 :   for (i=1;i<=4;i++)
     744          140 :   { w = u&v; w ^= w >> 4; w ^= w >> 2; w ^= w >> 1; v = (w&1UL)|(v<<1); }
     745          315 :   for (i=1;i<=8;i++)
     746          280 :   { w = u&v; w ^= w >> 8; w ^= w >> 4; w ^= w >> 2; w ^= w >> 1;
     747          280 :     v = (w&1UL)|(v<<1); }
     748          595 :   for (i=1;i<=16;i++)
     749          560 :   { w = u&v; w ^= w >> 16; w ^= w >> 8; w ^= w >> 4; w ^= w >> 2; w ^= w >> 1;
     750          560 :     v = (w&1UL)|(v<<1); }
     751              : #ifdef LONG_IS_64BIT
     752          990 :   for (i=1; i<=32; i++)
     753          960 :   { w = u&v; w ^= w >> 32; w ^= w >> 16; w ^= w >> 8; w ^= w >> 4; w ^= w >> 2;
     754          960 :     w ^= w >> 1; v = (w&1UL)|(v<<1); }
     755              : #endif
     756           35 :   return (F2x_recip1(v)<<1) | 1UL;
     757              : }
     758              : 
     759              : static GEN
     760           35 : F2xn_inv1(GEN v, long e)
     761              : {
     762           35 :   ulong mask = e==BITS_IN_LONG ? -1UL: ((1UL<<e)-1);
     763           35 :   return mkvecsmall2(v[1],F2xn_inv_basecase1(uel(v,2))&mask);
     764              : }
     765              : 
     766              : static GEN
     767           21 : F2xn_div1(GEN g, GEN f, long e)
     768              : {
     769           21 :   GEN fi = F2xn_inv1(f, e);
     770           21 :   return g ? F2xn_mul(g, fi, e): fi;
     771              : }
     772              : 
     773              : GEN
     774           35 : F2xn_div(GEN g, GEN f, long e)
     775              : {
     776           35 :   pari_sp av = avma, av2;
     777              :   ulong mask;
     778              :   GEN W;
     779           35 :   long n=1;
     780           35 :   if (lg(f)<=2) pari_err_INV("Flxn_inv",f);
     781           35 :   if (e <= BITS_IN_LONG) return F2xn_div1(g, f, e);
     782           14 :   W = F2xn_inv1(f, BITS_IN_LONG);
     783           14 :   mask = quadratic_prec_mask(divsBIL(e+BITS_IN_LONG-1));
     784           14 :   n = BITS_IN_LONG;
     785           14 :   av2 = avma;
     786           30 :   for (;mask>1;)
     787              :   {
     788              :     GEN u, fr;
     789           16 :     long n2 = n;
     790           16 :     n<<=1; if (mask & 1) n--;
     791           16 :     mask >>= 1;
     792           16 :     fr = F2xn_red(f, n);
     793           16 :     if (mask>1 || !g)
     794              :     {
     795            9 :       u = F2x_shift(F2xn_mul(W, fr, n), -n2);
     796            9 :       W = F2x_add(W, F2x_shift(F2xn_mul(u, W, n-n2), n2));
     797              :     } else
     798              :     {
     799            7 :       GEN y = F2xn_mul(g, W, n), yt =  F2xn_red(y, n-n2);
     800            7 :       u = F2xn_mul(yt, F2x_shift(F2xn_mul(fr,  W, n), -n2), n-n2);
     801            7 :       W = F2x_add(y, F2x_shift(u, n2));
     802              :     }
     803           16 :     if (gc_needed(av2,2))
     804              :     {
     805            0 :       if(DEBUGMEM>1) pari_warn(warnmem,"F2xn_inv, e = %ld", n);
     806            0 :       W = gc_upto(av2, W);
     807              :     }
     808              :   }
     809           14 :   return gc_upto(av, F2xn_red(W,e));
     810              : }
     811              : 
     812              : GEN
     813           28 : F2xn_inv(GEN f, long e)
     814           28 : { return F2xn_div(NULL, f, e); }
     815              : 
     816              : GEN
     817       219049 : F2x_get_red(GEN T)
     818              : {
     819       219049 :   return T;
     820              : }
     821              : 
     822              : /* separate from F2x_divrem for maximal speed. */
     823              : GEN
     824     52097538 : F2x_rem(GEN x, GEN y)
     825              : {
     826              :   long dx,dy;
     827     52097538 :   long lx=lg(x);
     828     52097538 :   dy = F2x_degree(y); if (!dy) return pol0_F2x(x[1]);
     829     49383561 :   dx = F2x_degree_lg(x,lx);
     830     49383561 :   x  = F2x_copy(x);
     831    164710856 :   while (dx>=dy)
     832              :   {
     833    115327295 :     F2x_addshiftip(x,y,dx-dy);
     834    118019224 :     while (lx>2 && x[lx-1]==0) lx--;
     835    115327295 :     dx = F2x_degree_lg(x,lx);
     836              :   }
     837     49383561 :   return F2x_renormalize(x, lx);
     838              : }
     839              : 
     840              : GEN
     841     13957676 : F2x_divrem(GEN x, GEN y, GEN *pr)
     842              : {
     843     13957676 :   long dx, dy, dz, lx = lg(x), vs = x[1];
     844              :   GEN z;
     845              : 
     846     13957676 :   dy = F2x_degree(y);
     847     13957676 :   if (dy<0) pari_err_INV("F2x_divrem",y);
     848     13957676 :   if (pr == ONLY_REM) return F2x_rem(x, y);
     849     13957676 :   if (!dy)
     850              :   {
     851      3166597 :     z = F2x_copy(x);
     852      3166597 :     if (pr && pr != ONLY_DIVIDES) *pr = pol0_F2x(vs);
     853      3166597 :     return z;
     854              :   }
     855     10791079 :   dx = F2x_degree_lg(x,lx);
     856     10791079 :   dz = dx-dy;
     857     10791079 :   if (dz < 0)
     858              :   {
     859          896 :     if (pr == ONLY_DIVIDES) return dx < 0? F2x_copy(x): NULL;
     860          896 :     z = pol0_F2x(vs);
     861          896 :     if (pr) *pr = F2x_copy(x);
     862          896 :     return z;
     863              :   }
     864     10790183 :   z = zero_zv(lg(x)-lg(y)+2); z[1] = vs;
     865     10790183 :   x = F2x_copy(x);
     866     34490510 :   while (dx>=dy)
     867              :   {
     868     23700327 :     F2x_set(z,dx-dy);
     869     23700327 :     F2x_addshiftip(x,y,dx-dy);
     870     25220451 :     while (lx>2 && x[lx-1]==0) lx--;
     871     23700327 :     dx = F2x_degree_lg(x,lx);
     872              :   }
     873     10790183 :   z = F2x_renormalize(z, lg(z));
     874     10790183 :   if (!pr) { cgiv(x); return z; }
     875      9539414 :   x = F2x_renormalize(x, lx);
     876      9539414 :   if (pr == ONLY_DIVIDES) {
     877            0 :     if (lg(x) == 2) { cgiv(x); return z; }
     878            0 :     return gc_NULL((pari_sp)(z + lg(z)));
     879              :   }
     880      9539414 :   *pr = x; return z;
     881              : }
     882              : 
     883              : long
     884        35500 : F2x_valrem(GEN x, GEN *Z)
     885              : {
     886        35500 :   long v, v2, i, l=lg(x);
     887              :   GEN y;
     888        35500 :   if (l==2) { *Z = F2x_copy(x); return LONG_MAX; }
     889        35503 :   for (i=2; i<l && x[i]==0; i++) /*empty*/;
     890        35500 :   v = i-2;
     891        35500 :   v2 = (i < l)? vals(x[i]): 0;
     892        35500 :   if (v+v2 == 0) { *Z = x; return 0; }
     893        11273 :   l -= i-2;
     894        11273 :   y = cgetg(l, t_VECSMALL); y[1] = x[1];
     895        11273 :   if (v2 == 0)
     896            6 :     for (i=2; i<l; i++) uel(y,i) = uel(x,i+v);
     897        11270 :   else if (l == 3)
     898        11248 :     y[2] = uel(x,2+v) >> v2;
     899              :   else
     900              :   {
     901           22 :     const ulong sh = BITS_IN_LONG - v2;
     902           22 :     ulong r = uel(x,2+v);
     903           44 :     for (i=3; i<l; i++)
     904              :     {
     905           22 :       uel(y,i-1) = (uel(x,i+v)<< sh) | (r >> v2);
     906           22 :       r = uel(x,i+v);
     907              :     }
     908           22 :     uel(y,l-1) = r >> v2;
     909           22 :     (void)F2x_renormalize(y,l);
     910              :   }
     911        11273 :   *Z = y; return (v << TWOPOTBITS_IN_LONG) + v2;
     912              : }
     913              : 
     914              : GEN
     915            0 : F2x_deflate(GEN x, long d)
     916              : {
     917              :   GEN y;
     918            0 :   long i,id, dy, dx = F2x_degree(x);
     919            0 :   if (d <= 1) return F2x_copy(x);
     920            0 :   if (dx < 0) return F2x_copy(x);
     921            0 :   dy = dx/d; /* dy+1 coefficients + 1 extra word for variable */
     922            0 :   y = zero_zv(nbits2lg(dy+1)-1); y[1] = x[1];
     923            0 :   for (i=id=0; i<=dy; i++,id+=d)
     924            0 :     if (F2x_coeff(x,id)) F2x_set(y, i);
     925            0 :   return y;
     926              : }
     927              : 
     928              : /* write p(X) = e(X^2) + Xo(X^2), shallow function */
     929              : void
     930        61607 : F2x_even_odd(GEN p, GEN *pe, GEN *po)
     931              : {
     932        61607 :   long n = F2x_degree(p), n0, n1, i;
     933              :   GEN p0, p1;
     934              : 
     935        61607 :   if (n <= 0) { *pe = F2x_copy(p); *po = pol0_F2x(p[1]); return; }
     936              : 
     937        57308 :   n0 = (n>>1)+1; n1 = n+1 - n0; /* n1 <= n0 <= n1+1 */
     938        57308 :   p0 = zero_zv(nbits2lg(n0+1)-1); p0[1] = p[1];
     939        57308 :   p1 = zero_zv(nbits2lg(n1+1)-1); p1[1] = p[1];
     940      2131942 :   for (i=0; i<n1; i++)
     941              :   {
     942      2074634 :     if (F2x_coeff(p,i<<1)) F2x_set(p0,i);
     943      2074634 :     if (F2x_coeff(p,1+(i<<1))) F2x_set(p1,i);
     944              :   }
     945        57308 :   if (n1 != n0 && F2x_coeff(p,i<<1)) F2x_set(p0,i);
     946        57308 :   *pe = F2x_renormalize(p0,lg(p0));
     947        57308 :   *po = F2x_renormalize(p1,lg(p1));
     948              : }
     949              : 
     950              : GEN
     951      1291711 : F2x_deriv(GEN z)
     952              : {
     953      1291711 :   const ulong mask = ULONG_MAX/3UL;
     954      1291711 :   long i,l = lg(z);
     955      1291711 :   GEN x = cgetg(l, t_VECSMALL); x[1] = z[1];
     956      2588627 :   for (i=2; i<l; i++) x[i] = (((ulong)z[i])>>1)&mask;
     957      1291711 :   return F2x_renormalize(x,l);
     958              : }
     959              : 
     960              : GEN
     961      3856169 : F2x_gcd(GEN a, GEN b)
     962              : {
     963      3856169 :   pari_sp av = avma;
     964      3856169 :   if (lg(b) > lg(a)) swap(a, b);
     965     25429246 :   while (lgpol(b))
     966              :   {
     967     21573077 :     GEN c = F2x_rem(a,b);
     968     21573077 :     a = b; b = c;
     969     21573077 :     if (gc_needed(av,2))
     970              :     {
     971            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"F2x_gcd (d = %ld)",F2x_degree(c));
     972            0 :       (void)gc_all(av,2, &a,&b);
     973              :     }
     974              :   }
     975      3856169 :   if (gc_needed(av,2)) a = gc_leaf(av, a);
     976      3856169 :   return a;
     977              : }
     978              : 
     979              : GEN
     980      2852889 : F2x_extgcd(GEN a, GEN b, GEN *ptu, GEN *ptv)
     981              : {
     982      2852889 :   pari_sp av=avma;
     983              :   GEN u,v,d,d1,v1;
     984      2852889 :   long vx = a[1];
     985      2852889 :   d = a; d1 = b;
     986      2852889 :   v = pol0_F2x(vx); v1 = pol1_F2x(vx);
     987     15232064 :   while (lgpol(d1))
     988              :   {
     989     12379175 :     GEN r, q = F2x_divrem(d,d1, &r);
     990     12379175 :     v = F2x_add(v,F2x_mul(q,v1));
     991     12379175 :     u=v; v=v1; v1=u;
     992     12379175 :     u=r; d=d1; d1=u;
     993     12379175 :     if (gc_needed(av,2))
     994              :     {
     995            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"F2x_extgcd (d = %ld)",F2x_degree(d));
     996            0 :       (void)gc_all(av,5, &d,&d1,&u,&v,&v1);
     997              :     }
     998              :   }
     999      2852889 :   if (ptu) *ptu = F2x_div(F2x_add(d, F2x_mul(b,v)), a);
    1000      2852889 :   *ptv = v;
    1001      2852889 :   if (gc_needed(av,2)) (void)gc_all(av,ptu?3:2,&d,ptv,ptu);
    1002      2852889 :   return d;
    1003              : }
    1004              : 
    1005              : static GEN
    1006          824 : F2x_halfgcd_i(GEN a, GEN b)
    1007              : {
    1008          824 :   pari_sp av=avma;
    1009              :   GEN u,u1,v,v1;
    1010          824 :   long vx = a[1];
    1011          824 :   long n = (F2x_degree(a)+1)>>1;
    1012          824 :   u1 = v = pol0_F2x(vx);
    1013          824 :   u = v1 = pol1_F2x(vx);
    1014        13058 :   while (F2x_degree(b)>=n)
    1015              :   {
    1016        12234 :     GEN r, q = F2x_divrem(a,b, &r);
    1017        12234 :     a = b; b = r; swap(u,u1); swap(v,v1);
    1018        12234 :     u1 = F2x_add(u1, F2x_mul(u, q));
    1019        12234 :     v1 = F2x_add(v1, F2x_mul(v, q));
    1020        12234 :     if (gc_needed(av,2))
    1021              :     {
    1022            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"F2x_halfgcd (d = %ld)",F2x_degree(b));
    1023            0 :       (void)gc_all(av,6, &a,&b,&u1,&v1,&u,&v);
    1024              :     }
    1025              :   }
    1026          824 :   return gc_GEN(av, mkmat22(u,v,u1,v1));
    1027              : }
    1028              : 
    1029              : GEN
    1030          824 : F2x_halfgcd(GEN x, GEN y)
    1031              : {
    1032              :   pari_sp av;
    1033              :   GEN M,q,r;
    1034          824 :   if (F2x_degree(y)<F2x_degree(x)) return F2x_halfgcd_i(x,y);
    1035          824 :   av = avma;
    1036          824 :   q = F2x_divrem(y,x,&r);
    1037          824 :   M = F2x_halfgcd_i(x,r);
    1038          824 :   gcoeff(M,1,1) = F2x_add(gcoeff(M,1,1), F2x_mul(q, gcoeff(M,1,2)));
    1039          824 :   gcoeff(M,2,1) = F2x_add(gcoeff(M,2,1), F2x_mul(q, gcoeff(M,2,2)));
    1040          824 :   return gc_GEN(av, M);
    1041              : }
    1042              : 
    1043              : GEN
    1044     14099077 : F2xq_mul(GEN x,GEN y,GEN pol)
    1045              : {
    1046     14099077 :   GEN z = F2x_mul(x,y);
    1047     14099077 :   return F2x_rem(z,pol);
    1048              : }
    1049              : 
    1050              : GEN
    1051      6644808 : F2xq_sqr(GEN x,GEN pol)
    1052              : {
    1053      6644808 :   GEN z = F2x_sqr(x);
    1054      6644808 :   return F2x_rem(z,pol);
    1055              : }
    1056              : 
    1057              : GEN
    1058      2852889 : F2xq_invsafe(GEN x, GEN T)
    1059              : {
    1060      2852889 :   GEN V, z = F2x_extgcd(get_F2x_mod(T), x, NULL, &V);
    1061      2852889 :   if (F2x_degree(z)) return NULL;
    1062      2852819 :   return V;
    1063              : }
    1064              : 
    1065              : GEN
    1066      2852882 : F2xq_inv(GEN x,GEN T)
    1067              : {
    1068      2852882 :   pari_sp av=avma;
    1069      2852882 :   GEN U = F2xq_invsafe(x, T);
    1070      2852882 :   if (!U) pari_err_INV("F2xq_inv", F2x_to_ZX(x));
    1071      2852812 :   return gc_leaf(av, U);
    1072              : }
    1073              : 
    1074              : GEN
    1075      1384012 : F2xq_div(GEN x,GEN y,GEN T)
    1076              : {
    1077      1384012 :   pari_sp av = avma;
    1078      1384012 :   return gc_leaf(av, F2xq_mul(x,F2xq_inv(y,T),T));
    1079              : }
    1080              : 
    1081              : static GEN
    1082       583008 : _F2xq_red(void *E, GEN x) { return F2x_rem(x, (GEN)E); }
    1083              : static GEN
    1084      1700698 : _F2xq_add(void *E, GEN x, GEN y) { (void)E; return F2x_add(x,y); }
    1085              : 
    1086              : static GEN
    1087      2088630 : _F2xq_cmul(void *E, GEN P, long a, GEN x)
    1088              : {
    1089      2088630 :   GEN pol = (GEN) E;
    1090      2088630 :   return F2x_coeff(P,a) ? x: pol0_F2x(pol[1]);
    1091              : }
    1092              : static GEN
    1093      1211628 : _F2xq_sqr(void *E, GEN x) { return F2xq_sqr(x, (GEN) E); }
    1094              : static GEN
    1095      2183368 : _F2xq_mul(void *E, GEN x, GEN y) { return F2xq_mul(x,y, (GEN) E); }
    1096              : 
    1097              : static GEN
    1098       928151 : _F2xq_one(void *E)
    1099              : {
    1100       928151 :   GEN pol = (GEN) E;
    1101       928151 :   return pol1_F2x(pol[1]);
    1102              : }
    1103              : static GEN
    1104       259885 : _F2xq_zero(void *E)
    1105              : {
    1106       259885 :   GEN pol = (GEN) E;
    1107       259885 :   return pol0_F2x(pol[1]);
    1108              : }
    1109              : 
    1110              : GEN
    1111      2438237 : F2xq_pow(GEN x, GEN n, GEN pol)
    1112              : {
    1113      2438237 :   pari_sp av=avma;
    1114              :   GEN y;
    1115              : 
    1116      2438237 :   if (!signe(n)) return pol1_F2x(x[1]);
    1117      2431819 :   if (is_pm1(n)) /* +/- 1 */
    1118      1841004 :     return (signe(n) < 0)? F2xq_inv(x,pol): F2x_copy(x);
    1119              : 
    1120       590815 :   if (signe(n) < 0) x = F2xq_inv(x,pol);
    1121       590815 :   y = gen_pow_i(x, n, (void*)pol, &_F2xq_sqr, &_F2xq_mul);
    1122       590815 :   return gc_GEN(av, y);
    1123              : }
    1124              : 
    1125              : GEN
    1126           49 : F2xq_powu(GEN x, ulong n, GEN pol)
    1127              : {
    1128           49 :   pari_sp av=avma;
    1129              :   GEN y;
    1130           49 :   switch(n)
    1131              :   {
    1132            0 :     case 0: return pol1_F2x(x[1]);
    1133            7 :     case 1: return F2x_copy(x);
    1134           14 :     case 2: return F2xq_sqr(x,pol);
    1135              :   }
    1136           28 :   y = gen_powu_i(x, n, (void*)pol, &_F2xq_sqr, &_F2xq_mul);
    1137           28 :   return gc_GEN(av, y);
    1138              : }
    1139              : 
    1140              : GEN
    1141           14 : F2xq_pow_init(GEN x, GEN n, long k,  GEN T)
    1142              : {
    1143           14 :   return gen_pow_init(x, n, k, (void*)T, &_F2xq_sqr, &_F2xq_mul);
    1144              : }
    1145              : 
    1146              : GEN
    1147         5244 : F2xq_pow_table(GEN R, GEN n, GEN T)
    1148              : {
    1149         5244 :   return gen_pow_table(R, n, (void*)T, &_F2xq_one, &_F2xq_mul);
    1150              : }
    1151              : 
    1152              : /* generates the list of powers of x of degree 0,1,2,...,l*/
    1153              : GEN
    1154       365884 : F2xq_powers(GEN x, long l, GEN T)
    1155              : {
    1156       365884 :   int use_sqr = 2*F2x_degree(x) >= get_F2x_degree(T);
    1157       365884 :   return gen_powers(x, l, use_sqr, (void*)T, &_F2xq_sqr, &_F2xq_mul, &_F2xq_one);
    1158              : }
    1159              : 
    1160              : GEN
    1161       236440 : F2xq_matrix_pow(GEN y, long n, long m, GEN P)
    1162              : {
    1163       236440 :   return F2xV_to_F2m(F2xq_powers(y,m-1,P),n);
    1164              : }
    1165              : 
    1166              : GEN
    1167       663241 : F2x_Frobenius(GEN T)
    1168              : {
    1169       663241 :   return F2xq_sqr(polx_F2x(get_F2x_var(T)), T);
    1170              : }
    1171              : 
    1172              : GEN
    1173       236440 : F2x_matFrobenius(GEN T)
    1174              : {
    1175       236440 :   long n = get_F2x_degree(T);
    1176       236440 :   return F2xq_matrix_pow(F2x_Frobenius(T), n, n, T);
    1177              : }
    1178              : 
    1179              : static struct bb_algebra F2xq_algebra = { _F2xq_red, _F2xq_add, _F2xq_add,
    1180              :               _F2xq_mul, _F2xq_sqr, _F2xq_one, _F2xq_zero};
    1181              : 
    1182              : GEN
    1183       611467 : F2x_F2xqV_eval(GEN Q, GEN x, GEN T)
    1184              : {
    1185       611467 :   long d = F2x_degree(Q);
    1186       611467 :   return gen_bkeval_powers(Q,d,x,(void*)T,&F2xq_algebra,_F2xq_cmul);
    1187              : }
    1188              : 
    1189              : GEN
    1190        45107 : F2x_F2xq_eval(GEN Q, GEN x, GEN T)
    1191              : {
    1192        45107 :   long d = F2x_degree(Q);
    1193        45107 :   int use_sqr = 2*F2x_degree(x) >= get_F2x_degree(T);
    1194        45107 :   return gen_bkeval(Q, d, x, use_sqr, (void*)T, &F2xq_algebra, _F2xq_cmul);
    1195              : }
    1196              : 
    1197              : static GEN
    1198        29526 : F2xq_autpow_sqr(void * T, GEN x) { return F2x_F2xq_eval(x, x, (GEN) T); }
    1199              : 
    1200              : static GEN
    1201        14853 : F2xq_autpow_mul(void * T, GEN x, GEN y) { return F2x_F2xq_eval(x, y, (GEN) T); }
    1202              : 
    1203              : GEN
    1204        19367 : F2xq_autpow(GEN x, long n, GEN T)
    1205              : {
    1206        19367 :   if (n==0) return F2x_rem(polx_F2x(x[1]), T);
    1207        19367 :   if (n==1) return F2x_rem(x, T);
    1208        19367 :   return gen_powu(x,n,(void*)T,F2xq_autpow_sqr,F2xq_autpow_mul);
    1209              : }
    1210              : 
    1211              : ulong
    1212       458090 : F2xq_trace(GEN x, GEN T)
    1213              : {
    1214       458090 :   pari_sp av = avma;
    1215       458090 :   long n = get_F2x_degree(T)-1;
    1216       458090 :   GEN z = F2xq_mul(x, F2x_deriv(get_F2x_mod(T)), T);
    1217       458090 :   return gc_ulong(av, F2x_degree(z) < n ? 0 : 1);
    1218              : }
    1219              : 
    1220              : GEN
    1221            7 : F2xq_conjvec(GEN x, GEN T)
    1222              : {
    1223            7 :   long i, l = 1+get_F2x_degree(T);
    1224            7 :   GEN z = cgetg(l,t_COL);
    1225            7 :   gel(z,1) = F2x_copy(x);
    1226          140 :   for (i=2; i<l; i++) gel(z,i) = F2xq_sqr(gel(z,i-1), T);
    1227            7 :   return z;
    1228              : }
    1229              : 
    1230              : static GEN
    1231      2394876 : _F2xq_pow(void *data, GEN x, GEN n)
    1232              : {
    1233      2394876 :   GEN pol = (GEN) data;
    1234      2394876 :   return F2xq_pow(x,n, pol);
    1235              : }
    1236              : 
    1237              : static GEN
    1238         9385 : _F2xq_rand(void *data)
    1239              : {
    1240         9385 :   pari_sp av=avma;
    1241         9385 :   GEN pol = (GEN) data;
    1242         9385 :   long d = F2x_degree(pol);
    1243              :   GEN z;
    1244              :   do
    1245              :   {
    1246         9573 :     set_avma(av);
    1247         9573 :     z = random_F2x(d,pol[1]);
    1248         9573 :   } while (lgpol(z)==0);
    1249         9385 :   return z;
    1250              : }
    1251              : 
    1252              : static GEN F2xq_easylog(void* E, GEN a, GEN g, GEN ord);
    1253              : 
    1254              : static const struct bb_group F2xq_star={_F2xq_mul,_F2xq_pow,_F2xq_rand,hash_GEN,F2x_equal,F2x_equal1,F2xq_easylog};
    1255              : 
    1256              : GEN
    1257          415 : F2xq_order(GEN a, GEN ord, GEN T)
    1258              : {
    1259          415 :   return gen_order(a,ord,(void*)T,&F2xq_star);
    1260              : }
    1261              : 
    1262              : static long
    1263       267274 : F2x_is_smooth_squarefree(GEN f, long r)
    1264              : {
    1265       267274 :   pari_sp av = avma;
    1266       267274 :   long i, df = F2x_degree(f);
    1267              :   GEN sx, a;
    1268       267274 :   if (!df) return 1;
    1269       262363 :   a = sx = polx_F2x(f[1]);
    1270       262363 :   for(i = 1;; i++)
    1271      2232222 :   {
    1272              :     long dg;
    1273              :     GEN g;
    1274      2494585 :     a = F2xq_sqr(a, f);
    1275      2494585 :     if (F2x_equal(a, sx)) return gc_long(av,1);
    1276      2428014 :     if (i==r) return gc_long(av,0);
    1277      2253778 :     g = F2x_gcd(f, F2x_add(a,sx));
    1278      2253778 :     dg = F2x_degree(g);
    1279      2253778 :     if (dg == df) return gc_long(av,1);
    1280      2232222 :     if (dg) { f = F2x_div(f, g); df -= dg; a = F2x_rem(a, f); }
    1281              :   }
    1282              : }
    1283              : 
    1284              : static long
    1285       231702 : F2x_is_smooth(GEN g, long r)
    1286              : {
    1287       231702 :   if (lgpol(g)==0) return 0;
    1288              :   while (1)
    1289        35572 :   {
    1290       267274 :     GEN f = F2x_gcd(g, F2x_deriv(g));
    1291       267274 :     if (!F2x_is_smooth_squarefree(F2x_div(g, f), r)) return 0;
    1292        93038 :     if (F2x_degree(f)==0) return 1;
    1293        35572 :     g = F2x_issquare(f) ? F2x_sqrt(f): f;
    1294              :   }
    1295              : }
    1296              : 
    1297              : static GEN
    1298        14972 : F2x_factorel(GEN h)
    1299              : {
    1300        14972 :   GEN F = F2x_factor(h);
    1301        14972 :   GEN F1 = gel(F, 1), F2 = gel(F, 2);
    1302        14972 :   long i, l1 = lg(F1)-1;
    1303        14972 :   GEN p2 = cgetg(l1+1, t_VECSMALL);
    1304        14972 :   GEN e2 = cgetg(l1+1, t_VECSMALL);
    1305        70025 :   for (i = 1; i <= l1; ++i)
    1306              :   {
    1307        55053 :     p2[i] = mael(F1, i, 2);
    1308        55053 :     e2[i] = F2[i];
    1309              :   }
    1310        14972 :   return mkmat2(p2, e2);
    1311              : }
    1312              : 
    1313              : static GEN
    1314        27080 : mkF2(ulong x, long v) { return mkvecsmall2(v, x); }
    1315              : 
    1316              : static GEN F2xq_log_Coppersmith_d(GEN W, GEN g, long r, long n, GEN T, GEN mo);
    1317              : 
    1318              : static GEN
    1319           58 : F2xq_log_from_rel(GEN W, GEN rel, long r, long n, GEN T, GEN m)
    1320              : {
    1321           58 :   pari_sp av = avma;
    1322           58 :   long vT = get_F2x_var(T);
    1323           58 :   GEN F = gel(rel,1), E = gel(rel,2), o = gen_0;
    1324           58 :   long i, l = lg(F);
    1325          486 :   for(i=1; i<l; i++)
    1326              :   {
    1327          428 :     GEN R = gel(W, F[i]);
    1328          428 :     if (signe(R)==0) /* Already failed */
    1329            0 :       return NULL;
    1330          428 :     else if (signe(R)<0) /* Not yet tested */
    1331              :     {
    1332            8 :       setsigne(gel(W,F[i]),0);
    1333            8 :       R = F2xq_log_Coppersmith_d(W, mkF2(F[i],vT), r, n, T, m);
    1334            8 :       if (!R) return NULL;
    1335              :     }
    1336          428 :     o = Fp_add(o, mulis(R, E[i]), m);
    1337              :   }
    1338           58 :   return gc_INT(av, o);
    1339              : }
    1340              : 
    1341              : static GEN
    1342           80 : F2xq_log_Coppersmith_d(GEN W, GEN g, long r, long n, GEN T, GEN mo)
    1343              : {
    1344           80 :   pari_sp av = avma, av2;
    1345           80 :   long dT = get_F2x_degree(T), vT = get_F2x_var(T);
    1346           80 :   long dg = F2x_degree(g), k = r-1, m = maxss((dg-k)/2,0);
    1347           80 :   long i, j, l = dg-m, N;
    1348           80 :   GEN v = cgetg(k+m+1,t_MAT);
    1349           80 :   long h = dT>>n, d = dT-(h<<n);
    1350           80 :   GEN p1 = pol1_F2x(vT);
    1351           80 :   GEN R = F2x_add(F2x_shift(p1, dT), T);
    1352           80 :   GEN z = F2x_rem(F2x_shift(p1, h), g);
    1353          993 :   for(i=1; i<=k+m; i++)
    1354              :   {
    1355          913 :     gel(v,i) = F2x_to_F2v(F2x_shift(z,-l),m);
    1356          913 :     z = F2x_rem(F2x_shift(z,1),g);
    1357              :   }
    1358           80 :   v = F2m_ker(v);
    1359          880 :   for(i=1; i<=k; i++)
    1360          800 :     gel(v,i) = F2v_to_F2x(gel(v,i),vT);
    1361           80 :   N = 1<<k;
    1362           80 :   av2 = avma;
    1363        33016 :   for (i=1; i<N; i++)
    1364              :   {
    1365              :     GEN p,q,qh,a,b;
    1366        32994 :     set_avma(av2);
    1367        32994 :     q = pol0_F2x(vT);
    1368       362934 :     for(j=0; j<k; j++)
    1369       329940 :       if (i&(1UL<<j))
    1370       156105 :         q = F2x_add(q, gel(v,j+1));
    1371        32994 :     qh= F2x_shift(q,h);
    1372        32994 :     p = F2x_rem(qh,g);
    1373        32994 :     b = F2x_add(F2x_mul(R, F2x_pow2n(q, n)), F2x_shift(F2x_pow2n(p, n), d));
    1374        32994 :     if (lgpol(b)==0 || !F2x_is_smooth(b, r)) continue;
    1375           59 :     a = F2x_div(F2x_add(qh,p),g);
    1376           59 :     if (F2x_degree(F2x_gcd(a,q)) &&  F2x_degree(F2x_gcd(a,p))) continue;
    1377           59 :     if (!(lgpol(a)==0 || !F2x_is_smooth(a, r)))
    1378              :     {
    1379           58 :       GEN F = F2x_factorel(b);
    1380           58 :       GEN G = F2x_factorel(a);
    1381           58 :       GEN FG = vecsmall_concat(vecsmall_append(gel(F, 1), 2), gel(G, 1));
    1382           58 :       GEN E  = vecsmall_concat(vecsmall_append(gel(F, 2), -d),
    1383           58 :                                zv_z_mul(gel(G, 2),-(1L<<n)));
    1384           58 :       GEN R  = famatsmall_reduce(mkmat2(FG, E));
    1385           58 :       GEN l  = F2xq_log_from_rel(W, R, r, n, T, mo);
    1386           58 :       if (!l) continue;
    1387           58 :       l = Fp_div(l,int2n(n),mo);
    1388           58 :       if (dg <= r)
    1389              :       {
    1390            8 :         affii(l,gel(W,g[2]));
    1391            8 :         if (DEBUGLEVEL>1) err_printf("Found %lu\n", g[2]);
    1392              :       }
    1393           58 :       return gc_INT(av, l);
    1394              :     }
    1395              :   }
    1396           22 :   return gc_NULL(av);
    1397              : }
    1398              : 
    1399              : static GEN
    1400           57 : F2xq_log_find_rel(GEN b, long r, GEN T, GEN *g, ulong *e)
    1401              : {
    1402           57 :   pari_sp av = avma;
    1403              :   while (1)
    1404          767 :   {
    1405              :     GEN M;
    1406          824 :     *g = F2xq_mul(*g, b, T); (*e)++;
    1407          824 :     M = F2x_halfgcd(*g,T);
    1408          824 :     if (F2x_is_smooth(gcoeff(M,1,1), r))
    1409              :     {
    1410          353 :       GEN z = F2x_add(F2x_mul(gcoeff(M,1,1),*g), F2x_mul(gcoeff(M,1,2),T));
    1411          353 :       if (F2x_is_smooth(z, r))
    1412              :       {
    1413           57 :         GEN F = F2x_factorel(z);
    1414           57 :         GEN G = F2x_factorel(gcoeff(M,1,1));
    1415           57 :         GEN rel = mkmat2(vecsmall_concat(gel(F, 1),gel(G, 1)),
    1416           57 :                          vecsmall_concat(gel(F, 2),zv_neg(gel(G, 2))));
    1417           57 :         return gc_all(av, 2, &rel, g);
    1418              :       }
    1419              :     }
    1420          767 :     if (gc_needed(av,2))
    1421              :     {
    1422            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"F2xq_log_find_rel");
    1423            0 :       *g = gc_leaf(av, *g);
    1424              :     }
    1425              :   }
    1426              : }
    1427              : 
    1428              : static GEN
    1429           28 : F2xq_log_Coppersmith_rec(GEN W, long r2, GEN a, long r, long n, GEN T, GEN m)
    1430              : {
    1431           28 :   long vT = get_F2x_var(T);
    1432           28 :   GEN b = polx_F2x(vT);
    1433           28 :   ulong AV = 0;
    1434           28 :   GEN g = a, bad = pol0_F2x(vT);
    1435              :   pari_timer ti;
    1436              :   while(1)
    1437           29 :   {
    1438              :     long i, l;
    1439              :     GEN V, F, E, Ao;
    1440           57 :     timer_start(&ti);
    1441           57 :     V = F2xq_log_find_rel(b, r2, T, &g, &AV);
    1442           57 :     if (DEBUGLEVEL>1) timer_printf(&ti,"%ld-smooth element",r2);
    1443           57 :     F = gel(V,1); E = gel(V,2);
    1444           57 :     l = lg(F);
    1445           57 :     Ao = gen_0;
    1446          435 :     for(i=1; i<l; i++)
    1447              :     {
    1448          407 :       GEN Fi = mkF2(F[i], vT);
    1449              :       GEN R;
    1450          407 :       if (F2x_degree(Fi) <= r)
    1451              :       {
    1452          328 :         if (signe(gel(W,F[i]))==0)
    1453            0 :           break;
    1454          328 :         else if (signe(gel(W,F[i]))<0)
    1455              :         {
    1456            0 :           setsigne(gel(W,F[i]),0);
    1457            0 :           R = F2xq_log_Coppersmith_d(W,Fi,r,n,T,m);
    1458              :         } else
    1459          328 :           R = gel(W,F[i]);
    1460              :       }
    1461              :       else
    1462              :       {
    1463           79 :         if (F2x_equal(Fi,bad)) break;
    1464           72 :         R = F2xq_log_Coppersmith_d(W,Fi,r,n,T,m);
    1465           72 :         if (!R) bad = Fi;
    1466              :       }
    1467          400 :       if (!R) break;
    1468          378 :       Ao = Fp_add(Ao, mulis(R, E[i]), m);
    1469              :     }
    1470           57 :     if (i==l) return subiu(Ao,AV);
    1471              :   }
    1472              : }
    1473              : 
    1474              : /* Coppersmith:
    1475              :  T*X^e = X^(h*2^n)-R
    1476              :  (u*x^h + v)^(2^n) = u^(2^n)*X^(h*2^n)+v^(2^n)
    1477              :  (u*x^h + v)^(2^n) = u^(2^n)*R+v^(2^n)
    1478              : */
    1479              : 
    1480              : static GEN
    1481       147904 : rel_Coppersmith(GEN u, GEN v, long h, GEN R, long r, long n, long d)
    1482              : {
    1483              :   GEN b, F, G, M;
    1484       147904 :   GEN a = F2x_add(F2x_shift(u, h), v);
    1485       147904 :   if (!F2x_is_smooth(a, r)) return NULL;
    1486        49568 :   b = F2x_add(F2x_mul(R, F2x_pow2n(u, n)), F2x_shift(F2x_pow2n(v, n),d));
    1487        49568 :   if (!F2x_is_smooth(b, r)) return NULL;
    1488         7371 :   F = F2x_factorel(a);
    1489         7371 :   G = F2x_factorel(b);
    1490        14742 :   M = mkmat2(vecsmall_concat(gel(F, 1), vecsmall_append(gel(G, 1), 2)),
    1491        14742 :              vecsmall_concat(zv_z_mul(gel(F, 2),1UL<<n), vecsmall_append(zv_neg(gel(G, 2)),d)));
    1492         7371 :   return famatsmall_reduce(M);
    1493              : }
    1494              : 
    1495              : GEN
    1496         2047 : F2xq_log_Coppersmith_worker(GEN u, long i, GEN V, GEN R)
    1497              : {
    1498         2047 :   long r = V[1], h = V[2], n = V[3], d = V[4];
    1499         2047 :   pari_sp ltop = avma;
    1500         2047 :   GEN v = mkF2(0,u[1]);
    1501         2047 :   GEN L = cgetg(2*i+1, t_VEC);
    1502         2047 :   pari_sp av = avma;
    1503              :   long j;
    1504         2047 :   long nbtest=0, rel = 1;
    1505       148552 :   for(j=1; j<=i; j++)
    1506              :   {
    1507       146505 :     v[2] = j;
    1508       146505 :     set_avma(av);
    1509       146505 :     if (F2x_degree(F2x_gcd(u,v))==0)
    1510              :     {
    1511        73959 :       GEN z = rel_Coppersmith(u, v, h, R, r, n, d);
    1512        73959 :       nbtest++;
    1513        73959 :       if (z) { gel(L, rel++) = z; av = avma; }
    1514        73959 :       if (i==j) continue;
    1515        73945 :       z = rel_Coppersmith(v, u, h, R, r, n, d);
    1516        73945 :       nbtest++;
    1517        73945 :       if (z) { gel(L, rel++) = z; av = avma; }
    1518              :     }
    1519              :   }
    1520         2047 :   setlg(L,rel);
    1521         2047 :   return gc_GEN(ltop, mkvec2(stoi(nbtest), L));
    1522              : }
    1523              : 
    1524              : static GEN
    1525           14 : F2xq_log_Coppersmith(long nbrel, long r, long n, GEN T)
    1526              : {
    1527           14 :   long dT = get_F2x_degree(T), vT = get_F2x_var(T);
    1528           14 :   long h = dT>>n, d = dT-(h<<n);
    1529           14 :   GEN R = F2x_add(F2x_shift(pol1_F2x(vT), dT), T);
    1530           14 :   GEN u = mkF2(0,vT);
    1531           14 :   long rel = 1, nbtest = 0;
    1532           14 :   GEN M = cgetg(nbrel+1, t_VEC);
    1533           14 :   long i = 0;
    1534           14 :   GEN worker = snm_closure(is_entry("_F2xq_log_Coppersmith_worker"),
    1535              :                mkvec2(mkvecsmall4(r, h, n, d), R));
    1536              :   struct pari_mt pt;
    1537           14 :   long running, pending = 0, stop=0;
    1538           14 :   mt_queue_start(&pt, worker);
    1539           14 :   if (DEBUGLEVEL) err_printf("Coppersmith (R = %ld): ",F2x_degree(R));
    1540         2091 :   while ((running = !stop) || pending)
    1541              :   {
    1542              :     GEN L, done;
    1543              :     long j, l;
    1544         2077 :     u[2] = i;
    1545         2077 :     mt_queue_submit(&pt, 0, running ? mkvec2(u, stoi(i)): NULL);
    1546         2077 :     done = mt_queue_get(&pt, NULL, &pending);
    1547         2077 :     if (!done) continue;
    1548         2047 :     L = gel(done, 2); nbtest += itos(gel(done,1));
    1549         2047 :     l = lg(L);
    1550         2047 :     if (l > 1)
    1551              :     {
    1552         9117 :       for (j=1; j<l; j++)
    1553              :       {
    1554         7246 :         if (rel>nbrel) break;
    1555         7210 :         gel(M,rel++) = gel(L,j);
    1556         7210 :         if (DEBUGLEVEL && (rel&511UL)==0)
    1557            0 :           err_printf("%ld%%[%ld] ",rel*100/nbrel,i);
    1558              :       }
    1559              :     }
    1560         2047 :     if (rel>nbrel) stop=1;
    1561         2047 :     i++;
    1562              :   }
    1563           14 :   mt_queue_end(&pt);
    1564           14 :   if (DEBUGLEVEL) err_printf(": %ld tests\n", nbtest);
    1565           14 :   return M;
    1566              : }
    1567              : 
    1568              : static GEN
    1569           14 : smallirred_F2x(ulong n, long sv)
    1570              : {
    1571           14 :   GEN a = zero_zv(nbits2lg(n+1)-1);
    1572           14 :   a[1] = sv; F2x_set(a,n); a[2]++;
    1573          238 :   while (!F2x_is_irred(a)) a[2]+=2;
    1574           14 :   return a;
    1575              : }
    1576              : 
    1577              : static GEN
    1578           14 : check_kernel(long N, GEN M, long nbi, GEN T, GEN m)
    1579              : {
    1580           14 :   pari_sp av = avma;
    1581           14 :   long dT = get_F2x_degree(T), vT = get_F2x_var(T);
    1582           14 :   GEN K = FpMs_leftkernel_elt(M, N, m);
    1583           14 :   long i, f=0, tbs;
    1584           14 :   long l = lg(K), lm = lgefint(m);
    1585           14 :   GEN idx = diviiexact(int2um1(dT), m);
    1586           14 :   GEN g = F2xq_pow(polx_F2x(vT), idx, T);
    1587              :   GEN tab;
    1588              :   pari_timer ti;
    1589           14 :   if (DEBUGLEVEL) timer_start(&ti);
    1590           14 :   K = FpC_Fp_mul(K, Fp_inv(gel(K,2), m), m);
    1591           14 :   tbs = maxss(1, expu(nbi/expi(m)));
    1592           14 :   tab = F2xq_pow_init(g, int2n(dT), tbs, T);
    1593        57344 :   for(i=1; i<l; i++)
    1594              :   {
    1595        57330 :     GEN k = gel(K,i);
    1596        57330 :     if (signe(k)==0 || !F2x_equal(F2xq_pow_table(tab, k, T),
    1597              :                                   F2xq_pow(mkF2(i,vT), idx, T)))
    1598        52086 :       gel(K,i) = cgetineg(lm);
    1599              :     else
    1600         5244 :       f++;
    1601              :   }
    1602           14 :   if (DEBUGLEVEL) timer_printf(&ti,"found %ld/%ld logs", f, nbi);
    1603           14 :   return gc_upto(av, K);
    1604              : }
    1605              : 
    1606              : static GEN
    1607           14 : F2xq_log_index(GEN a0, GEN b0, GEN m, GEN T0)
    1608              : {
    1609           14 :   pari_sp av = avma;
    1610           14 :   GEN  M, S, a, b, Ao=NULL, Bo=NULL, W, e;
    1611              :   pari_timer ti;
    1612           14 :   long n = F2x_degree(T0), r = (long) (sqrt((double) 2*n))-(n>100);
    1613           14 :   GEN T = smallirred_F2x(n,T0[1]);
    1614           14 :   long d = 2, r2 = 3*r/2, d2 = 2;
    1615           14 :   long N = (1UL<<(r+1))-1UL;
    1616           14 :   long nbi = itos(ffsumnbirred(gen_2, r)), nbrel=nbi*5/4;
    1617           14 :   if (DEBUGLEVEL)
    1618              :   {
    1619            0 :     err_printf("F2xq_log: Parameters r=%ld r2=%ld\n", r,r2);
    1620            0 :     err_printf("F2xq_log: Size FB=%ld rel. needed=%ld\n", nbi, nbrel);
    1621            0 :     timer_start(&ti);
    1622              :   }
    1623           14 :   S = Flx_to_F2x(Flx_ffisom(F2x_to_Flx(T0),F2x_to_Flx(T),2));
    1624           14 :   a = F2x_F2xq_eval(a0, S, T);
    1625           14 :   b = F2x_F2xq_eval(b0, S, T);
    1626           14 :   if (DEBUGLEVEL) timer_printf(&ti,"model change");
    1627           14 :   M = F2xq_log_Coppersmith(nbrel,r,d,T);
    1628           14 :   if(DEBUGLEVEL)
    1629            0 :     timer_printf(&ti,"relations");
    1630           14 :   W = check_kernel(N, M, nbi, T, m);
    1631           14 :   timer_start(&ti);
    1632           14 :   Ao = F2xq_log_Coppersmith_rec(W, r2, a, r, d2, T, m);
    1633           14 :   if (DEBUGLEVEL) timer_printf(&ti,"smooth element");
    1634           14 :   Bo = F2xq_log_Coppersmith_rec(W, r2, b, r, d2, T, m);
    1635           14 :   if (DEBUGLEVEL) timer_printf(&ti,"smooth generator");
    1636           14 :   e = Fp_div(Ao, Bo, m);
    1637           14 :   if (!F2x_equal(F2xq_pow(b0,e,T0),a0)) pari_err_BUG("F2xq_log");
    1638           14 :   return gc_upto(av, e);
    1639              : }
    1640              : 
    1641              : static GEN
    1642       559320 : F2xq_easylog(void* E, GEN a, GEN g, GEN ord)
    1643              : {
    1644       559320 :   if (F2x_equal1(a)) return gen_0;
    1645       524625 :   if (F2x_equal(a,g)) return gen_1;
    1646       523779 :   if (typ(ord)!=t_INT) return NULL;
    1647       262244 :   if (expi(ord)<28) return NULL;
    1648           14 :   return F2xq_log_index(a,g,ord,(GEN)E);
    1649              : }
    1650              : 
    1651              : GEN
    1652       543777 : F2xq_log(GEN a, GEN g, GEN ord, GEN T)
    1653              : {
    1654       543777 :   GEN z, v = get_arith_ZZM(ord);
    1655       543777 :   ord = mkvec2(gel(v,1),ZM_famat_limit(gel(v,2),int2n(28)));
    1656       543777 :   z = gen_PH_log(a,g,ord,(void*)T,&F2xq_star);
    1657       543777 :   return z? z: cgetg(1,t_VEC);
    1658              : }
    1659              : 
    1660              : GEN
    1661       213015 : F2xq_Artin_Schreier(GEN a, GEN T)
    1662              : {
    1663       213015 :   pari_sp ltop=avma;
    1664       213015 :   long j,N = get_F2x_degree(T), vT = get_F2x_var(T);
    1665       213015 :   GEN Q = F2x_matFrobenius(T);
    1666      1478093 :   for (j=1; j<=N; j++)
    1667      1265078 :     F2m_flip(Q,j,j);
    1668       213015 :   F2v_add_inplace(gel(Q,1),a);
    1669       213015 :   Q = F2m_ker_sp(Q,0);
    1670       213015 :   if (lg(Q)!=2) return NULL;
    1671       213015 :   Q = gel(Q,1);
    1672       213015 :   Q[1] = vT;
    1673       213015 :   return gc_leaf(ltop, F2x_renormalize(Q, lg(Q)));
    1674              : }
    1675              : 
    1676              : GEN
    1677        61607 : F2xq_sqrt_fast(GEN c, GEN sqx, GEN T)
    1678              : {
    1679              :   GEN c0, c1;
    1680        61607 :   F2x_even_odd(c, &c0, &c1);
    1681        61607 :   return F2x_add(c0, F2xq_mul(c1, sqx, T));
    1682              : }
    1683              : 
    1684              : static int
    1685        19360 : F2x_is_x(GEN a) { return lg(a)==3 && a[2]==2; }
    1686              : 
    1687              : GEN
    1688        38844 : F2xq_sqrt(GEN a, GEN T)
    1689              : {
    1690        38844 :   pari_sp av = avma;
    1691        38844 :   long n = get_F2x_degree(T), vT = get_F2x_var(T);
    1692              :   GEN sqx;
    1693        38844 :   if (n==1) return F2x_copy(a);
    1694        38749 :   if (n==2) return F2xq_sqr(a,T);
    1695        19360 :   sqx = F2xq_autpow(mkF2(4, vT), n-1, T);
    1696        19360 :   return gc_leaf(av, F2x_is_x(a)? sqx: F2xq_sqrt_fast(a,sqx,T));
    1697              : }
    1698              : 
    1699              : GEN
    1700         8324 : F2xq_sqrtn(GEN a, GEN n, GEN T, GEN *zeta)
    1701              : {
    1702         8324 :   long dT = get_F2x_degree(T), vT = get_F2x_var(T);
    1703         8324 :   if (!lgpol(a))
    1704              :   {
    1705            7 :     if (signe(n) < 0) pari_err_INV("F2xq_sqrtn",a);
    1706            0 :     if (zeta)
    1707            0 :       *zeta=pol1_F2x(vT);
    1708            0 :     return pol0_F2x(vT);
    1709              :   }
    1710         8317 :   return gen_Shanks_sqrtn(a, n, int2um1(dT), zeta, (void*)T, &F2xq_star);
    1711              : }
    1712              : 
    1713              : GEN
    1714          161 : gener_F2xq(GEN T, GEN *po)
    1715              : {
    1716          161 :   long i, j, vT = get_F2x_var(T), f = get_F2x_degree(T);
    1717          161 :   pari_sp av0 = avma, av;
    1718              :   GEN g, L2, o, q;
    1719              : 
    1720          161 :   if (f == 1) {
    1721           21 :     if (po) *po = mkvec2(gen_1, trivial_fact());
    1722           21 :     return pol1_F2x(vT);
    1723              :   }
    1724          140 :   q = int2um1(f);
    1725          140 :   o = factor_pn_1(gen_2,f);
    1726          140 :   L2 = leafcopy( gel(o, 1) );
    1727          399 :   for (i = j = 1; i < lg(L2); i++)
    1728              :   {
    1729          259 :     if (absequaliu(gel(L2,i),2)) continue;
    1730          259 :     gel(L2,j++) = diviiexact(q, gel(L2,i));
    1731              :   }
    1732          140 :   setlg(L2, j);
    1733          229 :   for (av = avma;; set_avma(av))
    1734              :   {
    1735          229 :     g = random_F2x(f, vT);
    1736          229 :     if (F2x_degree(g) < 1) continue;
    1737          492 :     for (i = 1; i < j; i++)
    1738              :     {
    1739          352 :       GEN a = F2xq_pow(g, gel(L2,i), T);
    1740          352 :       if (F2x_equal1(a)) break;
    1741              :     }
    1742          205 :     if (i == j) break;
    1743              :   }
    1744          140 :   if (!po) g = gc_GEN(av0, g);
    1745              :   else {
    1746            0 :     *po = mkvec2(int2um1(f), o);
    1747            0 :     (void)gc_all(av0, 2, &g, po);
    1748              :   }
    1749          140 :   return g;
    1750              : }
    1751              : 
    1752              : static GEN
    1753          798 : _F2xq_neg(void *E, GEN x) { (void) E; return F2x_copy(x); }
    1754              : static GEN
    1755        15890 : _F2xq_rmul(void *E, GEN x, GEN y) { (void) E; return F2x_mul(x,y); }
    1756              : static GEN
    1757          413 : _F2xq_inv(void *E, GEN x) { return F2xq_inv(x, (GEN) E); }
    1758              : static int
    1759          973 : _F2xq_equal0(GEN x) { return lgpol(x)==0; }
    1760              : static GEN
    1761          693 : _F2xq_s(void *E, long x)
    1762          693 : { GEN T = (GEN) E;
    1763          693 :   long v = get_F2x_var(T);
    1764          693 :   return odd(x)? pol1_F2x(v): pol0_F2x(v);
    1765              : }
    1766              : 
    1767              : static const struct bb_field F2xq_field={_F2xq_red,_F2xq_add,_F2xq_rmul,_F2xq_neg,
    1768              :                                          _F2xq_inv,_F2xq_equal0,_F2xq_s};
    1769              : 
    1770         1701 : const struct bb_field *get_F2xq_field(void **E, GEN T)
    1771              : {
    1772         1701 :   *E = (void *) T;
    1773         1701 :   return &F2xq_field;
    1774              : }
    1775              : 
    1776              : /***********************************************************************/
    1777              : /**                                                                   **/
    1778              : /**                               F2xV                                **/
    1779              : /**                                                                   **/
    1780              : /***********************************************************************/
    1781              : /* F2xV are t_VEC with F2x coefficients. */
    1782              : 
    1783              : GEN
    1784        39202 : FlxC_to_F2xC(GEN x) { pari_APPLY_type(t_COL, Flx_to_F2x(gel(x,i))) }
    1785              : GEN
    1786            0 : F2xC_to_FlxC(GEN x) { pari_APPLY_type(t_COL, F2x_to_Flx(gel(x,i))) }
    1787              : GEN
    1788        11837 : F2xC_to_ZXC(GEN x) { pari_APPLY_type(t_COL, F2x_to_ZX(gel(x,i))) }
    1789              : GEN
    1790      1795936 : F2xV_to_F2m(GEN x, long n) { pari_APPLY_type(t_MAT, F2x_to_F2v(gel(x,i), n)) }
    1791              : 
    1792              : void
    1793        34237 : F2xV_to_FlxV_inplace(GEN v)
    1794              : {
    1795        34237 :   long i, l = lg(v);
    1796        80752 :   for(i = 1; i < l;i++) gel(v,i) = F2x_to_Flx(gel(v,i));
    1797        34237 : }
    1798              : void
    1799      1453162 : F2xV_to_ZXV_inplace(GEN v)
    1800              : {
    1801      1453162 :   long i, l = lg(v);
    1802      2774235 :   for(i = 1; i < l; i++) gel(v,i)= F2x_to_ZX(gel(v,i));
    1803      1453162 : }
    1804              : 
    1805              : /***********************************************************************/
    1806              : /**                                                                   **/
    1807              : /**                             F2xX                                  **/
    1808              : /**                                                                   **/
    1809              : /***********************************************************************/
    1810              : 
    1811              : GEN
    1812      2716269 : F2xX_renormalize(GEN /*in place*/ x, long lx)
    1813      2716269 : { return FlxX_renormalize(x, lx); }
    1814              : 
    1815              : GEN
    1816       447042 : pol1_F2xX(long v, long sv) { return pol1_FlxX(v, sv); }
    1817              : 
    1818              : GEN
    1819          441 : polx_F2xX(long v, long sv) { return polx_FlxX(v, sv); }
    1820              : 
    1821              : long
    1822       207075 : F2xY_degreex(GEN b)
    1823              : {
    1824       207075 :   long deg = 0, i;
    1825       207075 :   if (!signe(b)) return -1;
    1826      1343375 :   for (i = 2; i < lg(b); ++i)
    1827      1136300 :     deg = maxss(deg, F2x_degree(gel(b, i)));
    1828       207075 :   return deg;
    1829              : }
    1830              : 
    1831              : GEN
    1832          945 : FlxX_to_F2xX(GEN B)
    1833              : {
    1834          945 :   long lb=lg(B);
    1835              :   long i;
    1836          945 :   GEN b=cgetg(lb,t_POL);
    1837          945 :   b[1]=evalsigne(1)|(((ulong)B[1])&VARNBITS);
    1838         4718 :   for (i=2; i<lb; i++)
    1839         3773 :     gel(b,i) = Flx_to_F2x(gel(B,i));
    1840          945 :   return F2xX_renormalize(b, lb);
    1841              : }
    1842              : 
    1843              : GEN
    1844         5264 : ZXX_to_F2xX(GEN B, long v)
    1845              : {
    1846         5264 :   long lb=lg(B);
    1847              :   long i;
    1848         5264 :   GEN b=cgetg(lb,t_POL);
    1849         5264 :   b[1]=evalsigne(1)|(((ulong)B[1])&VARNBITS);
    1850        24507 :   for (i=2; i<lb; i++)
    1851        19243 :     switch (typ(gel(B,i)))
    1852              :     {
    1853         9141 :     case t_INT:
    1854         9141 :       gel(b,i) = Z_to_F2x(gel(B,i), evalvarn(v));
    1855         9141 :       break;
    1856        10102 :     case t_POL:
    1857        10102 :       gel(b,i) = ZX_to_F2x(gel(B,i));
    1858        10102 :       break;
    1859              :     }
    1860         5264 :   return F2xX_renormalize(b, lb);
    1861              : }
    1862              : 
    1863              : GEN
    1864           56 : F2xX_to_FlxX(GEN B)
    1865              : {
    1866           56 :   long i, lb = lg(B);
    1867           56 :   GEN b = cgetg(lb,t_POL);
    1868          266 :   for (i=2; i<lb; i++)
    1869          210 :     gel(b,i) = F2x_to_Flx(gel(B,i));
    1870           56 :   b[1] = B[1]; return b;
    1871              : }
    1872              : 
    1873              : GEN
    1874         1470 : F2xX_to_ZXX(GEN B)
    1875              : {
    1876         1470 :   long i, lb = lg(B);
    1877         1470 :   GEN b = cgetg(lb,t_POL);
    1878         4991 :   for (i=2; i<lb; i++)
    1879              :   {
    1880         3521 :     GEN c = gel(B,i);
    1881         3521 :     gel(b,i) = lgpol(c) ?  F2x_equal1(c) ? gen_1 : F2x_to_ZX(c) : gen_0;
    1882              :   }
    1883         1470 :   b[1] = B[1]; return b;
    1884              : }
    1885              : 
    1886              : GEN
    1887        80589 : F2xX_deriv(GEN z)
    1888              : {
    1889        80589 :   long i,l = lg(z)-1;
    1890              :   GEN x;
    1891        80589 :   if (l < 2) l = 2;
    1892        80589 :   x = cgetg(l, t_POL); x[1] = z[1];
    1893       528028 :   for (i=2; i<l; i++) gel(x,i) = odd(i) ? pol0_F2x(mael(z,i+1,1)): gel(z,i+1);
    1894        80589 :   return F2xX_renormalize(x,l);
    1895              : }
    1896              : 
    1897              : static GEN
    1898         1186 : F2xX_addspec(GEN x, GEN y, long lx, long ly)
    1899              : {
    1900              :   long i,lz;
    1901              :   GEN z;
    1902         1186 :   if (ly>lx) swapspec(x,y, lx,ly);
    1903         1186 :   lz = lx+2; z = cgetg(lz, t_POL);
    1904       139499 :   for (i=0; i<ly; i++) gel(z,i+2) = F2x_add(gel(x,i), gel(y,i));
    1905         1186 :   for (   ; i<lx; i++) gel(z,i+2) = F2x_copy(gel(x,i));
    1906         1186 :   z[1] = 0; return F2xX_renormalize(z, lz);
    1907              : }
    1908              : 
    1909              : GEN
    1910       424054 : F2xX_add(GEN x, GEN y)
    1911              : {
    1912              :   long i,lz;
    1913              :   GEN z;
    1914       424054 :   long lx=lg(x);
    1915       424054 :   long ly=lg(y);
    1916       424054 :   if (ly>lx) swapspec(x,y, lx,ly);
    1917       424054 :   lz = lx; z = cgetg(lz, t_POL); z[1]=x[1];
    1918      1502295 :   for (i=2; i<ly; i++) gel(z,i) = F2x_add(gel(x,i), gel(y,i));
    1919      1682976 :   for (   ; i<lx; i++) gel(z,i) = F2x_copy(gel(x,i));
    1920       424054 :   return F2xX_renormalize(z, lz);
    1921              : }
    1922              : 
    1923              : GEN
    1924            0 : F2xX_F2x_add(GEN x, GEN y)
    1925              : {
    1926            0 :   long i, lz = lg(y);
    1927              :   GEN z;
    1928            0 :   if (signe(y) == 0) return scalarpol(x, varn(y));
    1929            0 :   z = cgetg(lz,t_POL); z[1] = y[1];
    1930            0 :   gel(z,2) = F2x_add(gel(y,2), x);
    1931            0 :   if (lz == 3) z = F2xX_renormalize(z,lz);
    1932              :   else
    1933            0 :     for(i=3;i<lz;i++) gel(z,i) = F2x_copy(gel(y,i));
    1934            0 :   return z;
    1935              : }
    1936              : 
    1937              : GEN
    1938       482261 : F2xX_F2x_mul(GEN P, GEN U)
    1939              : {
    1940       482261 :   long i, lP = lg(P);
    1941       482261 :   GEN res = cgetg(lP,t_POL);
    1942       482261 :   res[1] = P[1];
    1943      2354583 :   for(i=2; i<lP; i++)
    1944      1872322 :     gel(res,i) = F2x_mul(U,gel(P,i));
    1945       482261 :   return F2xX_renormalize(res, lP);
    1946              : }
    1947              : 
    1948              : GEN
    1949       136640 : F2xY_F2xqV_evalx(GEN P, GEN x, GEN T)
    1950              : {
    1951       136640 :   long i, lP = lg(P);
    1952       136640 :   GEN res = cgetg(lP,t_POL);
    1953       136640 :   res[1] = P[1];
    1954       618663 :   for(i=2; i<lP; i++)
    1955       482023 :     gel(res,i) = F2x_F2xqV_eval(gel(P,i), x, T);
    1956       136640 :   return F2xX_renormalize(res, lP);
    1957              : }
    1958              : 
    1959              : GEN
    1960            0 : F2xY_F2xq_evalx(GEN P, GEN x, GEN T)
    1961              : {
    1962            0 :   pari_sp av = avma;
    1963            0 :   long n = brent_kung_optpow(get_F2x_degree(T)-1,lgpol(P),1);
    1964            0 :   GEN xp = F2xq_powers(x, n, T);
    1965            0 :   return gc_upto(av, F2xY_F2xqV_evalx(P, xp, T));
    1966              : }
    1967              : 
    1968              : static GEN
    1969         6038 : F2xX_to_Kronecker_spec(GEN P, long n, long d)
    1970              : {
    1971         6038 :   long i, k, l, N = 2*d + 1;
    1972         6038 :   long dP = n+1;
    1973              :   GEN x;
    1974         6038 :   if (n == 0) return pol0_Flx(P[1]&VARNBITS);
    1975         6038 :   l = nbits2nlong(N*dP+d+1);
    1976         6038 :   x = zero_zv(l+1);
    1977       368117 :   for (k=i=0; i<n; i++, k+=N)
    1978              :   {
    1979       362079 :     GEN c = gel(P,i);
    1980       362079 :     F2x_addshiftip(x, c, k);
    1981              :   }
    1982         6038 :   x[1] = P[1]&VARNBITS; return F2x_renormalize(x, l+2);
    1983              : }
    1984              : 
    1985              : GEN
    1986       311050 : F2xX_to_Kronecker(GEN P, long d)
    1987              : {
    1988       311050 :   long i, k, l, N = 2*d + 1;
    1989       311050 :   long dP = degpol(P);
    1990              :   GEN x;
    1991       311050 :   if (dP < 0) return pol0_Flx(P[1]&VARNBITS);
    1992       309742 :   l = nbits2nlong(N*dP+d+1);
    1993       309742 :   x = zero_zv(l+1);
    1994      1719603 :   for (k=i=0; i<=dP; i++, k+=N)
    1995              :   {
    1996      1409861 :     GEN c = gel(P,i+2);
    1997      1409861 :     F2x_addshiftip(x, c, k);
    1998              :   }
    1999       309742 :   x[1] = P[1]&VARNBITS; return F2x_renormalize(x, l+2);
    2000              : }
    2001              : 
    2002              : static GEN
    2003      1610696 : F2x_slice(GEN x, long n, long d)
    2004              : {
    2005      1610696 :   ulong ib, il=dvmduBIL(n, &ib);
    2006      1610696 :   ulong db, dl=dvmduBIL(d, &db);
    2007      1610696 :   long lN = dl+2+(db?1:0);
    2008      1610696 :   GEN t = cgetg(lN,t_VECSMALL);
    2009      1610696 :   t[1] = x[1];
    2010      1610696 :   if (ib)
    2011              :   {
    2012      1444632 :     ulong i, ic = BITS_IN_LONG-ib;
    2013      1444632 :     ulong r = uel(x,2+il)>>ib;
    2014      1445200 :     for(i=0; i<dl; i++)
    2015              :     {
    2016          568 :       uel(t,2+i) = (uel(x,3+il+i)<<ic)|r;
    2017          568 :       r = uel(x,3+il+i)>>ib;
    2018              :     }
    2019      1444632 :     if (db)
    2020      1444632 :       uel(t,2+i) = (uel(x,3+il+i)<<ic)|r;
    2021              :   }
    2022              :   else
    2023              :   {
    2024              :     long i;
    2025       332276 :     for(i=2; i<lN; i++)
    2026       166212 :       uel(t,i) = uel(x,il+i);
    2027              :   }
    2028      1610696 :   if (db) uel(t,lN-1) &= (1UL<<db)-1;
    2029      1610696 :   return F2x_renormalize(t, lN);
    2030              : }
    2031              : 
    2032              : GEN
    2033       158544 : Kronecker_to_F2xqX(GEN z, GEN T)
    2034              : {
    2035       158544 :   long lz = F2x_degree(z)+1;
    2036       158544 :   long i, j, N = get_F2x_degree(T)*2 + 1;
    2037       158544 :   long lx = lz / (N-2);
    2038       158544 :   GEN x = cgetg(lx+3,t_POL);
    2039       158544 :   x[1] = z[1];
    2040      1769240 :   for (i=0, j=2; i<lz; i+=N, j++)
    2041              :   {
    2042      1610696 :     GEN t = F2x_slice(z,i,minss(lz-i,N));
    2043      1610696 :     t[1] = T[1];
    2044      1610696 :     gel(x,j) = F2x_rem(t, T);
    2045              :   }
    2046       158544 :   return F2xX_renormalize(x, j);
    2047              : }
    2048              : 
    2049              : GEN
    2050            0 : F2xX_to_F2xC(GEN x, long N, long sv)
    2051              : {
    2052              :   long i, l;
    2053              :   GEN z;
    2054            0 :   l = lg(x)-1; x++;
    2055            0 :   if (l > N+1) l = N+1; /* truncate higher degree terms */
    2056            0 :   z = cgetg(N+1,t_COL);
    2057            0 :   for (i=1; i<l ; i++) gel(z,i) = gel(x,i);
    2058            0 :   for (   ; i<=N; i++) gel(z,i) = pol0_F2x(sv);
    2059            0 :   return z;
    2060              : }
    2061              : 
    2062              : GEN
    2063            0 : F2xXV_to_F2xM(GEN v, long n, long sv)
    2064              : {
    2065            0 :   long j, N = lg(v);
    2066            0 :   GEN y = cgetg(N, t_MAT);
    2067            0 :   for (j=1; j<N; j++) gel(y,j) = F2xX_to_F2xC(gel(v,j), n, sv);
    2068            0 :   return y;
    2069              : }
    2070              : 
    2071              : /***********************************************************************/
    2072              : /**                                                                   **/
    2073              : /**                             F2xXV/F2xXC                           **/
    2074              : /**                                                                   **/
    2075              : /***********************************************************************/
    2076              : 
    2077              : GEN
    2078         1330 : FlxXC_to_F2xXC(GEN x) { pari_APPLY_type(t_COL, FlxX_to_F2xX(gel(x,i))); }
    2079              : GEN
    2080         2611 : F2xXC_to_ZXXC(GEN x) { pari_APPLY_type(t_COL, F2xX_to_ZXX(gel(x,i))); }
    2081              : 
    2082              : /***********************************************************************/
    2083              : /**                                                                   **/
    2084              : /**                             F2xqX                                 **/
    2085              : /**                                                                   **/
    2086              : /***********************************************************************/
    2087              : 
    2088              : static GEN
    2089       784233 : get_F2xqX_red(GEN T, GEN *B)
    2090              : {
    2091       784233 :   if (typ(T)!=t_VEC) { *B=NULL; return T; }
    2092         2842 :   *B = gel(T,1); return gel(T,2);
    2093              : }
    2094              : 
    2095              : GEN
    2096         2856 : random_F2xqX(long d1, long v, GEN T)
    2097              : {
    2098         2856 :   long dT = get_F2x_degree(T), vT = get_F2x_var(T);
    2099         2856 :   long i, d = d1+2;
    2100         2856 :   GEN y = cgetg(d,t_POL); y[1] = evalsigne(1) | evalvarn(v);
    2101        19124 :   for (i=2; i<d; i++) gel(y,i) = random_F2x(dT, vT);
    2102         2856 :   return FlxX_renormalize(y,d);
    2103              : }
    2104              : 
    2105              : GEN
    2106      1006014 : F2xqX_red(GEN z, GEN T)
    2107              : {
    2108              :   GEN res;
    2109      1006014 :   long i, l = lg(z);
    2110      1006014 :   res = cgetg(l,t_POL); res[1] = z[1];
    2111      5674841 :   for(i=2;i<l;i++) gel(res,i) = F2x_rem(gel(z,i),T);
    2112      1006014 :   return F2xX_renormalize(res,l);
    2113              : }
    2114              : 
    2115              : GEN
    2116         6993 : F2xqX_F2xq_mul(GEN P, GEN U, GEN T)
    2117              : {
    2118         6993 :   long i, lP = lg(P);
    2119         6993 :   GEN res = cgetg(lP,t_POL);
    2120         6993 :   res[1] = P[1];
    2121        39165 :   for(i=2; i<lP; i++)
    2122        32172 :     gel(res,i) = F2xq_mul(U,gel(P,i), T);
    2123         6993 :   return F2xX_renormalize(res, lP);
    2124              : }
    2125              : 
    2126              : GEN
    2127       206606 : F2xqX_F2xq_mul_to_monic(GEN P, GEN U, GEN T)
    2128              : {
    2129       206606 :   long i, lP = lg(P);
    2130       206606 :   GEN res = cgetg(lP,t_POL);
    2131       206606 :   res[1] = P[1];
    2132      1131813 :   for(i=2; i<lP-1; i++) gel(res,i) = F2xq_mul(U,gel(P,i), T);
    2133       206606 :   gel(res,lP-1) = pol1_F2x(T[1]);
    2134       206606 :   return F2xX_renormalize(res, lP);
    2135              : }
    2136              : 
    2137              : GEN
    2138       206620 : F2xqX_normalize(GEN z, GEN T)
    2139              : {
    2140       206620 :   GEN p1 = leading_coeff(z);
    2141       206620 :   if (!lgpol(z) || (!degpol(p1) && p1[1] == 1)) return z;
    2142       206606 :   return F2xqX_F2xq_mul_to_monic(z, F2xq_inv(p1,T), T);
    2143              : }
    2144              : 
    2145              : GEN
    2146       155525 : F2xqX_mul(GEN x, GEN y, GEN T)
    2147              : {
    2148       155525 :   pari_sp ltop=avma;
    2149              :   GEN z, kx, ky;
    2150       155525 :   long d = get_F2x_degree(T);
    2151       155525 :   kx= F2xX_to_Kronecker(x, d);
    2152       155525 :   ky= F2xX_to_Kronecker(y, d);
    2153       155525 :   z = F2x_mul(ky, kx);
    2154       155525 :   z = Kronecker_to_F2xqX(z, T);
    2155       155525 :   return gc_upto(ltop, z);
    2156              : }
    2157              : 
    2158              : static GEN
    2159         3019 : F2xqX_mulspec(GEN x, GEN y, GEN T, long nx, long ny)
    2160              : {
    2161         3019 :   pari_sp ltop=avma;
    2162              :   GEN z, kx, ky;
    2163         3019 :   long dT = get_F2x_degree(T);
    2164         3019 :   kx= F2xX_to_Kronecker_spec(x, nx, dT);
    2165         3019 :   ky= F2xX_to_Kronecker_spec(y, ny, dT);
    2166         3019 :   z = F2x_mul(ky, kx);
    2167         3019 :   z = Kronecker_to_F2xqX(z,T);
    2168         3019 :   return gc_upto(ltop,z);
    2169              : }
    2170              : 
    2171              : GEN
    2172       105488 : F2xqX_sqr(GEN x, GEN T)
    2173              : {
    2174       105488 :   long d = degpol(x), l = 2*d+3;
    2175              :   GEN z;
    2176       105488 :   if (!signe(x)) return pol_0(varn(x));
    2177       105481 :   z = cgetg(l,t_POL);
    2178       105481 :   z[1] = x[1];
    2179       105481 :   if (d > 0)
    2180              :   {
    2181       105383 :     GEN u = pol0_F2x(T[1]);
    2182              :     long i,j;
    2183       269258 :     for (i=2,j=2; i<d+2; i++,j+=2)
    2184              :     {
    2185       163875 :       gel(z, j) = F2xq_sqr(gel(x, i), T);
    2186       163875 :       gel(z, j+1) = u;
    2187              :     }
    2188              :   }
    2189       105481 :   gel(z, 2+2*d) = F2xq_sqr(gel(x, 2+d), T);
    2190       105481 :   return FlxX_renormalize(z, l);
    2191              : }
    2192              : 
    2193              : static GEN
    2194          882 : _F2xqX_mul(void *data,GEN a,GEN b) { return F2xqX_mul(a,b, (GEN) data); }
    2195              : static GEN
    2196            0 : _F2xqX_sqr(void *data,GEN a) { return F2xqX_sqr(a, (GEN) data); }
    2197              : GEN
    2198            0 : F2xqX_powu(GEN x, ulong n, GEN T)
    2199            0 : { return gen_powu(x, n, (void*)T, &_F2xqX_sqr, &_F2xqX_mul); }
    2200              : 
    2201              : GEN
    2202            7 : F2xqXV_prod(GEN V, GEN T)
    2203              : {
    2204            7 :   return gen_product(V, (void*)T, &_F2xqX_mul);
    2205              : }
    2206              : 
    2207              : static GEN
    2208            7 : F2xqV_roots_to_deg1(GEN x, GEN T, long v)
    2209              : {
    2210            7 :   long sv = get_Flx_var(T);
    2211          896 :   pari_APPLY_same(deg1pol_shallow(pol1_F2x(sv),gel(x,i), v))
    2212              : }
    2213              : 
    2214              : GEN
    2215            7 : F2xqV_roots_to_pol(GEN V, GEN T, long v)
    2216              : {
    2217            7 :   pari_sp ltop = avma;
    2218            7 :   GEN W = F2xqV_roots_to_deg1(V, T, v);
    2219            7 :   return gc_upto(ltop, F2xqXV_prod(W, T));
    2220              : }
    2221              : 
    2222              : static GEN
    2223       545842 : F2xqX_divrem_basecase(GEN x, GEN y, GEN T, GEN *pr)
    2224              : {
    2225       545842 :   long vx = varn(x), dx = degpol(x), dy = degpol(y), dz, i, j, sx, lr;
    2226              :   pari_sp av0, av;
    2227              :   GEN z, p1, rem, lead;
    2228              : 
    2229       545842 :   if (!signe(y)) pari_err_INV("F2xqX_divrem",y);
    2230       545842 :   if (dx < dy)
    2231              :   {
    2232            0 :     if (pr)
    2233              :     {
    2234            0 :       av0 = avma; x = F2xqX_red(x, T);
    2235            0 :       if (pr == ONLY_DIVIDES) { set_avma(av0); return signe(x)? NULL: pol_0(vx); }
    2236            0 :       if (pr == ONLY_REM) return x;
    2237            0 :       *pr = x;
    2238              :     }
    2239            0 :     return pol_0(vx);
    2240              :   }
    2241       545842 :   lead = leading_coeff(y);
    2242       545842 :   if (!dy) /* y is constant */
    2243              :   {
    2244       115631 :     if (pr && pr != ONLY_DIVIDES)
    2245              :     {
    2246       105607 :       if (pr == ONLY_REM) return pol_0(vx);
    2247           21 :       *pr = pol_0(vx);
    2248              :     }
    2249        10045 :     if (F2x_equal1(lead)) return gcopy(x);
    2250         6986 :     av0 = avma; x = F2xqX_F2xq_mul(x,F2xq_inv(lead,T),T);
    2251         6986 :     return gc_upto(av0,x);
    2252              :   }
    2253       430211 :   av0 = avma; dz = dx-dy;
    2254       430211 :   lead = F2x_equal1(lead)? NULL: gclone(F2xq_inv(lead,T));
    2255       430211 :   set_avma(av0);
    2256       430211 :   z = cgetg(dz+3,t_POL); z[1] = x[1];
    2257       430211 :   x += 2; y += 2; z += 2;
    2258              : 
    2259       430211 :   p1 = gel(x,dx); av = avma;
    2260       430211 :   gel(z,dz) = lead? gc_upto(av, F2xq_mul(p1,lead, T)): leafcopy(p1);
    2261      1280252 :   for (i=dx-1; i>=dy; i--)
    2262              :   {
    2263       850041 :     av = avma; p1 = gel(x,i);
    2264      2662139 :     for (j=i-dy+1; j<=i && j<=dz; j++)
    2265      1812098 :       p1 = F2x_add(p1, F2x_mul(gel(z,j),gel(y,i-j)));
    2266       850041 :     if (lead) p1 = F2x_mul(p1, lead);
    2267       850041 :     gel(z,i-dy) = gc_leaf(av, F2x_rem(p1,T));
    2268              :   }
    2269       430211 :   if (!pr) { guncloneNULL(lead); return z-2; }
    2270              : 
    2271       407051 :   rem = (GEN)avma; av = (pari_sp)new_chunk(dx+3);
    2272       630350 :   for (sx=0; ; i--)
    2273              :   {
    2274       630350 :     p1 = gel(x,i);
    2275      1903167 :     for (j=0; j<=i && j<=dz; j++)
    2276      1272817 :       p1 = F2x_add(p1, F2x_mul(gel(z,j),gel(y,i-j)));
    2277       630350 :     p1 = F2x_rem(p1, T); if (lgpol(p1)) { sx = 1; break; }
    2278       286339 :     if (!i) break;
    2279       223299 :     set_avma(av);
    2280              :   }
    2281       407051 :   if (pr == ONLY_DIVIDES)
    2282              :   {
    2283            0 :     guncloneNULL(lead);
    2284            0 :     if (sx) return gc_NULL(av0);
    2285            0 :     return gc_const((pari_sp)rem, z-2);
    2286              :   }
    2287       407051 :   lr=i+3; rem -= lr; av = (pari_sp)rem;
    2288       407051 :   rem[0] = evaltyp(t_POL) | _evallg(lr);
    2289       407051 :   rem[1] = z[-1];
    2290       407051 :   rem += 2; gel(rem,i) = gc_leaf(av, p1);
    2291      1381790 :   for (i--; i>=0; i--)
    2292              :   {
    2293       974739 :     av = avma; p1 = gel(x,i);
    2294      3409272 :     for (j=0; j<=i && j<=dz; j++)
    2295      2434533 :       p1 = F2x_add(p1, F2x_mul(gel(z,j),gel(y,i-j)));
    2296       974739 :     gel(rem,i) = gc_leaf(av, F2x_rem(p1, T));
    2297              :   }
    2298       407051 :   rem -= 2;
    2299       407051 :   guncloneNULL(lead);
    2300       407051 :   if (!sx) (void)F2xX_renormalize(rem, lr);
    2301       407051 :   if (pr == ONLY_REM) return gc_upto(av0,rem);
    2302           35 :   *pr = rem; return z-2;
    2303              : }
    2304              : 
    2305              : static GEN
    2306         2423 : F2xX_recipspec(GEN x, long l, long n, long vs)
    2307              : {
    2308              :   long i;
    2309         2423 :   GEN z = cgetg(n+2,t_POL);
    2310         2423 :   z[1] = 0; z += 2;
    2311       139712 :   for(i=0; i<l; i++)
    2312       137289 :     gel(z,n-i-1) = F2x_copy(gel(x,i));
    2313         2423 :   for(   ; i<n; i++)
    2314            0 :     gel(z,n-i-1) = pol0_F2x(vs);
    2315         2423 :   return F2xX_renormalize(z-2,n+2);
    2316              : }
    2317              : 
    2318              : static GEN
    2319            0 : F2xqX_invBarrett_basecase(GEN T, GEN Q)
    2320              : {
    2321            0 :   long i, l=lg(T)-1, lr = l-1, k;
    2322            0 :   long sv=Q[1];
    2323            0 :   GEN r=cgetg(lr,t_POL); r[1]=T[1];
    2324            0 :   gel(r,2) = pol1_F2x(sv);
    2325            0 :   for (i=3;i<lr;i++)
    2326              :   {
    2327            0 :     pari_sp ltop=avma;
    2328            0 :     GEN u = gel(T,l-i+2);
    2329            0 :     for (k=3;k<i;k++)
    2330            0 :       u = F2x_add(u, F2xq_mul(gel(T,l-i+k),gel(r,k),Q));
    2331            0 :     gel(r,i) = gc_upto(ltop, u);
    2332              :   }
    2333            0 :   r = F2xX_renormalize(r,lr);
    2334            0 :   return r;
    2335              : }
    2336              : 
    2337              : /* Return new lgpol */
    2338              : static long
    2339         3337 : F2xX_lgrenormalizespec(GEN x, long lx)
    2340              : {
    2341              :   long i;
    2342         3526 :   for (i = lx-1; i>=0; i--)
    2343         3526 :     if (lgpol(gel(x,i))) break;
    2344         3337 :   return i+1;
    2345              : }
    2346              : 
    2347              : static GEN
    2348           45 : F2xqX_invBarrett_Newton(GEN S, GEN T)
    2349              : {
    2350           45 :   pari_sp av = avma;
    2351           45 :   long nold, lx, lz, lq, l = degpol(S), i, lQ;
    2352           45 :   GEN q, y, z, x = cgetg(l+2, t_POL) + 2;
    2353           45 :   long dT = get_F2x_degree(T);
    2354           45 :   ulong mask = quadratic_prec_mask(l-2); /* assume l > 2 */
    2355         5337 :   for (i=0;i<l;i++) gel(x,i) = pol0_F2x(T[1]);
    2356           45 :   q = F2xX_recipspec(S+2,l+1,l+1,dT);
    2357           45 :   lQ = lgpol(q); q+=2;
    2358              :   /* We work on _spec_ FlxX's, all the l[xzq] below are lgpol's */
    2359              : 
    2360              :   /* initialize */
    2361           45 :   gel(x,0) = F2xq_inv(gel(q,0),T);
    2362           45 :   if (lQ>1 && F2x_degree(gel(q,1)) >= dT)
    2363            0 :     gel(q,1) = F2x_rem(gel(q,1), T);
    2364           45 :   if (lQ>1 && lgpol(gel(q,1)))
    2365           38 :   {
    2366           38 :     GEN u = gel(q, 1);
    2367           38 :     if (!F2x_equal1(gel(x,0))) u = F2xq_mul(u, F2xq_sqr(gel(x,0), T), T);
    2368           38 :     else u = F2x_copy(u);
    2369           38 :     gel(x,1) = u; lx = 2;
    2370              :   }
    2371              :   else
    2372            7 :     lx = 1;
    2373           45 :   nold = 1;
    2374          367 :   for (; mask > 1; )
    2375              :   { /* set x -= x(x*q - 1) + O(t^(nnew + 1)), knowing x*q = 1 + O(t^(nold+1)) */
    2376          322 :     long i, lnew, nnew = nold << 1;
    2377              : 
    2378          322 :     if (mask & 1) nnew--;
    2379          322 :     mask >>= 1;
    2380              : 
    2381          322 :     lnew = nnew + 1;
    2382          322 :     lq = F2xX_lgrenormalizespec(q, minss(lQ,lnew));
    2383          322 :     z = F2xqX_mulspec(x, q, T, lx, lq); /* FIXME: high product */
    2384          322 :     lz = lgpol(z); if (lz > lnew) lz = lnew;
    2385          322 :     z += 2;
    2386              :     /* subtract 1 [=>first nold words are 0]: renormalize so that z(0) != 0 */
    2387          644 :     for (i = nold; i < lz; i++) if (lgpol(gel(z,i))) break;
    2388          322 :     nold = nnew;
    2389          322 :     if (i >= lz) continue; /* z-1 = 0(t^(nnew + 1)) */
    2390              : 
    2391              :     /* z + i represents (x*q - 1) / t^i */
    2392          322 :     lz = F2xX_lgrenormalizespec (z+i, lz-i);
    2393          322 :     z = F2xqX_mulspec(x, z+i, T, lx, lz); /* FIXME: low product */
    2394          322 :     lz = lgpol(z); z += 2;
    2395          322 :     if (lz > lnew-i) lz = F2xX_lgrenormalizespec(z, lnew-i);
    2396              : 
    2397          322 :     lx = lz+ i;
    2398          322 :     y  = x + i; /* x -= z * t^i, in place */
    2399         5479 :     for (i = 0; i < lz; i++) gel(y,i) = gel(z,i);
    2400              :   }
    2401           45 :   x -= 2; setlg(x, lx + 2); x[1] = S[1];
    2402           45 :   return gc_GEN(av, x);
    2403              : }
    2404              : 
    2405              : GEN
    2406           45 : F2xqX_invBarrett(GEN T, GEN Q)
    2407              : {
    2408           45 :   pari_sp ltop=avma;
    2409           45 :   long l=lg(T), v = varn(T);
    2410              :   GEN r;
    2411           45 :   GEN c = gel(T,l-1);
    2412           45 :   if (l<5) return pol_0(v);
    2413           45 :   if (l<=F2xqX_INVBARRETT_LIMIT)
    2414              :   {
    2415            0 :     if (!F2x_equal1(c))
    2416              :     {
    2417            0 :       GEN ci = F2xq_inv(c,Q);
    2418            0 :       T = F2xqX_F2xq_mul(T, ci, Q);
    2419            0 :       r = F2xqX_invBarrett_basecase(T,Q);
    2420            0 :       r = F2xqX_F2xq_mul(r,ci,Q);
    2421              :     } else
    2422            0 :       r = F2xqX_invBarrett_basecase(T,Q);
    2423              :   } else
    2424           45 :     r = F2xqX_invBarrett_Newton(T,Q);
    2425           45 :   return gc_upto(ltop, r);
    2426              : }
    2427              : 
    2428              : GEN
    2429       220365 : F2xqX_get_red(GEN S, GEN T)
    2430              : {
    2431       220365 :   if (typ(S)==t_POL && lg(S)>F2xqX_BARRETT_LIMIT)
    2432           42 :     retmkvec2(F2xqX_invBarrett(S, T), S);
    2433       220323 :   return S;
    2434              : }
    2435              : 
    2436              : /* Compute x mod S where 2 <= degpol(S) <= l+1 <= 2*(degpol(S)-1)
    2437              :  *  * and mg is the Barrett inverse of S. */
    2438              : static GEN
    2439         1189 : F2xqX_divrem_Barrettspec(GEN x, long l, GEN mg, GEN S, GEN T, GEN *pr)
    2440              : {
    2441              :   GEN q, r;
    2442         1189 :   long lt = degpol(S); /*We discard the leading term*/
    2443              :   long ld, lm, lT, lmg;
    2444         1189 :   ld = l-lt;
    2445         1189 :   lm = minss(ld, lgpol(mg));
    2446         1189 :   lT  = F2xX_lgrenormalizespec(S+2,lt);
    2447         1189 :   lmg = F2xX_lgrenormalizespec(mg+2,lm);
    2448         1189 :   q = F2xX_recipspec(x+lt,ld,ld,0);               /* q = rec(x)     lq<=ld*/
    2449         1189 :   q = F2xqX_mulspec(q+2,mg+2,T,lgpol(q),lmg);   /* q = rec(x) * mg lq<=ld+lm*/
    2450         1189 :   q = F2xX_recipspec(q+2,minss(ld,lgpol(q)),ld,0);/* q = rec (rec(x) * mg) lq<=ld*/
    2451         1189 :   if (!pr) return q;
    2452         1186 :   r = F2xqX_mulspec(q+2,S+2,T,lgpol(q),lT);     /* r = q*pol        lr<=ld+lt*/
    2453         1186 :   r = F2xX_addspec(x,r+2,lt,minss(lt,lgpol(r)));/* r = x - r   lr<=lt */
    2454         1186 :   if (pr == ONLY_REM) return r;
    2455            3 :   *pr = r; return q;
    2456              : }
    2457              : 
    2458              : static GEN
    2459         1186 : F2xqX_divrem_Barrett(GEN x, GEN mg, GEN S, GEN T, GEN *pr)
    2460              : {
    2461         1186 :   GEN q = NULL, r = F2xqX_red(x, T);
    2462         1186 :   long l = lgpol(r), lt = degpol(S), lm = 2*lt-1, v = varn(S);
    2463              :   long i;
    2464         1186 :   if (l <= lt)
    2465              :   {
    2466            0 :     if (pr == ONLY_REM) return r;
    2467            0 :     if (pr == ONLY_DIVIDES) return signe(r)? NULL: pol_0(v);
    2468            0 :     if (pr) *pr = r;
    2469            0 :     return pol_0(v);
    2470              :   }
    2471         1186 :   if (lt <= 1)
    2472            0 :     return F2xqX_divrem_basecase(x,S,T,pr);
    2473         1186 :   if (pr != ONLY_REM && l>lm)
    2474              :   {
    2475            3 :     long vT = get_F2x_var(T);
    2476            3 :     q = cgetg(l-lt+2, t_POL); q[1] = S[1];
    2477          375 :     for (i=0;i<l-lt;i++) gel(q+2,i) = pol0_F2x(vT);
    2478              :   }
    2479         1189 :   while (l>lm)
    2480              :   {
    2481            3 :     GEN zr, zq = F2xqX_divrem_Barrettspec(r+2+l-lm,lm,mg,S,T,&zr);
    2482            3 :     long lz = lgpol(zr);
    2483            3 :     if (pr != ONLY_REM)
    2484              :     {
    2485            3 :       long lq = lgpol(zq);
    2486          231 :       for(i=0; i<lq; i++) gel(q+2+l-lm,i) = gel(zq,2+i);
    2487              :     }
    2488          234 :     for(i=0; i<lz; i++) gel(r+2+l-lm,i) = gel(zr,2+i);
    2489            3 :     l = l-lm+lz;
    2490              :   }
    2491         1186 :   if (pr == ONLY_REM)
    2492              :   {
    2493         1183 :     if (l > lt)
    2494         1183 :       r = F2xqX_divrem_Barrettspec(r+2,l,mg,S,T,ONLY_REM);
    2495              :     else
    2496            0 :       r = F2xX_renormalize(r, lg(r));
    2497         1183 :     setvarn(r, v); return F2xX_renormalize(r, lg(r));
    2498              :   }
    2499            3 :   if (l > lt)
    2500              :   {
    2501            3 :     GEN zq = F2xqX_divrem_Barrettspec(r+2,l,mg,S,T,pr? &r: NULL);
    2502            3 :     if (!q) q = zq;
    2503              :     else
    2504              :     {
    2505            3 :       long lq = lgpol(zq);
    2506          147 :       for(i=0; i<lq; i++) gel(q+2,i) = gel(zq,2+i);
    2507              :     }
    2508              :   }
    2509            0 :   else if (pr)
    2510            0 :     r = F2xX_renormalize(r, l+2);
    2511            3 :   setvarn(q, v); q = F2xX_renormalize(q, lg(q));
    2512            3 :   if (pr == ONLY_DIVIDES) return signe(r)? NULL: q;
    2513            3 :   if (pr) { setvarn(r, v); *pr = r; }
    2514            3 :   return q;
    2515              : }
    2516              : 
    2517              : GEN
    2518        33243 : F2xqX_divrem(GEN x, GEN S, GEN T, GEN *pr)
    2519              : {
    2520              :   GEN B, y;
    2521              :   long dy, dx, d;
    2522        33243 :   if (pr==ONLY_REM) return F2xqX_rem(x, S, T);
    2523        33243 :   y = get_F2xqX_red(S, &B);
    2524        33243 :   dy = degpol(y); dx = degpol(x); d = dx-dy;
    2525        33243 :   if (!B && d+3 < F2xqX_DIVREM_BARRETT_LIMIT)
    2526        33240 :     return F2xqX_divrem_basecase(x,y,T,pr);
    2527              :   else
    2528              :   {
    2529            3 :     pari_sp av=avma;
    2530            3 :     GEN mg = B? B: F2xqX_invBarrett(y, T);
    2531            3 :     GEN q = F2xqX_divrem_Barrett(x,mg,y,T,pr);
    2532            3 :     if (!q) return gc_NULL(av);
    2533            3 :     if (!pr || pr==ONLY_DIVIDES) return gc_GEN(av, q);
    2534            0 :     return gc_all(av,2,&q,pr);
    2535              :   }
    2536              : }
    2537              : 
    2538              : GEN
    2539       750990 : F2xqX_rem(GEN x, GEN S, GEN T)
    2540              : {
    2541       750990 :   GEN B, y = get_F2xqX_red(S, &B);
    2542       750990 :   long dy = degpol(y), dx = degpol(x), d = dx-dy;
    2543       750990 :   if (d < 0) return F2xqX_red(x, T);
    2544       513785 :   if (!B && d+3 < F2xqX_REM_BARRETT_LIMIT)
    2545       512602 :     return F2xqX_divrem_basecase(x,y, T, ONLY_REM);
    2546              :   else
    2547              :   {
    2548         1183 :     pari_sp av=avma;
    2549         1183 :     GEN mg = B? B: F2xqX_invBarrett(y, T);
    2550         1183 :     GEN r = F2xqX_divrem_Barrett(x, mg, y, T, ONLY_REM);
    2551         1183 :     return gc_upto(av, r);
    2552              :   }
    2553              : }
    2554              : 
    2555              : static GEN
    2556            0 : F2xqX_addmulmul(GEN u, GEN v, GEN x, GEN y, GEN T)
    2557              : {
    2558            0 :   return F2xX_add(F2xqX_mul(u, x, T),F2xqX_mul(v, y, T));
    2559              : }
    2560              : 
    2561              : INLINE GEN
    2562            0 : F2xXn_red(GEN a, long n) { return FlxXn_red(a, n); }
    2563              : 
    2564              : static GEN
    2565            0 : F2xqXM_F2xqX_mul2(GEN M, GEN x, GEN y, GEN T)
    2566              : {
    2567            0 :   GEN res = cgetg(3, t_COL);
    2568            0 :   gel(res, 1) = F2xqX_addmulmul(gcoeff(M,1,1), gcoeff(M,1,2), x, y, T);
    2569            0 :   gel(res, 2) = F2xqX_addmulmul(gcoeff(M,2,1), gcoeff(M,2,2), x, y, T);
    2570            0 :   return res;
    2571              : }
    2572              : 
    2573              : static GEN
    2574            0 : F2xqXM_mul2(GEN A, GEN B, GEN T)
    2575              : {
    2576            0 :   GEN A11=gcoeff(A,1,1),A12=gcoeff(A,1,2), B11=gcoeff(B,1,1),B12=gcoeff(B,1,2);
    2577            0 :   GEN A21=gcoeff(A,2,1),A22=gcoeff(A,2,2), B21=gcoeff(B,2,1),B22=gcoeff(B,2,2);
    2578            0 :   GEN M1 = F2xqX_mul(F2xX_add(A11,A22), F2xX_add(B11,B22), T);
    2579            0 :   GEN M2 = F2xqX_mul(F2xX_add(A21,A22), B11, T);
    2580            0 :   GEN M3 = F2xqX_mul(A11, F2xX_add(B12,B22), T);
    2581            0 :   GEN M4 = F2xqX_mul(A22, F2xX_add(B21,B11), T);
    2582            0 :   GEN M5 = F2xqX_mul(F2xX_add(A11,A12), B22, T);
    2583            0 :   GEN M6 = F2xqX_mul(F2xX_add(A21,A11), F2xX_add(B11,B12), T);
    2584            0 :   GEN M7 = F2xqX_mul(F2xX_add(A12,A22), F2xX_add(B21,B22), T);
    2585            0 :   GEN T1 = F2xX_add(M1,M4), T2 = F2xX_add(M7,M5);
    2586            0 :   GEN T3 = F2xX_add(M1,M2), T4 = F2xX_add(M3,M6);
    2587            0 :   retmkmat22(F2xX_add(T1,T2), F2xX_add(M3,M5),
    2588              :              F2xX_add(M2,M4), F2xX_add(T3,T4));
    2589              : }
    2590              : 
    2591              : /* Return [0,1;1,-q]*M */
    2592              : static GEN
    2593            0 : F2xqX_F2xqXM_qmul(GEN q, GEN M, GEN T)
    2594              : {
    2595            0 :   GEN u = F2xqX_mul(gcoeff(M,2,1), q, T);
    2596            0 :   GEN v = F2xqX_mul(gcoeff(M,2,2), q, T);
    2597            0 :   retmkmat22(gcoeff(M,2,1), gcoeff(M,2,2),
    2598              :     F2xX_add(gcoeff(M,1,1), u), F2xX_add(gcoeff(M,1,2), v));
    2599              : }
    2600              : 
    2601              : static GEN
    2602            0 : matid2_F2xXM(long v, long sv)
    2603            0 : { retmkmat22(pol1_F2xX(v, sv),pol_0(v),pol_0(v),pol1_F2xX(v, sv)); }
    2604              : 
    2605              : static GEN
    2606            0 : matJ2_F2xXM(long v, long sv)
    2607            0 : { retmkmat22(pol_0(v),pol1_F2xX(v, sv),pol1_F2xX(v, sv),pol_0(v)); }
    2608              : 
    2609              : struct F2xqX_res
    2610              : {
    2611              :    GEN res, lc;
    2612              :    long deg0, deg1;
    2613              : };
    2614              : 
    2615              : INLINE void
    2616            0 : F2xqX_halfres_update(long da, long db, long dr, GEN T, struct F2xqX_res *res)
    2617              : {
    2618            0 :   if (dr >= 0)
    2619              :   {
    2620            0 :     if (!F2x_equal1(res->lc))
    2621              :     {
    2622            0 :       res->lc  = F2xq_powu(res->lc, da - dr, T);
    2623            0 :       res->res = F2xq_mul(res->res, res->lc, T);
    2624              :     }
    2625              :   } else
    2626              :   {
    2627            0 :     if (db == 0)
    2628              :     {
    2629            0 :       if (!F2x_equal1(res->lc))
    2630              :       {
    2631            0 :           res->lc  = F2xq_powu(res->lc, da, T);
    2632            0 :           res->res = F2xq_mul(res->res, res->lc, T);
    2633              :       }
    2634              :     } else
    2635            0 :       res->res = pol0_F2x(get_F2x_var(T));
    2636              :   }
    2637            0 : }
    2638              : 
    2639              : static GEN
    2640            7 : F2xqX_halfres_basecase(GEN a, GEN b, GEN T, GEN *pa, GEN *pb, struct F2xqX_res *res)
    2641              : {
    2642            7 :   pari_sp av=avma;
    2643              :   GEN u,u1,v,v1, M;
    2644            7 :   long vx = varn(a), vT = get_F2x_var(T), n = lgpol(a)>>1;
    2645            7 :   u1 = v = pol_0(vx);
    2646            7 :   u = v1 = pol1_F2xX(vx, vT);
    2647            7 :   while (lgpol(b)>n)
    2648              :   {
    2649              :     GEN r, q;
    2650            0 :     q = F2xqX_divrem(a,b, T, &r);
    2651            0 :     if (res)
    2652              :     {
    2653            0 :       long da = degpol(a), db = degpol(b), dr = degpol(r);
    2654            0 :       res->lc = gel(b,db+2);
    2655            0 :       if (dr >= n)
    2656            0 :         F2xqX_halfres_update(da, db, dr, T, res);
    2657              :       else
    2658              :       {
    2659            0 :         res->deg0 = da;
    2660            0 :         res->deg1 = db;
    2661              :       }
    2662              :     }
    2663            0 :     a = b; b = r; swap(u,u1); swap(v,v1);
    2664            0 :     u1 = F2xX_add(u1, F2xqX_mul(u, q, T));
    2665            0 :     v1 = F2xX_add(v1, F2xqX_mul(v, q, T));
    2666            0 :     if (gc_needed(av,2))
    2667              :     {
    2668            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"F2xqX_halfgcd (d = %ld)",degpol(b));
    2669            0 :       if (res)
    2670            0 :         (void)gc_all(av, 8, &a,&b,&u1,&v1,&u,&v,&res->res,&res->lc);
    2671              :       else
    2672            0 :         (void)gc_all(av, 6, &a,&b,&u1,&v1,&u,&v);
    2673              :     }
    2674              :   }
    2675            7 :   M = mkmat22(u,v,u1,v1); *pa = a; *pb = b;
    2676            0 :   return res ? gc_all(av, 5, &M, pa, pb, &res->res, &res->lc)
    2677            7 :              : gc_all(av, 3, &M, pa, pb);
    2678              : }
    2679              : 
    2680              : static GEN F2xqX_halfres_i(GEN x, GEN y, GEN T, GEN *a, GEN *b, struct F2xqX_res *res);
    2681              : 
    2682              : static GEN
    2683            0 : F2xqX_halfres_split(GEN x, GEN y, GEN T, GEN *a, GEN *b, struct F2xqX_res *res)
    2684              : {
    2685            0 :   pari_sp av = avma;
    2686              :   GEN Q, R, S, V1, V2;
    2687              :   GEN x1, y1, r, q;
    2688            0 :   long l = lgpol(x), n = l>>1, k, vT = get_F2x_var(T);
    2689            0 :   if (lgpol(y) <= n)
    2690            0 :     { *a = RgX_copy(x); *b = RgX_copy(y); return matid2_F2xXM(varn(x),vT); }
    2691            0 :   if (res)
    2692              :   {
    2693            0 :      res->lc = leading_coeff(y);
    2694            0 :      res->deg0 -= n;
    2695            0 :      res->deg1 -= n;
    2696              :   }
    2697            0 :   R = F2xqX_halfres_i(F2xX_shift(x,-n, vT),F2xX_shift(y,-n, vT), T, a, b, res);
    2698            0 :   if (res)
    2699              :   {
    2700            0 :     res->deg0 += n;
    2701            0 :     res->deg1 += n;
    2702              :   }
    2703            0 :   V1 = F2xqXM_F2xqX_mul2(R, Flxn_red(x,n), Flxn_red(y,n), T);
    2704            0 :   x1 = F2xX_add(F2xX_shift(*a,n,vT), gel(V1,1));
    2705            0 :   y1 = F2xX_add(F2xX_shift(*b,n,vT), gel(V1,2));
    2706            0 :   if (lgpol(y1) <= n)
    2707              :   {
    2708            0 :     *a = x1; *b = y1;
    2709            0 :     return res ? gc_all(av, 5, &R, a, b, &res->res, &res->lc)
    2710            0 :                : gc_all(av, 3, &R, a, b, &res->res, &res->lc);
    2711              :   }
    2712            0 :   k = 2*n-degpol(y1);
    2713            0 :   q = F2xqX_divrem(x1, y1, T, &r);
    2714            0 :   if (res)
    2715              :   {
    2716            0 :     long dx1 = degpol(x1), dy1 = degpol(y1), dr = degpol(r);
    2717            0 :     if (dy1 < degpol(y))
    2718            0 :       F2xqX_halfres_update(res->deg0, res->deg1, dy1, T, res);
    2719            0 :     res->lc = leading_coeff(y1);
    2720            0 :     res->deg0 = dx1;
    2721            0 :     res->deg1 = dy1;
    2722            0 :     if (dr >= n)
    2723              :     {
    2724            0 :       F2xqX_halfres_update(dx1, dy1, dr, T, res);
    2725            0 :       res->deg0 = dy1;
    2726            0 :       res->deg1 = dr;
    2727              :     }
    2728            0 :     res->deg0 -= k;
    2729            0 :     res->deg1 -= k;
    2730              :   }
    2731            0 :   S = F2xqX_halfres_i(F2xX_shift(y1,-k, vT), F2xX_shift(r,-k, vT), T, a, b, res);
    2732            0 :   if (res)
    2733              :   {
    2734            0 :     res->deg0 += k;
    2735            0 :     res->deg1 += k;
    2736              :   }
    2737            0 :   Q = F2xqXM_mul2(S,F2xqX_F2xqXM_qmul(q, R, T), T);
    2738            0 :   V2 = F2xqXM_F2xqX_mul2(S, F2xXn_red(y1,k), F2xXn_red(r,k), T);
    2739            0 :   *a = F2xX_add(F2xX_shift(*a,k,vT), gel(V2,1));
    2740            0 :   *b = F2xX_add(F2xX_shift(*b,k,vT), gel(V2,2));
    2741            0 :   return res ? gc_all(av, 5, &Q, a, b, &res->res, &res->lc)
    2742            0 :              : gc_all(av, 3, &Q, a, b, &res->res, &res->lc);
    2743              : }
    2744              : 
    2745              : static GEN
    2746            7 : F2xqX_halfres_i(GEN x, GEN y, GEN T, GEN *a, GEN *b, struct F2xqX_res *res)
    2747              : {
    2748            7 :   if (lgpol(x) < F2xqX_HALFGCD_LIMIT)
    2749            7 :     return F2xqX_halfres_basecase(x, y, T, a, b, res);
    2750            0 :   return F2xqX_halfres_split(x, y, T, a, b, res);
    2751              : }
    2752              : 
    2753              : static GEN
    2754            7 : F2xqX_halfgcd_all_i(GEN x, GEN y, GEN T, GEN *pa, GEN *pb)
    2755              : {
    2756              :   GEN a, b;
    2757            7 :   GEN R = F2xqX_halfres_i(x, y, T, &a, &b, NULL);
    2758            7 :   if (pa) *pa = a;
    2759            7 :   if (pb) *pb = b;
    2760            7 :   return R;
    2761              : }
    2762              : 
    2763              : /* Return M in GL_2(F_2[X]/(T)[Y]) such that:
    2764              : if [a',b']~=M*[a,b]~ then degpol(a')>= (lgpol(a)>>1) >degpol(b')
    2765              : */
    2766              : 
    2767              : GEN
    2768            7 : F2xqX_halfgcd_all(GEN x, GEN y, GEN T, GEN *a, GEN *b)
    2769              : {
    2770            7 :   pari_sp av = avma;
    2771              :   GEN R,q,r;
    2772            7 :   if (!signe(x))
    2773              :   {
    2774            0 :     if (a) *a = RgX_copy(y);
    2775            0 :     if (b) *b = RgX_copy(x);
    2776            0 :     return matJ2_F2xXM(varn(x), get_F2x_var(T));
    2777              :   }
    2778            7 :   if (degpol(y)<degpol(x)) return F2xqX_halfgcd_all_i(x, y, T, a, b);
    2779            7 :   q = F2xqX_divrem(y, x, T, &r);
    2780            7 :   R = F2xqX_halfgcd_all_i(x, r, T, a, b);
    2781            7 :   gcoeff(R,1,1) = F2xX_add(gcoeff(R,1,1), F2xqX_mul(q, gcoeff(R,1,2), T));
    2782            7 :   gcoeff(R,2,1) = F2xX_add(gcoeff(R,2,1), F2xqX_mul(q, gcoeff(R,2,2), T));
    2783            7 :   return !a && b ? gc_all(av, 2, &R, b): gc_all(av, 1+!!a+!!b, &R, a, b);
    2784              : }
    2785              : 
    2786              : GEN
    2787            0 : F2xqX_halfgcd(GEN x, GEN y, GEN T)
    2788            0 : { return F2xqX_halfgcd_all(x, y, T, NULL, NULL); }
    2789              : 
    2790              : static GEN
    2791       169613 : F2xqX_gcd_basecase(GEN a, GEN b, GEN T)
    2792              : {
    2793       169613 :   pari_sp av = avma, av0=avma;
    2794       698583 :   while (signe(b))
    2795              :   {
    2796              :     GEN c;
    2797       528970 :     if (gc_needed(av0,2))
    2798              :     {
    2799            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"F2xqX_gcd (d = %ld)",degpol(b));
    2800            0 :       (void)gc_all(av0,2, &a,&b);
    2801              :     }
    2802       528970 :     av = avma; c = F2xqX_rem(a, b, T); a=b; b=c;
    2803              :   }
    2804       169613 :   return gc_const(av, a);
    2805              : }
    2806              : 
    2807              : GEN
    2808       170012 : F2xqX_gcd(GEN x, GEN y, GEN T)
    2809              : {
    2810       170012 :   pari_sp av = avma;
    2811       170012 :   x = F2xqX_red(x, T);
    2812       170012 :   y = F2xqX_red(y, T);
    2813       170012 :   if (!signe(x)) return gc_upto(av, y);
    2814       169613 :   while (lgpol(y)>=F2xqX_GCD_LIMIT)
    2815              :   {
    2816            0 :     if (lgpol(y)<=(lgpol(x)>>1))
    2817              :     {
    2818            0 :       GEN r = F2xqX_rem(x, y, T);
    2819            0 :       x = y; y = r;
    2820              :     }
    2821            0 :     (void) F2xqX_halfgcd_all(x, y, T, &x, &y);
    2822            0 :     if (gc_needed(av,2))
    2823              :     {
    2824            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"F2xqX_gcd (y = %ld)",degpol(y));
    2825            0 :       (void)gc_all(av,2,&x,&y);
    2826              :     }
    2827              :   }
    2828       169613 :   return gc_upto(av, F2xqX_gcd_basecase(x, y, T));
    2829              : }
    2830              : 
    2831              : static GEN
    2832           14 : F2xqX_extgcd_basecase(GEN a, GEN b, GEN T,  GEN *ptu, GEN *ptv)
    2833              : {
    2834           14 :   pari_sp av=avma;
    2835              :   GEN u,v,d,d1,v1;
    2836           14 :   long vx = varn(a);
    2837           14 :   d = a; d1 = b;
    2838           14 :   v = pol_0(vx); v1 = pol1_F2xX(vx, get_F2x_var(T));
    2839           63 :   while (signe(d1))
    2840              :   {
    2841           49 :     GEN r, q = F2xqX_divrem(d, d1, T, &r);
    2842           49 :     v = F2xX_add(v,F2xqX_mul(q,v1,T));
    2843           49 :     u=v; v=v1; v1=u;
    2844           49 :     u=r; d=d1; d1=u;
    2845           49 :     if (gc_needed(av,2))
    2846              :     {
    2847            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"F2xqX_extgcd (d = %ld)",degpol(d));
    2848            0 :       (void)gc_all(av,5, &d,&d1,&u,&v,&v1);
    2849              :     }
    2850              :   }
    2851           14 :   if (ptu) *ptu = F2xqX_div(F2xX_add(d,F2xqX_mul(b,v, T)), a, T);
    2852           14 :   *ptv = v; return d;
    2853              : }
    2854              : 
    2855              : static GEN
    2856            0 : F2xqX_extgcd_halfgcd(GEN x, GEN y, GEN T,  GEN *ptu, GEN *ptv)
    2857              : {
    2858              :   GEN u,v;
    2859            0 :   GEN V = cgetg(expu(lgpol(y))+2,t_VEC);
    2860            0 :   long i, n = 0, vs = varn(x), vT = get_F2x_var(T);
    2861            0 :   while (lgpol(y)>=F2xqX_EXTGCD_LIMIT)
    2862              :   {
    2863            0 :     if (lgpol(y)<=(lgpol(x)>>1))
    2864              :     {
    2865            0 :       GEN r, q = F2xqX_divrem(x, y, T, &r);
    2866            0 :       x = y; y = r;
    2867            0 :       gel(V,++n) = mkmat22(pol_0(vs),pol1_F2xX(vs,vT),pol1_F2xX(vs,vT),RgX_copy(q));
    2868              :     } else
    2869            0 :       gel(V,++n) = F2xqX_halfgcd_all(x, y, T, &x, &y);
    2870              :   }
    2871            0 :   y = F2xqX_extgcd_basecase(x,y, T, &u,&v);
    2872            0 :   for (i = n; i>1; i--)
    2873              :   {
    2874            0 :     GEN R = gel(V,i);
    2875            0 :     GEN u1 = F2xqX_addmulmul(u, v, gcoeff(R,1,1), gcoeff(R,2,1), T);
    2876            0 :     GEN v1 = F2xqX_addmulmul(u, v, gcoeff(R,1,2), gcoeff(R,2,2), T);
    2877            0 :     u = u1; v = v1;
    2878              :   }
    2879              :   {
    2880            0 :     GEN R = gel(V,1);
    2881            0 :     if (ptu)
    2882            0 :       *ptu = F2xqX_addmulmul(u, v, gcoeff(R,1,1), gcoeff(R,2,1), T);
    2883            0 :     *ptv   = F2xqX_addmulmul(u, v, gcoeff(R,1,2), gcoeff(R,2,2), T);
    2884              :   }
    2885            0 :   return y;
    2886              : }
    2887              : 
    2888              : /* x and y in Z[Y][X], return lift(gcd(x mod T,p, y mod T,p)). Set u and v st
    2889              :  * ux + vy = gcd (mod T,p) */
    2890              : GEN
    2891           14 : F2xqX_extgcd(GEN x, GEN y, GEN T,  GEN *ptu, GEN *ptv)
    2892              : {
    2893           14 :   pari_sp av = avma;
    2894              :   GEN d;
    2895           14 :   x = F2xqX_red(x, T);
    2896           14 :   y = F2xqX_red(y, T);
    2897           14 :   if (lgpol(y)>=F2xqX_EXTGCD_LIMIT)
    2898            0 :     d = F2xqX_extgcd_halfgcd(x, y, T, ptu, ptv);
    2899              :   else
    2900           14 :     d = F2xqX_extgcd_basecase(x, y, T, ptu, ptv);
    2901           14 :   return gc_all(av, ptu?3:2, &d, ptv, ptu);
    2902              : }
    2903              : 
    2904              : static GEN
    2905            0 : F2xqX_halfres(GEN x, GEN y, GEN T, GEN *a, GEN *b, GEN *r)
    2906              : {
    2907              :   struct F2xqX_res res;
    2908              :   GEN V;
    2909              :   long dB;
    2910              : 
    2911            0 :   res.res  = *r;
    2912            0 :   res.lc   = leading_coeff(y);
    2913            0 :   res.deg0 = degpol(x);
    2914            0 :   res.deg1 = degpol(y);
    2915            0 :   V = F2xqX_halfres_i(x, y, T, a, b, &res);
    2916            0 :   dB = degpol(*b);
    2917            0 :   if (dB < degpol(y))
    2918            0 :     F2xqX_halfres_update(res.deg0, res.deg1, dB, T, &res);
    2919            0 :   *r = res.res;
    2920            0 :   return V;
    2921              : }
    2922              : 
    2923              : /* Res(A,B) = Res(B,R) * lc(B)^(a-r) * (-1)^(ab), with R=A%B, a=deg(A) ...*/
    2924              : static GEN
    2925           21 : F2xqX_resultant_basecase(GEN a, GEN b, GEN T)
    2926              : {
    2927           21 :   pari_sp av = avma;
    2928           21 :   long vT = get_F2x_var(T), da,db,dc;
    2929           21 :   GEN c,lb, res = pol1_F2x(vT);
    2930              : 
    2931           21 :   if (!signe(a) || !signe(b)) return pol0_F2x(vT);
    2932              : 
    2933           21 :   da = degpol(a);
    2934           21 :   db = degpol(b);
    2935           21 :   if (db > da)
    2936            0 :     swapspec(a,b, da,db);
    2937           21 :   if (!da) return pol1_F2x(vT); /* = res * a[2] ^ db, since 0 <= db <= da = 0 */
    2938           49 :   while (db)
    2939              :   {
    2940           28 :     lb = gel(b,db+2);
    2941           28 :     c = F2xqX_rem(a,b, T);
    2942           28 :     a = b; b = c; dc = degpol(c);
    2943           28 :     if (dc < 0) { set_avma(av); return pol0_F2x(vT); }
    2944              : 
    2945           28 :     if (!equali1(lb)) res = F2xq_mul(res, F2xq_powu(lb, da - dc, T), T);
    2946           28 :     if (gc_needed(av,2))
    2947              :     {
    2948            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"F2xqX_resultant (da = %ld)",da);
    2949            0 :       (void)gc_all(av,3, &a,&b,&res);
    2950              :     }
    2951           28 :     da = db; /* = degpol(a) */
    2952           28 :     db = dc; /* = degpol(b) */
    2953              :   }
    2954           21 :   res = F2xq_mul(res, F2xq_powu(gel(b,2), da, T), T);
    2955           21 :   return gc_upto(av, res);
    2956              : }
    2957              : 
    2958              : /* Res(A,B) = Res(B,R) * lc(B)^(a-r) * (-1)^(ab), with R=A%B, a=deg(A) ...*/
    2959              : GEN
    2960           21 : F2xqX_resultant(GEN x, GEN y, GEN T)
    2961              : {
    2962           21 :   pari_sp av = avma;
    2963           21 :   long dx, dy, vT = get_F2x_var(T);
    2964           21 :   GEN res = pol1_F2x(vT);
    2965           21 :   if (!signe(x) || !signe(y)) return pol0_F2x(vT);
    2966           21 :   dx = degpol(x); dy = degpol(y);
    2967           21 :   if (dx < dy)
    2968            7 :     swap(x,y);
    2969           21 :   while (lgpol(y) >= F2xqX_GCD_LIMIT)
    2970              :   {
    2971            0 :     if (lgpol(y)<=(lgpol(x)>>1))
    2972              :     {
    2973            0 :       GEN r = F2xqX_rem(x, y, T);
    2974            0 :       long dx = degpol(x), dy = degpol(y), dr = degpol(r);
    2975            0 :       GEN ly = gel(y,dy+2);
    2976            0 :       if (!F2x_equal1(ly))
    2977            0 :         res = F2xq_mul(res, F2xq_powu(ly, dx - dr, T), T);
    2978            0 :       x = y; y = r;
    2979              :     }
    2980            0 :     (void) F2xqX_halfres(x, y, T, &x, &y, &res);
    2981            0 :     if (gc_needed(av,2))
    2982              :     {
    2983            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"F2xqX_resultant (y = %ld)",degpol(y));
    2984            0 :       (void)gc_all(av,3,&x,&y,&res);
    2985              :     }
    2986              :   }
    2987           21 :   res = F2xq_mul(res, F2xqX_resultant_basecase(x, y, T), T);
    2988           21 :   return gc_upto(av, res);
    2989              : }
    2990              : 
    2991              : /* disc P = (-1)^(n(n-1)/2) lc(P)^(n - deg P' - 2) Res(P,P'), n = deg P */
    2992              : GEN
    2993           14 : F2xqX_disc(GEN P, GEN T)
    2994              : {
    2995           14 :   pari_sp av = avma;
    2996           14 :   GEN L, dP = F2xX_deriv(P), D = F2xqX_resultant(P, dP, T);
    2997              :   long dd;
    2998           14 :   if (!lgpol(D)) return pol_0(get_F2x_var(T));
    2999           14 :   dd = degpol(P) - 2 - degpol(dP); /* >= -1; > -1 iff p | deg(P) */
    3000           14 :   L = leading_coeff(P);
    3001           14 :   if (dd && !F2x_equal1(L))
    3002            0 :     D = (dd == -1)? F2xq_div(D,L,T): F2xq_mul(D, F2xq_powu(L, dd, T), T);
    3003           14 :   return gc_upto(av, D);
    3004              : }
    3005              : 
    3006              : /***********************************************************************/
    3007              : /**                                                                   **/
    3008              : /**                             F2xqXQ                                **/
    3009              : /**                                                                   **/
    3010              : /***********************************************************************/
    3011              : 
    3012              : GEN
    3013       114537 : F2xqXQ_mul(GEN x, GEN y, GEN S, GEN T) {
    3014       114537 :   return F2xqX_rem(F2xqX_mul(x,y,T),S,T);
    3015              : }
    3016              : 
    3017              : GEN
    3018       104417 : F2xqXQ_sqr(GEN x, GEN S, GEN T) {
    3019       104417 :   return F2xqX_rem(F2xqX_sqr(x,T),S,T);
    3020              : }
    3021              : 
    3022              : GEN
    3023            7 : F2xqXQ_invsafe(GEN x, GEN S, GEN T)
    3024              : {
    3025            7 :   GEN V, z = F2xqX_extgcd(get_F2xqX_mod(S), x, T, NULL, &V);
    3026            7 :   if (degpol(z)) return NULL;
    3027            7 :   z = F2xq_invsafe(gel(z,2),T);
    3028            7 :   if (!z) return NULL;
    3029            7 :   return F2xqX_F2xq_mul(V, z, T);
    3030              : }
    3031              : 
    3032              : GEN
    3033            7 : F2xqXQ_inv(GEN x, GEN S, GEN T)
    3034              : {
    3035            7 :   pari_sp av = avma;
    3036            7 :   GEN U = F2xqXQ_invsafe(x, S, T);
    3037            7 :   if (!U) pari_err_INV("F2xqXQ_inv",x);
    3038            7 :   return gc_upto(av, U);
    3039              : }
    3040              : 
    3041              : struct _F2xqXQ {
    3042              :   GEN T, S;
    3043              : };
    3044              : 
    3045              : static GEN
    3046       345579 : _F2xqXQ_add(void *data, GEN x, GEN y) {
    3047              :   (void) data;
    3048       345579 :   return F2xX_add(x,y);
    3049              : }
    3050              : static GEN
    3051       482261 : _F2xqXQ_cmul(void *data, GEN P, long a, GEN x) {
    3052              :   (void) data;
    3053       482261 :   return F2xX_F2x_mul(x,gel(P,a+2));
    3054              : }
    3055              : static GEN
    3056       352064 : _F2xqXQ_red(void *data, GEN x) {
    3057       352064 :   struct _F2xqXQ *d = (struct _F2xqXQ*) data;
    3058       352064 :   return F2xqX_red(x, d->T);
    3059              : }
    3060              : static GEN
    3061       114481 : _F2xqXQ_mul(void *data, GEN x, GEN y) {
    3062       114481 :   struct _F2xqXQ *d = (struct _F2xqXQ*) data;
    3063       114481 :   return F2xqXQ_mul(x,y, d->S,d->T);
    3064              : }
    3065              : static GEN
    3066        33264 : _F2xqXQ_sqr(void *data, GEN x) {
    3067        33264 :   struct _F2xqXQ *d = (struct _F2xqXQ*) data;
    3068        33264 :   return F2xqXQ_sqr(x, d->S,d->T);
    3069              : }
    3070              : static GEN
    3071            7 : _F2xqXQ_zero(void *data) {
    3072            7 :   struct _F2xqXQ *d = (struct _F2xqXQ*) data;
    3073            7 :   return pol_0(get_F2xqX_var(d->S));
    3074              : }
    3075              : static GEN
    3076       375504 : _F2xqXQ_one(void *data) {
    3077       375504 :   struct _F2xqXQ *d = (struct _F2xqXQ*) data;
    3078       375504 :   return pol1_F2xX(get_F2xqX_var(d->S),get_F2x_var(d->T));
    3079              : }
    3080              : 
    3081              : static struct bb_algebra F2xqXQ_algebra = { _F2xqXQ_red,
    3082              :  _F2xqXQ_add, _F2xqXQ_add, _F2xqXQ_mul,_F2xqXQ_sqr,_F2xqXQ_one,_F2xqXQ_zero };
    3083              : 
    3084              : GEN
    3085            7 : F2xqXQ_pow(GEN x, GEN n, GEN S, GEN T)
    3086              : {
    3087              :   struct _F2xqXQ D;
    3088            7 :   long s = signe(n);
    3089            7 :   if (!s) return pol1_F2xX(get_F2xqX_var(S), get_F2x_var(T));
    3090            7 :   if (s < 0) x = F2xqXQ_inv(x,S,T);
    3091            7 :   if (is_pm1(n)) return s < 0 ? x : gcopy(x);
    3092            7 :   if (degpol(x) >= get_F2xqX_degree(S)) x = F2xqX_rem(x,S,T);
    3093            7 :   D.T = F2x_get_red(T);
    3094            7 :   D.S = F2xqX_get_red(S, T);
    3095            7 :   return gen_pow(x, n, (void*)&D, &_F2xqXQ_sqr, &_F2xqXQ_mul);
    3096              : }
    3097              : 
    3098              : GEN
    3099         7728 : F2xqXQ_powers(GEN x, long l, GEN S, GEN T)
    3100              : {
    3101              :   struct _F2xqXQ D;
    3102         7728 :   int use_sqr = 2*degpol(x) >= get_F2xqX_degree(S);
    3103         7728 :   D.T = F2x_get_red(T);
    3104         7728 :   D.S = F2xqX_get_red(S, T);
    3105         7728 :   return gen_powers(x, l, use_sqr, (void*)&D, &_F2xqXQ_sqr, &_F2xqXQ_mul,&_F2xqXQ_one);
    3106              : }
    3107              : 
    3108              : GEN
    3109        14441 : F2xqX_F2xqXQV_eval(GEN P, GEN V, GEN S, GEN T)
    3110              : {
    3111              :   struct _F2xqXQ D;
    3112        14441 :   D.T = F2x_get_red(T);
    3113        14441 :   D.S = F2xqX_get_red(S, T);
    3114        14441 :   return gen_bkeval_powers(P, degpol(P), V, (void*)&D, &F2xqXQ_algebra,
    3115              :                                                    _F2xqXQ_cmul);
    3116              : }
    3117              : 
    3118              : GEN
    3119       122248 : F2xqX_F2xqXQ_eval(GEN Q, GEN x, GEN S, GEN T)
    3120              : {
    3121              :   struct _F2xqXQ D;
    3122       122248 :   int use_sqr = 2*degpol(x) >= get_F2xqX_degree(S);
    3123       122248 :   D.T = F2x_get_red(T);
    3124       122248 :   D.S = F2xqX_get_red(S, T);
    3125       122248 :   return gen_bkeval(Q, degpol(Q), x, use_sqr, (void*)&D, &F2xqXQ_algebra,
    3126              :                                                     _F2xqXQ_cmul);
    3127              : }
    3128              : 
    3129              : static GEN
    3130        88832 : F2xqXQ_autpow_sqr(void * E, GEN x)
    3131              : {
    3132        88832 :   struct _F2xqXQ *D = (struct _F2xqXQ *)E;
    3133        88832 :   GEN T = D->T;
    3134        88832 :   GEN phi = gel(x,1), S = gel(x,2);
    3135        88832 :   long n = brent_kung_optpow(get_F2x_degree(T)-1,lgpol(S)+1,1);
    3136        88832 :   GEN V = F2xq_powers(phi, n, T);
    3137        88832 :   GEN phi2 = F2x_F2xqV_eval(phi, V, T);
    3138        88832 :   GEN Sphi = F2xY_F2xqV_evalx(S, V, T);
    3139        88832 :   GEN S2 = F2xqX_F2xqXQ_eval(Sphi, S, D->S, T);
    3140        88832 :   return mkvec2(phi2, S2);
    3141              : }
    3142              : 
    3143              : static GEN
    3144        33416 : F2xqXQ_autpow_mul(void * E, GEN x, GEN y)
    3145              : {
    3146        33416 :   struct _F2xqXQ *D = (struct _F2xqXQ *)E;
    3147        33416 :   GEN T = D->T;
    3148        33416 :   GEN phi1 = gel(x,1), S1 = gel(x,2);
    3149        33416 :   GEN phi2 = gel(y,1), S2 = gel(y,2);
    3150        33416 :   long n = brent_kung_optpow(get_F2x_degree(T)-1,lgpol(S1)+1,1);
    3151        33416 :   GEN V = F2xq_powers(phi2, n, T);
    3152        33416 :   GEN phi3 = F2x_F2xqV_eval(phi1,V,T);
    3153        33416 :   GEN Sphi = F2xY_F2xqV_evalx(S1,V,T);
    3154        33416 :   GEN S3 = F2xqX_F2xqXQ_eval(Sphi, S2, D->S, T);
    3155        33416 :   return mkvec2(phi3, S3);
    3156              : }
    3157              : 
    3158              : GEN
    3159        70558 : F2xqXQ_autpow(GEN aut, long n, GEN S, GEN T)
    3160              : {
    3161              :   struct _F2xqXQ D;
    3162        70558 :   D.T = F2x_get_red(T);
    3163        70558 :   D.S = F2xqX_get_red(S, T);
    3164        70558 :   return gen_powu(aut,n,&D,F2xqXQ_autpow_sqr,F2xqXQ_autpow_mul);
    3165              : }
    3166              : 
    3167              : static GEN
    3168         7196 : F2xqXQ_auttrace_mul(void *E, GEN x, GEN y)
    3169              : {
    3170         7196 :   struct _F2xqXQ *D = (struct _F2xqXQ *) E;
    3171         7196 :   GEN T = D->T;
    3172         7196 :   GEN phi1 = gel(x,1), S1 = gel(x,2), a1 = gel(x,3);
    3173         7196 :   GEN phi2 = gel(y,1), S2 = gel(y,2), a2 = gel(y,3);
    3174         7196 :   long n2 = brent_kung_optpow(get_F2x_degree(T)-1, lgpol(S1)+lgpol(a1)+1, 1);
    3175         7196 :   GEN V2 = F2xq_powers(phi2, n2, T);
    3176         7196 :   GEN phi3 = F2x_F2xqV_eval(phi1, V2, T);
    3177         7196 :   GEN Sphi = F2xY_F2xqV_evalx(S1, V2, T);
    3178         7196 :   GEN aphi = F2xY_F2xqV_evalx(a1, V2, T);
    3179         7196 :   long n = brent_kung_optpow(maxss(degpol(Sphi),degpol(aphi)),2,1);
    3180         7196 :   GEN V = F2xqXQ_powers(S2, n, D->S, T);
    3181         7196 :   GEN S3 = F2xqX_F2xqXQV_eval(Sphi, V, D->S, T);
    3182         7196 :   GEN aS = F2xqX_F2xqXQV_eval(aphi, V, D->S, T);
    3183         7196 :   GEN a3 = F2xX_add(aS, a2);
    3184         7196 :   return mkvec3(phi3, S3, a3);
    3185              : }
    3186              : 
    3187              : static GEN
    3188         4907 : F2xqXQ_auttrace_sqr(void *E, GEN x) { return F2xqXQ_auttrace_mul(E, x, x); }
    3189              : GEN
    3190         2737 : F2xqXQ_auttrace(GEN aut, long n, GEN S, GEN T)
    3191              : {
    3192              :   struct _F2xqXQ D;
    3193         2737 :   D.T = F2x_get_red(T);
    3194         2737 :   D.S = F2xqX_get_red(S, T);
    3195         2737 :   return gen_powu(aut,n,&D,F2xqXQ_auttrace_sqr,F2xqXQ_auttrace_mul);
    3196              : }
    3197              : 
    3198              : GEN
    3199           63 : F2xqXQV_red(GEN x, GEN S, GEN T)
    3200          273 : { pari_APPLY_type(t_VEC, F2xqX_rem(gel(x,i), S, T)) }
        

Generated by: LCOV version 2.0-1