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 - FpV.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.18.1 lcov report (development 30556-bb9f5f8fc8) Lines: 737 989 74.5 %
Date: 2025-11-25 09:20:50 Functions: 110 139 79.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 2000  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_mat
      19             : 
      20             : /********************************************************************/
      21             : /**                                                                **/
      22             : /**                           REDUCTION                            **/
      23             : /**                                                                **/
      24             : /********************************************************************/
      25             : /* z in Z^n, return lift(Col(z) * Mod(1,p)) */
      26             : GEN
      27    30021202 : FpC_red(GEN x, GEN p)
      28   209968660 : { pari_APPLY_type(t_COL, modii(gel(x,i), p)) }
      29             : 
      30             : /* z in Z^n, return lift(Vec(z) * Mod(1,p)) */
      31             : GEN
      32         420 : FpV_red(GEN x, GEN p)
      33        2695 : { pari_APPLY_type(t_VEC, modii(gel(x,i), p)) }
      34             : 
      35             : GEN
      36     7004897 : FpC_center(GEN x, GEN p, GEN pov2)
      37    42865433 : { pari_APPLY_type(t_COL, Fp_center(gel(x,i), p, pov2)) }
      38             : 
      39             : GEN
      40      164710 : Flv_center(GEN x, ulong p, ulong ps2)
      41     2621724 : { pari_APPLY_ulong(Fl_center(uel(x,i),p,ps2)) }
      42             : 
      43             : /* z in Mat m,n(Z), return lift(z * Mod(1,p)) */
      44             : GEN
      45     5616736 : FpM_red(GEN x, GEN p)
      46    24448226 : { pari_APPLY_same(FpC_red(gel(x,i), p)) }
      47             : 
      48             : GEN
      49     2792834 : FpM_center(GEN x, GEN p, GEN pov2)
      50     8370014 : { pari_APPLY_same(FpC_center(gel(x,i), p,pov2)) }
      51             : 
      52             : /* HACK: assume p > 3, which ensures u = gen_[0-2] is never written to */
      53             : static void
      54         168 : Fp_center_inplace(GEN u, GEN p, GEN ps2)
      55             : {
      56         168 :   if (abscmpii(u, ps2) > 0)
      57             :   {
      58          28 :     pari_sp av = avma;
      59          28 :     affii(subii(u, p), u);
      60          28 :     set_avma(av);
      61             :   }
      62         168 : }
      63             : 
      64             : /* p > 3; assume entries in [0,p[ and ps2 = p>>1. */
      65             : static void
      66          42 : _FpC_center_inplace(GEN z, GEN p, GEN ps2)
      67             : {
      68          42 :   long i, l = lg(z);
      69         210 :   for (i = 1; i < l; i++) Fp_center_inplace(gel(z,i), p, ps2);
      70          42 : }
      71             : static void
      72           7 : _F3C_center_inplace(GEN z)
      73             : {
      74           7 :   long i, l = lg(z);
      75          35 :   for (i = 1; i < l; i++) /* z[i] = 0, 1 : no-op */
      76          28 :     if (equaliu(gel(z,i), 2)) gel(z,i) = gen_m1;
      77           7 : }
      78             : void
      79           0 : FpC_center_inplace(GEN z, GEN p, GEN ps2)
      80             : {
      81           0 :   switch (itou_or_0(p))
      82             :   {
      83           0 :     case 2: break;
      84           0 :     case 3:_F3C_center_inplace(z); break;
      85           0 :     default: _FpC_center_inplace(z, p, ps2);
      86             :   }
      87           0 : }
      88             : 
      89             : void
      90          42 : FpM_center_inplace(GEN z, GEN p, GEN pov2)
      91             : {
      92          42 :   long i, l = lg(z);
      93          42 :   switch (itou_or_0(p))
      94             :   {
      95          21 :     case 2: break;
      96           7 :     case 3:
      97          14 :       for (i = 1; i < l; i++) _F3C_center_inplace(gel(z,i));
      98           7 :       break;
      99          14 :     default:
     100          56 :       for (i = 1; i < l; i++) _FpC_center_inplace(gel(z,i), p, pov2);
     101             :   }
     102          42 : }
     103             : GEN
     104       11347 : Flm_center(GEN x, ulong p, ulong ps2)
     105      175875 : { pari_APPLY_same(Flv_center(gel(x,i), p,ps2)) }
     106             : 
     107             : GEN
     108         147 : random_FpV(long d, GEN p)
     109             : {
     110             :   long i;
     111         147 :   GEN y = cgetg(d+1,t_VEC);
     112       23183 :   for (i=1; i<=d; i++) gel(y,i) = randomi(p);
     113         147 :   return y;
     114             : }
     115             : 
     116             : GEN
     117         924 : random_FpC(long d, GEN p)
     118             : {
     119             :   long i;
     120         924 :   GEN y = cgetg(d+1,t_COL);
     121        6188 :   for (i=1; i<=d; i++) gel(y,i) = randomi(p);
     122         924 :   return y;
     123             : }
     124             : 
     125             : GEN
     126       41404 : random_Flv(long n, ulong p)
     127             : {
     128       41404 :   GEN y = cgetg(n+1, t_VECSMALL);
     129             :   long i;
     130      262074 :   for (i=1; i<=n; i++) uel(y,i) = random_Fl(p);
     131       41406 :   return y;
     132             : }
     133             : 
     134             : /********************************************************************/
     135             : /**                                                                **/
     136             : /**                           ADD, SUB                             **/
     137             : /**                                                                **/
     138             : /********************************************************************/
     139             : GEN
     140      283453 : FpC_add(GEN x, GEN y, GEN p)
     141     3450765 : { pari_APPLY_type(t_COL, Fp_add(gel(x,i), gel(y,i), p)) }
     142             : 
     143             : GEN
     144           0 : FpV_add(GEN x, GEN y, GEN p)
     145           0 : { pari_APPLY_type(t_VEC, Fp_add(gel(x,i), gel(y,i), p)) }
     146             : 
     147             : GEN
     148           0 : FpM_add(GEN x, GEN y, GEN p)
     149           0 : { pari_APPLY_same(FpC_add(gel(x,i), gel(y,i), p)) }
     150             : 
     151             : GEN
     152     1159163 : Flv_add(GEN x, GEN y, ulong p)
     153             : {
     154     1159163 :   if (p==2)
     155     2478925 :     pari_APPLY_ulong(x[i]^y[i])
     156             :   else
     157    13903675 :     pari_APPLY_ulong(Fl_add(x[i], y[i], p))
     158             : }
     159             : 
     160             : void
     161      509440 : Flv_add_inplace(GEN x, GEN y, ulong p)
     162             : {
     163      509440 :   long i, l = lg(x);
     164      509440 :   if (p==2)
     165     1569662 :     for (i = 1; i < l; i++) x[i] ^= y[i];
     166             :   else
     167      164878 :     for (i = 1; i < l; i++) x[i] = Fl_add(x[i], y[i], p);
     168      509440 : }
     169             : 
     170             : ulong
     171        3871 : Flv_sum(GEN x, ulong p)
     172             : {
     173        3871 :   long i, l = lg(x);
     174        3871 :   ulong s = 0;
     175        3871 :   if (p==2)
     176       17689 :     for (i = 1; i < l; i++) s ^= x[i];
     177             :   else
     178           0 :     for (i = 1; i < l; i++) s = Fl_add(s, x[i], p);
     179        3871 :   return s;
     180             : }
     181             : 
     182             : GEN
     183      827139 : FpC_sub(GEN x, GEN y, GEN p)
     184    11174101 : { pari_APPLY_type(t_COL, Fp_sub(gel(x,i), gel(y,i), p)) }
     185             : 
     186             : GEN
     187           0 : FpV_sub(GEN x, GEN y, GEN p)
     188           0 : { pari_APPLY_type(t_VEC, Fp_sub(gel(x,i), gel(y,i), p)) }
     189             : 
     190             : GEN
     191           0 : FpM_sub(GEN x, GEN y, GEN p)
     192           0 : { pari_APPLY_same(FpC_sub(gel(x,i), gel(y,i), p)) }
     193             : 
     194             : GEN
     195   220682232 : Flv_sub(GEN x, GEN y, ulong p)
     196   990181113 : { pari_APPLY_ulong(Fl_sub(uel(x,i), uel(y,i), p)) }
     197             : 
     198             : void
     199           0 : Flv_sub_inplace(GEN x, GEN y, ulong p)
     200             : {
     201           0 :   long i, l = lg(x);
     202           0 :   for (i = 1; i < l; i++) x[i] = Fl_sub(x[i], y[i], p);
     203           0 : }
     204             : 
     205             : GEN
     206       51293 : Flm_Fl_add(GEN x, ulong y, ulong p)
     207             : {
     208       51293 :   long l = lg(x), i, j;
     209       51293 :   GEN z = cgetg(l,t_MAT);
     210             : 
     211       51293 :   if (l==1) return z;
     212       51293 :   if (l != lgcols(x)) pari_err_OP( "+", x, utoi(y));
     213      241346 :   for (i=1; i<l; i++)
     214             :   {
     215      190054 :     GEN zi = cgetg(l,t_VECSMALL), xi = gel(x,i);
     216      190053 :     gel(z,i) = zi;
     217     1329706 :     for (j=1; j<l; j++) zi[j] = xi[j];
     218      190053 :     zi[i] = Fl_add(zi[i], y, p);
     219             :   }
     220       51292 :   return z;
     221             : }
     222             : GEN
     223        3619 : Flm_Fl_sub(GEN x, ulong y, ulong p) { return Flm_Fl_add(x, Fl_neg(y,p), p); }
     224             : 
     225             : GEN
     226       23751 : Flm_add(GEN x, GEN y, ulong p)
     227      363189 : { pari_APPLY_same(Flv_add(gel(x,i), gel(y,i), p)) }
     228             : 
     229             : GEN
     230    25574441 : Flm_sub(GEN x, GEN y, ulong p)
     231   246236885 : { pari_APPLY_same(Flv_sub(gel(x,i), gel(y,i), p)) }
     232             : 
     233             : /********************************************************************/
     234             : /**                                                                **/
     235             : /**                           MULTIPLICATION                       **/
     236             : /**                                                                **/
     237             : /********************************************************************/
     238             : GEN
     239      964652 : FpC_Fp_mul(GEN x, GEN y, GEN p)
     240    11607618 : { pari_APPLY_type(t_COL, Fp_mul(gel(x,i), y, p)) }
     241             : 
     242             : GEN
     243     1227048 : Flv_Fl_mul(GEN x, ulong y, ulong p)
     244    16903726 : { pari_APPLY_ulong(Fl_mul(x[i], y, p)) }
     245             : 
     246             : GEN
     247        4706 : Flv_Fl_div(GEN x, ulong y, ulong p)
     248             : {
     249        4706 :   return Flv_Fl_mul(x, Fl_inv(y, p), p);
     250             : }
     251             : void
     252           0 : Flv_Fl_div_inplace(GEN x, ulong y, ulong p)
     253             : {
     254           0 :   Flv_Fl_mul_inplace(x, Fl_inv(y, p), p);
     255           0 : }
     256             : GEN
     257      763925 : FpM_Fp_mul(GEN X, GEN c, GEN p) {
     258      763925 :   long i, j, h, l = lg(X);
     259      763925 :   GEN A = cgetg(l, t_MAT);
     260      763925 :   if (l == 1) return A;
     261      763925 :   h = lgcols(X);
     262     4046149 :   for (j=1; j<l; j++)
     263             :   {
     264     3282350 :     GEN a = cgetg(h, t_COL), x = gel(X, j);
     265    23552338 :     for (i = 1; i < h; i++) gel(a,i) = Fp_mul(gel(x,i), c, p);
     266     3282224 :     gel(A,j) = a;
     267             :   }
     268      763799 :   return A;
     269             : }
     270             : 
     271             : /* x *= y */
     272             : void
     273     7881363 : Flv_Fl_mul_part_inplace(GEN x, ulong y, ulong p, long l)
     274             : {
     275             :   long i;
     276     7881363 :   if (HIGHWORD(y | p))
     277     8587572 :     for(i=1; i<=l; i++) x[i] = Fl_mul(x[i], y, p);
     278             :   else
     279    32186270 :     for(i=1; i<=l; i++) x[i] = (x[i] * y) % p;
     280     7881360 : }
     281             : void
     282           0 : Flv_Fl_mul_inplace(GEN x, ulong y, ulong p)
     283           0 : { Flv_Fl_mul_part_inplace(x, y, p, lg(x)-1); }
     284             : 
     285             : /* set y *= x */
     286             : void
     287           0 : Flm_Fl_mul_inplace(GEN y, ulong x, ulong p)
     288             : {
     289           0 :   long i, j, m, l = lg(y);
     290           0 :   if (l == 1) return;
     291           0 :   m = lgcols(y);
     292           0 :   if (HIGHWORD(x | p))
     293           0 :     for(j=1; j<l; j++)
     294           0 :       for(i=1; i<m; i++) ucoeff(y,i,j) = Fl_mul(ucoeff(y,i,j), x, p);
     295             :   else
     296           0 :     for(j=1; j<l; j++)
     297           0 :       for(i=1; i<m; i++) ucoeff(y,i,j) = (ucoeff(y,i,j) * x) % p;
     298             : }
     299             : 
     300             : /* return x * y */
     301             : static GEN
     302    17171790 : Flm_Fl_mul_pre_i(GEN y, ulong x, ulong p, ulong pi)
     303             : {
     304    17171790 :   long i, j, m, l = lg(y);
     305    17171790 :   GEN z = cgetg(l, t_MAT);
     306    17170308 :   if (l == 1) return z;
     307    17170308 :   m = lgcols(y);
     308   156097493 :   for(j=1; j<l; j++) {
     309   138841321 :     GEN c = cgetg(m, t_VECSMALL); gel(z,j) = c;
     310   372116223 :     for(i=1; i<m; i++) uel(c,i) = Fl_mul_pre(ucoeff(y,i,j), x, p, pi);
     311             :   }
     312    17256172 :   return z;
     313             : }
     314             : 
     315             : /* return x * y */
     316             : static GEN
     317     8456091 : Flm_Fl_mul_OK(GEN y, ulong x, ulong p)
     318             : {
     319     8456091 :   long i, j, m, l = lg(y);
     320     8456091 :   GEN z = cgetg(l, t_MAT);
     321     8456083 :   if (l == 1) return z;
     322     8456083 :   m = lgcols(y);
     323    48001491 :   for(j=1; j<l; j++) {
     324    39545412 :     GEN c = cgetg(m, t_VECSMALL); gel(z,j) = c;
     325   127424422 :     for(i=1; i<m; i++) uel(c,i) = (ucoeff(y,i,j) * x) % p;
     326             :   }
     327     8456079 :   return z;
     328             : }
     329             : 
     330             : /* return x * y */
     331             : GEN
     332    25556795 : Flm_Fl_mul_pre(GEN y, ulong x, ulong p, ulong pi)
     333             : {
     334    25556795 :   if (HIGHWORD(p))
     335    17171665 :     return Flm_Fl_mul_pre_i(y, x, p, pi);
     336             :   else
     337     8385130 :     return Flm_Fl_mul_OK(y, x, p);
     338             : }
     339             : 
     340             : /* return x * y */
     341             : GEN
     342       71006 : Flm_Fl_mul(GEN y, ulong x, ulong p)
     343             : {
     344       71006 :   if (HIGHWORD(p))
     345          74 :     return Flm_Fl_mul_pre_i(y, x, p, get_Fl_red(p));
     346             :   else
     347       70932 :     return Flm_Fl_mul_OK(y, x, p);
     348             : }
     349             : 
     350             : GEN
     351     4069689 : Flv_neg(GEN x, ulong p)
     352    31168713 : { pari_APPLY_ulong(Fl_neg(uel(x,i), p)) }
     353             : 
     354             : void
     355        6579 : Flv_neg_inplace(GEN v, ulong p)
     356             : {
     357             :   long i;
     358      192965 :   for (i = 1; i < lg(v); ++i)
     359      186386 :     v[i] = Fl_neg(v[i], p);
     360        6579 : }
     361             : 
     362             : GEN
     363      322716 : Flm_neg(GEN x, ulong p)
     364     4361700 : { pari_APPLY_same(Flv_neg(gel(x,i), p)) }
     365             : 
     366             : /* x[i,]*y. Assume lx > 1 and 0 < i < lgcols(x) */
     367             : static GEN
     368    18557391 : FpMrow_FpC_mul_i(GEN x, GEN y, long lx, long i, GEN p)
     369             : {
     370    18557391 :   pari_sp av = avma;
     371    18557391 :   GEN c = mulii(gcoeff(x,i,1), gel(y,1));
     372             :   long k;
     373   223190837 :   for (k = 2; k < lx; k++)
     374             :   {
     375   204634610 :     GEN t = mulii(gcoeff(x,i,k), gel(y,k));
     376   204632388 :     if (signe(t)) c = addii(c, t);
     377             :   }
     378    18556227 :   return gc_INT(av, modii(c, p));
     379             : }
     380             : 
     381             : static long
     382    97688539 : zmrow_zc_mul(GEN x, GEN y, long lx, long i)
     383             : {
     384             :   long k;
     385    97688539 :   long c = coeff(x,i,1) * y[1];
     386  1498281551 :   for (k = 2; k < lx; k++)
     387  1400593012 :     c += coeff(x,i,k) * y[k];
     388    97688539 :   return c;
     389             : }
     390             : 
     391             : GEN
     392     6450537 : zm_zc_mul(GEN x, GEN y)
     393             : {
     394     6450537 :   long lx = lg(x), l, i;
     395             :   GEN z;
     396     6450537 :   if (lx == 1) return cgetg(1, t_VECSMALL);
     397     6450537 :   l = lg(gel(x,1));
     398     6450537 :   z = cgetg(l,t_VECSMALL);
     399   104139076 :   for (i=1; i<l; i++) z[i] = zmrow_zc_mul(x, y, lx, i);
     400     6450537 :   return z;
     401             : }
     402             : 
     403             : GEN
     404        2114 : zm_mul(GEN x, GEN y)
     405             : {
     406        2114 :   long i,j,lx=lg(x), ly=lg(y);
     407             :   GEN z;
     408        2114 :   if (ly==1) return cgetg(1,t_MAT);
     409        2114 :   z = cgetg(ly,t_MAT);
     410        2114 :   if (lx==1)
     411             :   {
     412           0 :     for (i=1; i<ly; i++) gel(z,i) = cgetg(1,t_VECSMALL);
     413           0 :     return z;
     414             :   }
     415       30849 :   for (j=1; j<ly; j++)
     416       28735 :     gel(z,j) = zm_zc_mul(x, gel(y,j));
     417        2114 :   return z;
     418             : }
     419             : 
     420             : static ulong
     421   650184270 : Flmrow_Flc_mul_SMALL(GEN x, GEN y, ulong p, long lx, long i)
     422             : {
     423   650184270 :   ulong c = ucoeff(x,i,1) * uel(y,1);
     424             :   long k;
     425  7895016357 :   for (k = 2; k < lx; k++) {
     426  7244832087 :     c += ucoeff(x,i,k) * uel(y,k);
     427  7244832087 :     if (c & HIGHBIT) c %= p;
     428             :   }
     429   650184270 :   return c % p;
     430             : }
     431             : 
     432             : static ulong
     433   537540927 : Flmrow_Flc_mul_i(GEN x, GEN y, ulong p, ulong pi, long lx, long i)
     434             : {
     435             :   ulong l0, l1, v1, h0, h1;
     436   537540927 :   long k = 1;
     437             :   LOCAL_OVERFLOW;
     438             :   LOCAL_HIREMAINDER;
     439   537540927 :   l1 = mulll(ucoeff(x,i,k), uel(y,k)); h1 = hiremainder; v1 = 0;
     440  8856935655 :   while (++k < lx) {
     441  8319394728 :     l0 = mulll(ucoeff(x,i,k), uel(y,k)); h0 = hiremainder;
     442  8319394728 :     l1 = addll(l0, l1); h1 = addllx(h0, h1); v1 += overflow;
     443             :   }
     444   537540927 :   if (v1 == 0) return remll_pre(h1, l1, p, pi);
     445    55258587 :   else return remlll_pre(v1, h1, l1, p, pi);
     446             : }
     447             : 
     448             : static GEN
     449      310747 : Flm_Flc_mul_i_2(GEN x, GEN y, long lx, long l)
     450             : {
     451             :   long i,j;
     452      310747 :   GEN z = NULL;
     453             : 
     454     2742128 :   for (j=1; j<lx; j++)
     455             :   {
     456     2431382 :     if (!y[j]) continue;
     457      720987 :     if (!z) z = Flv_copy(gel(x,j));
     458    14689886 :     else for (i = 1; i < l; i++) z[i] ^= coeff(x,i,j);
     459             :   }
     460      310746 :   if (!z) z = zero_zv(l-1);
     461      310747 :   return z;
     462             : }
     463             : 
     464             : static GEN
     465     1752784 : FpM_FpC_mul_i(GEN x, GEN y, long lx, long l, GEN p)
     466             : {
     467     1752784 :   GEN z = cgetg(l,t_COL);
     468             :   long i;
     469    16617491 :   for (i = 1; i < l; i++) gel(z,i) = FpMrow_FpC_mul_i(x, y, lx, i, p);
     470     1752691 :   return z;
     471             : }
     472             : 
     473             : static void
     474    76556618 : __Flm_Flc_mul_i_SMALL(GEN z, GEN x, GEN y, long lx, long l, ulong p)
     475             : {
     476             :   long i;
     477   726762670 :   for (i = 1; i < l; i++) z[i] = Flmrow_Flc_mul_SMALL(x, y, p, lx, i);
     478    76578474 : }
     479             : static GEN
     480    73336397 : Flm_Flc_mul_i_SMALL(GEN x, GEN y, long lx, long l, ulong p)
     481             : {
     482    73336397 :   GEN z = cgetg(l,t_VECSMALL);
     483    73335056 :   __Flm_Flc_mul_i_SMALL(z, x, y, lx, l, p);
     484    73337399 :   return z;
     485             : }
     486             : 
     487             : static void
     488    95925051 : __Flm_Flc_mul_i(GEN z, GEN x, GEN y, long lx, long l, ulong p, ulong pi)
     489             : {
     490             :   long i;
     491   635516980 :   for (i = 1; i < l; i++) z[i] = Flmrow_Flc_mul_i(x, y, p, pi, lx, i);
     492    96248131 : }
     493             : static GEN
     494    91561604 : Flm_Flc_mul_i(GEN x, GEN y, long lx, long l, ulong p, ulong pi)
     495             : {
     496    91561604 :   GEN z = cgetg(l,t_VECSMALL);
     497    91378369 :   __Flm_Flc_mul_i(z, x, y, lx, l, p, pi);
     498    91613589 :   return z;
     499             : }
     500             : 
     501             : GEN
     502     2004160 : FpM_mul(GEN x, GEN y, GEN p)
     503             : {
     504     2004160 :   long lx=lg(x), ly=lg(y);
     505             :   GEN z;
     506     2004160 :   pari_sp av = avma;
     507     2004160 :   if (ly==1) return cgetg(1,t_MAT);
     508     2004160 :   if (lx==1) return zeromat(0, ly-1);
     509     2004160 :   if (lgefint(p) == 3)
     510             :   {
     511     1832482 :     ulong pp = uel(p,2);
     512     1832482 :     if (pp == 2)
     513             :     {
     514      720751 :       x = ZM_to_F2m(x);
     515      720806 :       y = ZM_to_F2m(y);
     516      720813 :       z = F2m_to_ZM(F2m_mul(x,y));
     517             :     }
     518             :     else
     519             :     {
     520     1111731 :       x = ZM_to_Flm(x, pp);
     521     1111752 :       y = ZM_to_Flm(y, pp);
     522     1111748 :       z = Flm_to_ZM(Flm_mul(x,y, pp));
     523             :     }
     524             :   } else
     525      171678 :     z = FpM_red(ZM_mul(x, y), p);
     526     2004236 :   return gc_upto(av, z);
     527             : }
     528             : 
     529             : static GEN
     530    28225482 : Flm_mul_classical(GEN x, GEN y, long l, long lx, long ly, ulong p, ulong pi)
     531             : {
     532             :   long j;
     533    28225482 :   GEN z = cgetg(ly, t_MAT);
     534    28224332 :   if (SMALL_ULONG(p))
     535    93186188 :     for (j=1; j<ly; j++)
     536    72997571 :       gel(z,j) = Flm_Flc_mul_i_SMALL(x, gel(y,j), lx, l, p);
     537             :   else
     538    99394613 :     for (j=1; j<ly; j++)
     539    91356686 :       gel(z,j) = Flm_Flc_mul_i(x, gel(y,j), lx, l, p, pi);
     540    28226544 :   return z;
     541             : }
     542             : 
     543             : /* Return A[ma+1..ma+da, na+1..na+ea] - B[mb+1..mb+db, nb+1..nb+eb]
     544             :  * as an (m x n)-matrix, padding the input with zeroes as necessary. */
     545             : static void
     546       66254 : add_slices_ip(long m, long n,
     547             :            GEN A, long ma, long da, long na, long ea,
     548             :            GEN B, long mb, long db, long nb, long eb,
     549             :            GEN M, long dy, long dx, ulong p)
     550             : {
     551       66254 :   long min_d = minss(da, db), min_e = minss(ea, eb), i, j;
     552             :   GEN C;
     553             : 
     554     2780930 :   for (j = 1; j <= min_e; j++) {
     555     2714674 :     C = gel(M, j + dx) + dy;
     556   123894325 :     for (i = 1; i <= min_d; i++)
     557   121179651 :       uel(C, i) = Fl_add(ucoeff(A, ma + i, na + j),
     558   121179679 :                         ucoeff(B, mb + i, nb + j), p);
     559     2779206 :     for (; i <= da; i++)
     560       64560 :       uel(C, i) = ucoeff(A, ma + i, na + j);
     561     2714646 :     for (; i <= db; i++)
     562           0 :       uel(C, i) = ucoeff(B, mb + i, nb + j);
     563     2714646 :     for (; i <= m; i++)
     564           0 :       uel(C, i) = 0;
     565             :   }
     566       69869 :   for (; j <= ea; j++) {
     567        3613 :     C = gel(M, j + dx) + dy;
     568      195159 :     for (i = 1; i <= da; i++)
     569      191546 :       uel(C, i) = ucoeff(A, ma + i, na + j);
     570        3613 :     for (; i <= m; i++)
     571           0 :       uel(C, i) = 0;
     572             :   }
     573       66256 :   for (; j <= eb; j++) {
     574           0 :     C = gel(M, j + dx) + dy;
     575           0 :     for (i = 1; i <= db; i++)
     576           0 :       uel(C, i) = ucoeff(B, mb + i, nb + j);
     577           0 :     for (; i <= m; i++)
     578           0 :       uel(C, i) = 0;
     579             :   }
     580       66256 :   for (; j <= n; j++) {
     581           0 :     C = gel(M, j + dx) + dy;
     582           0 :     for (i = 1; i <= m; i++)
     583           0 :       uel(C, i) = 0;
     584             :   }
     585       66256 : }
     586             : 
     587             : static GEN
     588       33128 : add_slices(long m, long n,
     589             :            GEN A, long ma, long da, long na, long ea,
     590             :            GEN B, long mb, long db, long nb, long eb, ulong p)
     591             : {
     592             :   GEN M;
     593             :   long j;
     594       33128 :   M = cgetg(n + 1, t_MAT);
     595     1415027 :   for (j = 1; j <= n; j++)
     596     1381900 :     gel(M, j) = cgetg(m + 1, t_VECSMALL);
     597       33127 :   add_slices_ip(m, n, A, ma, da, na, ea, B, mb, db, nb, eb, M, 0, 0, p);
     598       33128 :   return M;
     599             : }
     600             : 
     601             : /* Return A[ma+1..ma+da, na+1..na+ea] - B[mb+1..mb+db, nb+1..nb+eb]
     602             :  * as an (m x n)-matrix, padding the input with zeroes as necessary. */
     603             : static GEN
     604       57974 : subtract_slices(long m, long n,
     605             :                 GEN A, long ma, long da, long na, long ea,
     606             :                 GEN B, long mb, long db, long nb, long eb, ulong p)
     607             : {
     608       57974 :   long min_d = minss(da, db), min_e = minss(ea, eb), i, j;
     609       57974 :   GEN M = cgetg(n + 1, t_MAT), C;
     610             : 
     611     2526676 :   for (j = 1; j <= min_e; j++) {
     612     2468702 :     gel(M, j) = C = cgetg(m + 1, t_VECSMALL);
     613   116108861 :     for (i = 1; i <= min_d; i++)
     614   113640164 :       uel(C, i) = Fl_sub(ucoeff(A, ma + i, na + j),
     615   113639949 :                         ucoeff(B, mb + i, nb + j), p);
     616     2569360 :     for (; i <= da; i++)
     617      100448 :       uel(C, i) = ucoeff(A, ma + i, na + j);
     618     2543952 :     for (; i <= db; i++)
     619       75040 :       uel(C, i) = Fl_neg(ucoeff(B, mb + i, nb + j), p);
     620     2468912 :     for (; i <= m; i++)
     621           0 :       uel(C, i) = 0;
     622             :   }
     623       57974 :   for (; j <= ea; j++) {
     624           0 :     gel(M, j) = C = cgetg(m + 1, t_VECSMALL);
     625           0 :     for (i = 1; i <= da; i++)
     626           0 :       uel(C, i) = ucoeff(A, ma + i, na + j);
     627           0 :     for (; i <= m; i++)
     628           0 :       uel(C, i) = 0;
     629             :   }
     630       59393 :   for (; j <= eb; j++) {
     631        1419 :     gel(M, j) = C = cgetg(m + 1, t_VECSMALL);
     632       82481 :     for (i = 1; i <= db; i++)
     633       81062 :       uel(C, i) = Fl_neg(ucoeff(B, mb + i, nb + j), p);
     634        1419 :     for (; i <= m; i++)
     635           0 :       uel(C, i) = 0;
     636             :   }
     637       59393 :   for (; j <= n; j++)
     638        1419 :     gel(M, j) = zero_Flv(m);
     639       57974 :   return M;
     640             : }
     641             : 
     642             : static GEN Flm_mul_i(GEN x, GEN y, long l, long lx, long ly, ulong p, ulong pi);
     643             : 
     644             : /* Strassen-Winograd matrix product A (m x n) * B (n x p) */
     645             : static GEN
     646        8282 : Flm_mul_sw(GEN A, GEN B, long m, long n, long p, ulong l, ulong li)
     647             : {
     648             :   pari_sp av;
     649        8282 :   long m1 = (m + 1)/2, m2 = m/2,
     650        8282 :     n1 = (n + 1)/2, n2 = n/2,
     651        8282 :     p1 = (p + 1)/2, p2 = p/2;
     652             :   GEN A11, A12, A22, B11, B21, B22,
     653             :     S1, S2, S3, S4, T1, T2, T3, T4,
     654             :     M1, M2, M3, M4, M5, M6, M7,
     655             :     V1, V2, V3, C;
     656             :   long j;
     657        8282 :   C = cgetg(p + 1, t_MAT);
     658      676685 :   for (j = 1; j <= p; j++)
     659      668403 :     gel(C, j) = cgetg(m + 1, t_VECSMALL);
     660        8282 :   av = avma;
     661        8282 :   T2 = subtract_slices(n1, p2, B, 0, n1, p1, p2, B, n1, n2, p1, p2, l);
     662        8282 :   S1 = subtract_slices(m2, n1, A, m1, m2, 0, n1, A, 0, m2, 0, n1, l);
     663        8282 :   M2 = Flm_mul_i(S1, T2, m2 + 1, n1 + 1, p2 + 1, l, li);
     664        8282 :   if (gc_needed(av, 1))
     665           0 :     (void)gc_all(av, 2, &T2, &M2);  /* destroy S1 */
     666        8282 :   T3 = subtract_slices(n1, p1, T2, 0, n1, 0, p2, B, 0, n1, 0, p1, l);
     667        8282 :   if (gc_needed(av, 1))
     668           0 :     (void)gc_all(av, 2, &M2, &T3);  /* destroy T2 */
     669        8282 :   S2 = add_slices(m2, n1, A, m1, m2, 0, n1, A, m1, m2, n1, n2, l);
     670        8282 :   T1 = subtract_slices(n1, p1, B, 0, n1, p1, p2, B, 0, n1, 0, p2, l);
     671        8282 :   M3 = Flm_mul_i(S2, T1, m2 + 1, n1 + 1, p2 + 1, l, li);
     672        8282 :   if (gc_needed(av, 1))
     673           0 :     (void)gc_all(av, 4, &M2, &T3, &S2, &M3);  /* destroy T1 */
     674        8282 :   S3 = subtract_slices(m1, n1, S2, 0, m2, 0, n1, A, 0, m1, 0, n1, l);
     675        8282 :   if (gc_needed(av, 1))
     676           0 :     (void)gc_all(av, 4, &M2, &T3, &M3, &S3);  /* destroy S2 */
     677        8282 :   A11 = matslice(A, 1, m1, 1, n1);
     678        8282 :   B11 = matslice(B, 1, n1, 1, p1);
     679        8282 :   M1 = Flm_mul_i(A11, B11, m1 + 1, n1 + 1, p1 + 1, l, li);
     680        8282 :   if (gc_needed(av, 1))
     681           0 :     (void)gc_all(av, 5, &M2, &T3, &M3, &S3, &M1);  /* destroy A11, B11 */
     682        8282 :   A12 = matslice(A, 1, m1, n1 + 1, n);
     683        8282 :   B21 = matslice(B, n1 + 1, n, 1, p1);
     684        8282 :   M4 = Flm_mul_i(A12, B21, m1 + 1, n2 + 1, p1 + 1, l, li);
     685        8282 :   if (gc_needed(av, 1))
     686           0 :     (void)gc_all(av, 6, &M2, &T3, &M3, &S3, &M1, &M4);  /* destroy A12, B21 */
     687        8282 :   add_slices_ip(m1, p1, M1, 0, m1, 0, p1, M4, 0, m1, 0, p1, C, 0, 0, l);
     688        8282 :   if (gc_needed(av, 1))
     689           0 :     (void)gc_all(av, 5, &M2, &T3, &M3, &S3, &M1);  /* destroy M4 */
     690        8282 :   M5 = Flm_mul_i(S3, T3, m1 + 1, n1 + 1, p1 + 1, l, li);
     691        8282 :   S4 = subtract_slices(m1, n2, A, 0, m1, n1, n2, S3, 0, m1, 0, n2, l);
     692        8282 :   if (gc_needed(av, 1))
     693           0 :     (void)gc_all(av, 6, &M2, &T3, &M3, &M1, &M5, &S4);  /* destroy S3 */
     694        8282 :   T4 = add_slices(n2, p1, B, n1, n2, 0, p1, T3, 0, n2, 0, p1, l);
     695        8282 :   if (gc_needed(av, 1))
     696           0 :     (void)gc_all(av, 6, &M2, &M3, &M1, &M5, &S4, &T4);  /* destroy T3 */
     697        8282 :   V1 = subtract_slices(m1, p1, M1, 0, m1, 0, p1, M5, 0, m1, 0, p1, l);
     698        8282 :   if (gc_needed(av, 1))
     699           0 :     (void)gc_all(av, 5, &M2, &M3, &S4, &T4, &V1);  /* destroy M1, M5 */
     700        8282 :   B22 = matslice(B, n1 + 1, n, p1 + 1, p);
     701        8282 :   M6 = Flm_mul_i(S4, B22, m1 + 1, n2 + 1, p2 + 1, l, li);
     702        8282 :   if (gc_needed(av, 1))
     703           0 :     (void)gc_all(av, 5, &M2, &M3, &T4, &V1, &M6);  /* destroy S4, B22 */
     704        8282 :   A22 = matslice(A, m1 + 1, m, n1 + 1, n);
     705        8282 :   M7 = Flm_mul_i(A22, T4, m2 + 1, n2 + 1, p1 + 1, l, li);
     706        8282 :   if (gc_needed(av, 1))
     707           0 :     (void)gc_all(av, 5, &M2, &M3, &V1, &M6, &M7);  /* destroy A22, T4 */
     708        8282 :   V3 = add_slices(m1, p2, V1, 0, m1, 0, p2, M3, 0, m2, 0, p2, l);
     709        8282 :   add_slices_ip(m1, p2, V3, 0, m1, 0, p2, M6, 0, m1, 0, p2, C, 0, p1, l);
     710        8282 :   if (gc_needed(av, 1))
     711           0 :     (void)gc_all(av, 4, &M2, &M3, &V1, &M7);  /* destroy V3, M6 */
     712        8282 :   V2 = add_slices(m2, p1, V1, 0, m2, 0, p1, M2, 0, m2, 0, p2, l);
     713        8282 :   if (gc_needed(av, 1))
     714           0 :     (void)gc_all(av, 3, &M3, &M7, &V2);  /* destroy V1, M2 */
     715        8282 :   add_slices_ip(m2, p1, V2, 0, m2, 0, p1, M7, 0, m2, 0, p1, C, m1, 0, l);
     716        8282 :   add_slices_ip(m2, p2, V2, 0, m2, 0, p2, M3, 0, m2, 0, p2, C, m1, p1, l);
     717        8282 :   set_avma(av); return C;
     718             : }
     719             : 
     720             : /* Strassen-Winograd used for dim >= ZM_sw_bound */
     721             : static GEN
     722    28232366 : Flm_mul_i(GEN x, GEN y, long l, long lx, long ly, ulong p, ulong pi)
     723             : {
     724    28232366 :   ulong e = expu(p);
     725             : #ifdef LONG_IS_64BIT /* Beware to update ZM_mul_i if this changes */
     726    23699382 :   long Flm_sw_bound = e <= 29 ? 140: e <=62 ? 40: 70;
     727             : #else
     728     4533444 :   long Flm_sw_bound = e <= 12 ? 230: e <=14 ? 170 : e <=17 ? 110: 120;
     729             : #endif
     730    28232826 :   if (l <= Flm_sw_bound || lx <= Flm_sw_bound || ly <= Flm_sw_bound)
     731    28224544 :     return Flm_mul_classical(x, y, l, lx, ly, p, pi);
     732             :   else
     733        8282 :     return Flm_mul_sw(x, y, l - 1, lx - 1, ly - 1, p, pi);
     734             : }
     735             : 
     736             : GEN
     737    13663898 : Flm_mul_pre(GEN x, GEN y, ulong p, ulong pi)
     738             : {
     739    13663898 :   long lx=lg(x), ly=lg(y);
     740    13663898 :   if (ly==1) return cgetg(1,t_MAT);
     741    13663898 :   if (lx==1) return zero_Flm(0, ly-1);
     742    13663898 :   return Flm_mul_i(x, y, lgcols(x), lx, ly, p, pi);
     743             : }
     744             : 
     745             : GEN
     746    14430356 : Flm_mul(GEN x, GEN y, ulong p)
     747             : {
     748    14430356 :   long lx=lg(x), ly=lg(y);
     749    14430356 :   if (ly==1) return cgetg(1,t_MAT);
     750    14430069 :   if (lx==1) return zero_Flm(0, ly-1);
     751    14430069 :   return Flm_mul_i(x, y, lgcols(x), lx, ly, p, get_Fl_red(p));
     752             : }
     753             : 
     754             : GEN
     755       79186 : Flm_sqr(GEN x, ulong p)
     756             : {
     757       79186 :   long lx = lg(x);
     758       79186 :   if (lx==1) return cgetg(1,t_MAT);
     759       79186 :   return Flm_mul_i(x, x, lx, lx, lx, p, get_Fl_red(p));
     760             : }
     761             : 
     762             : struct _Flm
     763             : {
     764             :   ulong p;
     765             :   long n;
     766             : };
     767             : 
     768             : static GEN
     769       13861 : _Flm_mul(void *E , GEN x, GEN y)
     770       13861 : { return Flm_mul(x,y,((struct _Flm*)E)->p); }
     771             : static GEN
     772       79186 : _Flm_sqr(void *E, GEN x)
     773       79186 : { return Flm_sqr(x,((struct _Flm*)E)->p); }
     774             : static GEN
     775         826 : _Flm_one(void *E)
     776         826 : { return matid_Flm(((struct _Flm*)E)->n); }
     777             : GEN
     778       45309 : Flm_powu(GEN x, ulong n, ulong p)
     779             : {
     780             :   struct _Flm d;
     781       45309 :   if (!n) return matid(lg(x)-1);
     782       45309 :   d.p = p;
     783       45309 :   return gen_powu(x, n, (void*)&d, &_Flm_sqr, &_Flm_mul);
     784             : }
     785             : GEN
     786         826 : Flm_powers(GEN x, ulong n, ulong p)
     787             : {
     788             :   struct _Flm d;
     789         826 :   d.p = p;
     790         826 :   d.n = lg(x)-1;
     791         826 :   return gen_powers(x, n, 1, (void*)&d,
     792             :                     &_Flm_sqr, &_Flm_mul, &_Flm_one);
     793             : }
     794             : 
     795             : static GEN
     796           0 : _FpM_mul(void *p , GEN x, GEN y)
     797           0 : { return FpM_mul(x,y,(GEN)p); }
     798             : static GEN
     799           0 : _FpM_sqr(void *p, GEN x)
     800           0 : { return FpM_mul(x,x,(GEN)p); }
     801             : GEN
     802           0 : FpM_powu(GEN x, ulong n, GEN p)
     803             : {
     804           0 :   if (!n) return matid(lg(x)-1);
     805           0 :   if (lgefint(p) == 3)
     806             :   {
     807           0 :     pari_sp av = avma;
     808           0 :     ulong pp = uel(p,2);
     809             :     GEN z;
     810           0 :     if (pp == 2)
     811           0 :       z = F2m_to_ZM(F2m_powu(ZM_to_F2m(x),n));
     812             :     else
     813           0 :       z = Flm_to_ZM(Flm_powu(ZM_to_Flm(x, pp), n, pp));
     814           0 :     return gc_upto(av, z);
     815             :   }
     816           0 :   return gen_powu(x, n, (void*)p, &_FpM_sqr, &_FpM_mul);
     817             : }
     818             : 
     819             : /*Multiple a column vector by a line vector to make a matrix*/
     820             : GEN
     821          14 : Flc_Flv_mul(GEN x, GEN y, ulong p)
     822             : {
     823          14 :   long i,j, lx=lg(x), ly=lg(y);
     824             :   GEN z;
     825          14 :   if (ly==1) return cgetg(1,t_MAT);
     826          14 :   z = cgetg(ly, t_MAT);
     827          49 :   for (j=1; j < ly; j++)
     828             :   {
     829          35 :     GEN zj = cgetg(lx,t_VECSMALL);
     830         112 :     for (i=1; i<lx; i++)
     831          77 :       uel(zj,i) = Fl_mul(uel(x,i), uel(y,j), p);
     832          35 :     gel(z,j) = zj;
     833             :   }
     834          14 :   return z;
     835             : }
     836             : 
     837             : /*Multiple a column vector by a line vector to make a matrix*/
     838             : GEN
     839        5777 : FpC_FpV_mul(GEN x, GEN y, GEN p)
     840             : {
     841        5777 :   long i,j, lx=lg(x), ly=lg(y);
     842             :   GEN z;
     843        5777 :   if (ly==1) return cgetg(1,t_MAT);
     844        5777 :   z = cgetg(ly,t_MAT);
     845       63885 :   for (j=1; j < ly; j++)
     846             :   {
     847       58108 :     GEN zj = cgetg(lx,t_COL);
     848     1371116 :     for (i=1; i<lx; i++) gel(zj,i) = Fp_mul(gel(x,i),gel(y,j), p);
     849       58108 :     gel(z, j) = zj;
     850             :   }
     851        5777 :   return z;
     852             : }
     853             : 
     854             : /* Multiply a line vector by a column and return a scalar (t_INT) */
     855             : GEN
     856     8491009 : FpV_dotproduct(GEN x, GEN y, GEN p)
     857             : {
     858     8491009 :   long i, lx = lg(x);
     859             :   pari_sp av;
     860             :   GEN c;
     861     8491009 :   if (lx == 1) return gen_0;
     862     8488496 :   av = avma; c = mulii(gel(x,1),gel(y,1));
     863    30285855 :   for (i=2; i<lx; i++) c = addii(c, mulii(gel(x,i),gel(y,i)));
     864     8488433 :   return gc_INT(av, modii(c,p));
     865             : }
     866             : GEN
     867           0 : FpV_dotsquare(GEN x, GEN p)
     868             : {
     869           0 :   long i, lx = lg(x);
     870             :   pari_sp av;
     871             :   GEN c;
     872           0 :   if (lx == 1) return gen_0;
     873           0 :   av = avma; c = sqri(gel(x,1));
     874           0 :   for (i=2; i<lx; i++) c = addii(c, sqri(gel(x,i)));
     875           0 :   return gc_INT(av, modii(c,p));
     876             : }
     877             : 
     878             : INLINE ulong
     879     9383092 : Flv_dotproductspec_SMALL(GEN x, GEN y, ulong p, long lx)
     880             : {
     881     9383092 :   ulong c = uel(x,0) * uel(y,0);
     882             :   long k;
     883    66488802 :   for (k = 1; k < lx; k++) {
     884    57105710 :     c += uel(x,k) * uel(y,k);
     885    57105710 :     if (c & HIGHBIT) c %= p;
     886             :   }
     887     9383092 :   return c % p;
     888             : }
     889             : 
     890             : INLINE ulong
     891      748114 : Flv_dotproductspec_i(GEN x, GEN y, ulong p, ulong pi, long lx)
     892             : {
     893             :   ulong l0, l1, v1, h0, h1;
     894      748114 :   long i = 0;
     895             :   LOCAL_OVERFLOW;
     896             :   LOCAL_HIREMAINDER;
     897      748114 :   l1 = mulll(uel(x,i), uel(y,i)); h1 = hiremainder; v1 = 0;
     898    15480608 :   while (++i < lx) {
     899    14732494 :     l0 = mulll(uel(x,i), uel(y,i)); h0 = hiremainder;
     900    14732494 :     l1 = addll(l0, l1); h1 = addllx(h0, h1); v1 += overflow;
     901             :   }
     902      748114 :   if (v1 == 0) return remll_pre(h1, l1, p, pi);
     903      464890 :   else return remlll_pre(v1, h1, l1, p, pi);
     904             : }
     905             : 
     906             : ulong
     907      531366 : Flv_dotproduct(GEN x, GEN y, ulong p)
     908             : {
     909      531366 :   long lx = lg(x)-1;
     910      531366 :   if (lx == 0) return 0;
     911      531366 :   if (SMALL_ULONG(p))
     912      531366 :     return Flv_dotproductspec_SMALL(x+1, y+1, p, lx);
     913             :   else
     914           0 :     return Flv_dotproductspec_i(x+1, y+1, p, get_Fl_red(p), lx);
     915             : }
     916             : 
     917             : ulong
     918       66256 : Flv_dotproduct_pre(GEN x, GEN y, ulong p, ulong pi)
     919             : {
     920       66256 :   long lx = lg(x)-1;
     921       66256 :   if (lx == 0) return 0;
     922       66256 :   if (SMALL_ULONG(p))
     923       60044 :     return Flv_dotproductspec_SMALL(x+1, y+1, p, lx);
     924             :   else
     925        6212 :     return Flv_dotproductspec_i(x+1, y+1, p, pi, lx);
     926             : }
     927             : 
     928             : ulong
     929     9601223 : Flx_dotproduct_pre(GEN x, GEN y, ulong p, ulong pi)
     930             : {
     931     9601223 :   long lx = minss(lgpol(x), lgpol(y));
     932     9601219 :   if (lx == 0) return 0;
     933     9533584 :   if (pi)
     934      741902 :     return Flv_dotproductspec_i(x+2, y+2, p, get_Fl_red(p), lx);
     935             :   else
     936     8791682 :     return Flv_dotproductspec_SMALL(x+2, y+2, p, lx);
     937             : }
     938             : ulong
     939           0 : Flx_dotproduct(GEN x, GEN y, ulong p)
     940           0 : { return Flx_dotproduct_pre(x, y, p, SMALL_ULONG(p)? 0: get_Fl_red(p)); }
     941             : 
     942             : GEN
     943     1752784 : FpM_FpC_mul(GEN x, GEN y, GEN p)
     944             : {
     945     1752784 :   long lx = lg(x);
     946     1752784 :   return lx==1? cgetg(1,t_COL): FpM_FpC_mul_i(x, y, lx, lgcols(x), p);
     947             : }
     948             : GEN
     949      887025 : Flm_Flc_mul(GEN x, GEN y, ulong p)
     950             : {
     951      887025 :   long l, lx = lg(x);
     952      887025 :   if (lx==1) return cgetg(1,t_VECSMALL);
     953      887025 :   l = lgcols(x);
     954      887025 :   if (p==2)
     955      310747 :     return Flm_Flc_mul_i_2(x, y, lx, l);
     956      576278 :   else if (SMALL_ULONG(p))
     957      338938 :     return Flm_Flc_mul_i_SMALL(x, y, lx, l, p);
     958             :   else
     959      237340 :     return Flm_Flc_mul_i(x, y, lx, l, p, get_Fl_red(p));
     960             : }
     961             : 
     962             : /* allow pi = 0 */
     963             : GEN
     964        6791 : Flm_Flc_mul_pre(GEN x, GEN y, ulong p, ulong pi)
     965             : {
     966        6791 :   long l, lx = lg(x);
     967             :   GEN z;
     968        6791 :   if (lx==1) return cgetg(1,t_VECSMALL);
     969        6791 :   l = lgcols(x);
     970        6791 :   z = cgetg(l, t_VECSMALL);
     971        6791 :   if (SMALL_ULONG(p))
     972        4407 :     __Flm_Flc_mul_i_SMALL(z, x, y, lx, l, p);
     973             :   else
     974        2384 :     __Flm_Flc_mul_i(z, x, y, lx, l, p, pi);
     975        6791 :   return z;
     976             : }
     977             : 
     978             : /* allow pi = 0 */
     979             : GEN
     980     7730042 : Flm_Flc_mul_pre_Flx(GEN x, GEN y, ulong p, ulong pi, long sv)
     981             : {
     982     7730042 :   long l, lx = lg(x);
     983             :   GEN z;
     984     7730042 :   if (lx==1) return pol0_Flx(sv);
     985     7730042 :   l = lgcols(x);
     986     7728189 :   z = cgetg(l + 1, t_VECSMALL); z[1] = sv;
     987     7726579 :   if (SMALL_ULONG(p))
     988     3216184 :     __Flm_Flc_mul_i_SMALL(z + 1, x, y, lx, l, p);
     989             :   else
     990     4510395 :     __Flm_Flc_mul_i(z + 1, x, y, lx, l, p, pi);
     991     7741836 :   return Flx_renormalize(z, l + 1);
     992             : }
     993             : 
     994             : /* RgV_to_RgX(FpM_FpC_mul(x,y,p), v), p != NULL, memory clean */
     995             : GEN
     996     1154696 : FpM_FpC_mul_FpX(GEN x, GEN y, GEN p, long v)
     997             : {
     998     1154696 :   long i, l, lx = lg(x);
     999             :   GEN z;
    1000     1154696 :   if (lx==1) return pol_0(v);
    1001     1154696 :   l = lgcols(x);
    1002     1154696 :   z = new_chunk(l+1);
    1003     1509855 :   for (i=l-1; i; i--)
    1004             :   {
    1005     1494990 :     pari_sp av = avma;
    1006     1494990 :     GEN t = FpMrow_FpC_mul_i(x,y,lx,i,p);
    1007     1494987 :     if (signe(t))
    1008             :     {
    1009     1139830 :       if (i != l-1) stackdummy((pari_sp)(z + l+1), (pari_sp)(z + i+2));
    1010     1139830 :       gel(z,i+1) = t;
    1011     1139830 :       break;
    1012             :     }
    1013      355157 :     set_avma(av);
    1014             :   }
    1015     1154695 :   if (!i) { set_avma((pari_sp)(z + l+1)); return pol_0(v); }
    1016     1139830 :   z[0] = evaltyp(t_POL) | _evallg(i+2);
    1017     1139830 :   z[1] = evalsigne(1) | evalvarn(v);
    1018     3337432 :   for (; i; i--) gel(z,i+1) = FpMrow_FpC_mul_i(x,y,lx,i,p);
    1019     1139834 :   return z;
    1020             : }
    1021             : 
    1022             : /********************************************************************/
    1023             : /**                                                                **/
    1024             : /**                           TRANSPOSITION                        **/
    1025             : /**                                                                **/
    1026             : /********************************************************************/
    1027             : 
    1028             : /* == zm_transpose */
    1029             : GEN
    1030      730726 : Flm_transpose(GEN x)
    1031             : {
    1032      730726 :   long i, dx, lx = lg(x);
    1033             :   GEN y;
    1034      730726 :   if (lx == 1) return cgetg(1,t_MAT);
    1035      730593 :   dx = lgcols(x); y = cgetg(dx,t_MAT);
    1036     8830557 :   for (i=1; i<dx; i++) gel(y,i) = Flm_row(x,i);
    1037      730592 :   return y;
    1038             : }
    1039             : 
    1040             : /********************************************************************/
    1041             : /**                                                                **/
    1042             : /**                           SCALAR MATRICES                      **/
    1043             : /**                                                                **/
    1044             : /********************************************************************/
    1045             : 
    1046             : GEN
    1047        2009 : gen_matid(long n, void *E, const struct bb_field *S)
    1048             : {
    1049        2009 :   GEN y = cgetg(n+1,t_MAT), _0, _1;
    1050             :   long i;
    1051        2009 :   if (n < 0) pari_err_DOMAIN("gen_matid", "dimension","<",gen_0,stoi(n));
    1052        2009 :   _0 = S->s(E,0);
    1053        2009 :   _1 = S->s(E,1);
    1054        8883 :   for (i=1; i<=n; i++)
    1055             :   {
    1056        6874 :     GEN z = const_col(n, _0); gel(z,i) = _1;
    1057        6874 :     gel(y, i) = z;
    1058             :   }
    1059        2009 :   return y;
    1060             : }
    1061             : 
    1062             : GEN
    1063          35 : matid_F2xqM(long n, GEN T)
    1064             : {
    1065             :   void *E;
    1066          35 :   const struct bb_field *S = get_F2xq_field(&E, T);
    1067          35 :   return gen_matid(n, E, S);
    1068             : }
    1069             : GEN
    1070           7 : matid_FlxqM(long n, GEN T, ulong p)
    1071             : {
    1072             :   void *E;
    1073           7 :   const struct bb_field *S = get_Flxq_field(&E, T, p);
    1074           7 :   return gen_matid(n, E, S);
    1075             : }
    1076             : 
    1077             : GEN
    1078     1435516 : matid_Flm(long n)
    1079             : {
    1080     1435516 :   GEN y = cgetg(n+1,t_MAT);
    1081             :   long i;
    1082     1435511 :   if (n < 0) pari_err_DOMAIN("matid_Flm", "dimension","<",gen_0,stoi(n));
    1083     9132861 :   for (i=1; i<=n; i++) { gel(y,i) = zero_zv(n); ucoeff(y, i,i) = 1; }
    1084     1435490 :   return y;
    1085             : }
    1086             : 
    1087             : GEN
    1088          42 : scalar_Flm(long s, long n)
    1089             : {
    1090             :   long i;
    1091          42 :   GEN y = cgetg(n+1,t_MAT);
    1092         560 :   for (i=1; i<=n; i++) { gel(y,i) = zero_Flv(n); coeff(y, i,i) = s; }
    1093          42 :   return y;
    1094             : }
    1095             : 
    1096             : /********************************************************************/
    1097             : /**                                                                **/
    1098             : /**                           CONVERSIONS                          **/
    1099             : /**                                                                **/
    1100             : /********************************************************************/
    1101             : GEN
    1102    54925059 : ZV_to_Flv(GEN x, ulong p)
    1103   560007963 : { pari_APPLY_ulong(umodiu(gel(x,i), p)) }
    1104             : 
    1105             : GEN
    1106    13588905 : ZM_to_Flm(GEN x, ulong p)
    1107    67287552 : { pari_APPLY_same(ZV_to_Flv(gel(x,i), p)) }
    1108             : 
    1109             : GEN
    1110       14722 : ZVV_to_FlvV(GEN x, ulong p)
    1111      112431 : { pari_APPLY_type(t_VEC, ZV_to_Flv(gel(x,i), p)) }
    1112             : 
    1113             : GEN
    1114        4780 : ZMV_to_FlmV(GEN x, ulong m)
    1115       37006 : { pari_APPLY_type(t_VEC,ZM_to_Flm(gel(x,i), m)) }
    1116             : 
    1117             : /*                          TO INTMOD                        */
    1118             : static GEN
    1119    18792807 : to_intmod(GEN x, GEN p) { retmkintmod(modii(x, p), p); }
    1120             : static GEN
    1121      708315 : Fl_to_intmod(ulong x, GEN p) { retmkintmod(utoi(x), p); }
    1122             : 
    1123             : GEN
    1124        4003 : Fp_to_mod(GEN z, GEN p)
    1125             : {
    1126        4003 :   retmkintmod(modii(z, p), icopy(p));
    1127             : }
    1128             : 
    1129             : GEN
    1130      966014 : FpX_to_mod_raw(GEN z, GEN p)
    1131             : {
    1132      966014 :   long i, l = lg(z);
    1133             :   GEN x;
    1134      966014 :   if (l == 2)
    1135             :   {
    1136      510440 :     x = cgetg(3,t_POL); x[1] = z[1];
    1137      510440 :     gel(x,2) = mkintmod(gen_0,p); return x;
    1138             :   }
    1139      455574 :   x = cgetg(l,t_POL); x[1] = z[1];
    1140     3824884 :   for (i=2; i<l; i++) gel(x,i) = to_intmod(gel(z,i), p);
    1141      455574 :   return normalizepol_lg(x,l);
    1142             : }
    1143             : 
    1144             : /* z in Z[X], return z * Mod(1,p), normalized*/
    1145             : GEN
    1146     1232742 : FpX_to_mod(GEN z, GEN p)
    1147             : {
    1148     1232742 :   long i, l = lg(z);
    1149             :   GEN x;
    1150     1232742 :   if (l == 2)
    1151             :   {
    1152        1197 :     x = cgetg(3,t_POL); x[1] = z[1];
    1153        1197 :     gel(x,2) = mkintmod(gen_0,icopy(p)); return x;
    1154             :   }
    1155     1231545 :   x = cgetg(l,t_POL); x[1] = z[1]; p = icopy(p);
    1156    16551661 :   for (i=2; i<l; i++) gel(x,i) = to_intmod(gel(z,i), p);
    1157     1231545 :   return normalizepol_lg(x,l);
    1158             : }
    1159             : 
    1160             : GEN
    1161       84021 : FpXC_to_mod(GEN z, GEN p)
    1162             : {
    1163       84021 :   long i,l = lg(z);
    1164       84021 :   GEN x = cgetg(l, t_COL);
    1165       84021 :   p = icopy(p);
    1166      474159 :   for (i=1; i<l; i++)
    1167      390138 :     gel(x,i) = FpX_to_mod_raw(gel(z,i), p);
    1168       84021 :   return x;
    1169             : }
    1170             : 
    1171             : static GEN
    1172           0 : FpXC_to_mod_raw(GEN x, GEN p)
    1173           0 : { pari_APPLY_type(t_COL, FpX_to_mod_raw(gel(x,i), p)) }
    1174             : 
    1175             : GEN
    1176           0 : FpXM_to_mod(GEN z, GEN p)
    1177             : {
    1178           0 :   long i,l = lg(z);
    1179           0 :   GEN x = cgetg(l, t_MAT);
    1180           0 :   p = icopy(p);
    1181           0 :   for (i=1; i<l; i++)
    1182           0 :     gel(x,i) = FpXC_to_mod_raw(gel(z,i), p);
    1183           0 :   return x;
    1184             : }
    1185             : 
    1186             : /* z in Z^n, return z * Mod(1,p), normalized*/
    1187             : GEN
    1188       36180 : FpV_to_mod(GEN z, GEN p)
    1189             : {
    1190       36180 :   long i,l = lg(z);
    1191       36180 :   GEN x = cgetg(l, t_VEC);
    1192       36180 :   if (l == 1) return x;
    1193       36180 :   p = icopy(p);
    1194       72955 :   for (i=1; i<l; i++) gel(x,i) = to_intmod(gel(z,i), p);
    1195       36180 :   return x;
    1196             : }
    1197             : /* z in Z^n, return z * Mod(1,p), normalized*/
    1198             : GEN
    1199         105 : FpC_to_mod(GEN z, GEN p)
    1200             : {
    1201         105 :   long i, l = lg(z);
    1202         105 :   GEN x = cgetg(l, t_COL);
    1203         105 :   if (l == 1) return x;
    1204          91 :   p = icopy(p);
    1205         805 :   for (i=1; i<l; i++) gel(x,i) = to_intmod(gel(z,i), p);
    1206          91 :   return x;
    1207             : }
    1208             : /* z in Mat m,n(Z), return z * Mod(1,p), normalized*/
    1209             : GEN
    1210         226 : FpM_to_mod(GEN z, GEN p)
    1211             : {
    1212         226 :   long i, j, m, l = lg(z);
    1213         226 :   GEN  x = cgetg(l,t_MAT), y, zi;
    1214         226 :   if (l == 1) return x;
    1215         205 :   m = lgcols(z);
    1216         205 :   p = icopy(p);
    1217        2456 :   for (i=1; i<l; i++)
    1218             :   {
    1219        2251 :     gel(x,i) = cgetg(m,t_COL);
    1220        2251 :     y = gel(x,i); zi= gel(z,i);
    1221       66799 :     for (j=1; j<m; j++) gel(y,j) = to_intmod(gel(zi,j), p);
    1222             :   }
    1223         205 :   return x;
    1224             : }
    1225             : GEN
    1226          28 : Flc_to_mod(GEN z, ulong pp)
    1227             : {
    1228          28 :   long i, l = lg(z);
    1229          28 :   GEN p, x = cgetg(l, t_COL);
    1230          28 :   if (l == 1) return x;
    1231          28 :   p = utoipos(pp);
    1232         112 :   for (i=1; i<l; i++) gel(x,i) = Fl_to_intmod(z[i], p);
    1233          28 :   return x;
    1234             : }
    1235             : GEN
    1236       60324 : Flm_to_mod(GEN z, ulong pp)
    1237             : {
    1238       60324 :   long i, j, m, l = lg(z);
    1239       60324 :   GEN p, x = cgetg(l,t_MAT), y, zi;
    1240       60324 :   if (l == 1) return x;
    1241       60296 :   m = lgcols(z);
    1242       60296 :   p = utoipos(pp);
    1243      209518 :   for (i=1; i<l; i++)
    1244             :   {
    1245      149222 :     gel(x,i) = cgetg(m,t_COL);
    1246      149222 :     y = gel(x,i); zi= gel(z,i);
    1247      857453 :     for (j=1; j<m; j++) gel(y,j) = Fl_to_intmod(zi[j], p);
    1248             :   }
    1249       60296 :   return x;
    1250             : }
    1251             : 
    1252             : GEN
    1253         574 : FpVV_to_mod(GEN z, GEN p)
    1254             : {
    1255         574 :   long i, j, m, l = lg(z);
    1256         574 :   GEN  x = cgetg(l,t_VEC), y, zi;
    1257         574 :   if (l == 1) return x;
    1258         574 :   m = lgcols(z);
    1259         574 :   p = icopy(p);
    1260        1246 :   for (i=1; i<l; i++)
    1261             :   {
    1262         672 :     gel(x,i) = cgetg(m,t_VEC);
    1263         672 :     y = gel(x,i); zi= gel(z,i);
    1264        2016 :     for (j=1; j<m; j++) gel(y,j) = to_intmod(gel(zi,j), p);
    1265             :   }
    1266         574 :   return x;
    1267             : }
    1268             : 
    1269             : /* z in Z^n, return z * Mod(1,p), normalized*/
    1270             : GEN
    1271           7 : FpXQC_to_mod(GEN z, GEN T, GEN p)
    1272             : {
    1273           7 :   long i,l = lg(z);
    1274           7 :   GEN x = cgetg(l, t_COL);
    1275           7 :   if (l == 1) return x;
    1276           7 :   p = icopy(p);
    1277           7 :   T = FpX_to_mod_raw(T, p);
    1278          21 :   for (i=1; i<l; i++)
    1279          14 :     gel(x,i) = mkpolmod(FpX_to_mod_raw(gel(z,i), p), T);
    1280           7 :   return x;
    1281             : }
    1282             : 
    1283             : static GEN
    1284      551383 : Fq_to_mod_raw(GEN x, GEN T, GEN p)
    1285             : {
    1286      551383 :   GEN z = typ(x)==t_INT ? mkintmod(modii(x, p), p): FpX_to_mod_raw(x, p);
    1287      551383 :   return mkpolmod(z, T);
    1288             : }
    1289             : 
    1290             : /* z in Z^n, return z * Mod(1,p), normalized*/
    1291             : GEN
    1292          14 : FqC_to_mod(GEN z, GEN T, GEN p)
    1293             : {
    1294             :   GEN x;
    1295          14 :   long i,l = lg(z);
    1296          14 :   if (!T) return FpC_to_mod(z, p);
    1297          14 :   x = cgetg(l, t_COL);
    1298          14 :   if (l == 1) return x;
    1299          14 :   p = icopy(p);
    1300          14 :   T = FpX_to_mod_raw(T, p);
    1301         252 :   for (i=1; i<l; i++)
    1302         238 :     gel(x,i) = Fq_to_mod_raw(gel(z, i), T, p);
    1303          14 :   return x;
    1304             : }
    1305             : 
    1306             : /* z in Z^n, return z * Mod(1,p), normalized*/
    1307             : static GEN
    1308      106631 : FqC_to_mod_raw(GEN x, GEN T, GEN p)
    1309      657776 : { pari_APPLY_type(t_COL, Fq_to_mod_raw(gel(x,i), T, p)) }
    1310             : 
    1311             : /* z in Z^n, return z * Mod(1,p), normalized*/
    1312             : GEN
    1313       26040 : FqM_to_mod(GEN z, GEN T, GEN p)
    1314             : {
    1315             :   GEN x;
    1316       26040 :   long i,l = lg(z);
    1317       26040 :   if (!T) return FpM_to_mod(z, p);
    1318       26040 :   x = cgetg(l, t_MAT);
    1319       26040 :   if (l == 1) return x;
    1320       26026 :   p = icopy(p);
    1321       26026 :   T = FpX_to_mod_raw(T, p);
    1322      132657 :   for (i=1; i<l; i++)
    1323      106631 :     gel(x,i) = FqC_to_mod_raw(gel(z, i), T, p);
    1324       26026 :   return x;
    1325             : }
    1326             : 
    1327             : /********************************************************************/
    1328             : /*                                                                  */
    1329             : /*                     Blackbox linear algebra                      */
    1330             : /*                                                                  */
    1331             : /********************************************************************/
    1332             : 
    1333             : /* A sparse column (zCs) v is a t_COL with two components C and E which are
    1334             :  * t_VECSMALL of the same length, representing sum_i E[i]*e_{C[i]}, where
    1335             :  * (e_j) is the canonical basis.
    1336             :  * A sparse matrix (zMs) is a t_VEC of zCs */
    1337             : 
    1338             : /* FpCs and FpMs are identical but E[i] is interpreted as a _signed_ C long
    1339             :  * integer representing an element of Fp. This is important since p can be
    1340             :  * large and p+E[i] would not fit in a C long.  */
    1341             : 
    1342             : /* RgCs and RgMs are similar, except that the type of the component is
    1343             :  * unspecified. Functions handling RgCs/RgMs must be independent of the type
    1344             :  * of E. */
    1345             : 
    1346             : /* Most functions take an argument nbrow which is the number of lines of the
    1347             :  * column/matrix, which cannot be derived from the data. */
    1348             : 
    1349             : GEN
    1350           0 : zCs_to_ZC(GEN R, long nbrow)
    1351             : {
    1352           0 :   GEN C = gel(R,1), E = gel(R,2), c = zerocol(nbrow);
    1353           0 :   long j, l = lg(C);
    1354           0 :   for (j = 1; j < l; ++j) gel(c, C[j]) = stoi(E[j]);
    1355           0 :   return c;
    1356             : }
    1357             : 
    1358             : GEN
    1359           0 : zMs_to_ZM(GEN x, long nbrow)
    1360           0 : { pari_APPLY_type(t_MAT, zCs_to_ZC(gel(x, i), nbrow)) }
    1361             : 
    1362             : GEN
    1363           0 : zMs_compress(GEN M, long nbrow)
    1364             : {
    1365           0 :   pari_sp av = avma;
    1366             :   GEN p, q, W;
    1367           0 :   long c, i, l = lg(M), n;
    1368           0 :   GEN v = zero_F2v(nbrow);
    1369           0 :   for (i = 1; i < l; i++)
    1370             :   {
    1371           0 :     GEN Vi = gmael(M,i,1);
    1372           0 :     long li = lg(Vi), j;
    1373           0 :     for (j = 1; j < li; j++)
    1374           0 :       F2v_set(v, uel(Vi,j));
    1375             :   }
    1376           0 :   n = F2v_hamming(v);
    1377           0 :   p = cgetg(n+1, t_VECSMALL);
    1378           0 :   q = zero_Flv(nbrow);
    1379           0 :   for (c = 1, i = 1; i <= nbrow; i++)
    1380           0 :     if (F2v_coeff(v,i))
    1381             :     {
    1382           0 :       q[i] = c;
    1383           0 :       p[c++] = i;
    1384             :     }
    1385           0 :   W = cgetg(l, t_MAT);
    1386           0 :   for (i = 1; i < l; i++)
    1387             :   {
    1388           0 :     GEN Vi = gmael(M,i,1), Wi;
    1389           0 :     long li = lg(Vi), j;
    1390           0 :     Wi = cgetg(li, t_VECSMALL);
    1391           0 :     for (j = 1; j < li; j++)
    1392           0 :       uel(Wi, j) = uel(q,uel(Vi,j));
    1393           0 :     gel(W, i) = mkmat2(Wi, gmael(M,i,2));
    1394             :   }
    1395           0 :   return gc_GEN(av, mkvec2(W, p));
    1396             : }
    1397             : 
    1398             : /* Solve equation f(X) = B (mod p) where B is a FpV, and f is an endomorphism.
    1399             :  * Return either a solution as a t_COL, or a kernel vector as a t_VEC. */
    1400             : GEN
    1401         147 : gen_FpM_Wiedemann(void *E, GEN (*f)(void*, GEN), GEN B, GEN p)
    1402             : {
    1403         147 :   pari_sp ltop = avma;
    1404         147 :   long col = 0, n = lg(B)-1, m = 2*n+1;
    1405         147 :   if (ZV_equal0(B)) return zerocol(n);
    1406         147 :   while (++col <= n)
    1407             :   {
    1408         147 :     pari_sp btop = avma, av;
    1409             :     long i, lQ;
    1410         147 :     GEN V, Q, M, W = B;
    1411         147 :     GEN b = cgetg(m+2, t_POL);
    1412         147 :     b[1] = evalsigne(1)|evalvarn(0);
    1413         147 :     gel(b, 2) = gel(W, col);
    1414       46219 :     for (i = 3; i<m+2; i++)
    1415       46072 :       gel(b, i) = cgeti(lgefint(p));
    1416         147 :     av = avma;
    1417       46219 :     for (i = 3; i<m+2; i++)
    1418             :     {
    1419       46072 :       W = f(E, W);
    1420       46072 :       affii(gel(W, col),gel(b, i));
    1421       46072 :       if (gc_needed(av,1))
    1422             :       {
    1423          72 :         if (DEBUGMEM>1) pari_warn(warnmem,"Wiedemann: first loop, %ld",i);
    1424          72 :         W = gc_upto(av, W);
    1425             :       }
    1426             :     }
    1427         147 :     b = FpX_renormalize(b, m+2);
    1428         147 :     if (lgpol(b)==0) {set_avma(btop); continue; }
    1429         147 :     M = FpX_halfgcd(b, pol_xn(m, 0), p);
    1430         147 :     Q = FpX_neg(FpX_normalize(gcoeff(M, 2, 1),p),p);
    1431         147 :     W = B; lQ =lg(Q);
    1432         147 :     if (DEBUGLEVEL) err_printf("Wiedemann: deg. minpoly: %ld\n",lQ-3);
    1433         147 :     V = FpC_Fp_mul(W, gel(Q, lQ-2), p);
    1434         147 :     av = avma;
    1435       22742 :     for (i = lQ-3; i > 1; i--)
    1436             :     {
    1437       22595 :       W = f(E, W);
    1438       22595 :       V = ZC_lincomb(gen_1, gel(Q,i), V, W);
    1439       22595 :       if (gc_needed(av,1))
    1440             :       {
    1441         110 :         if (DEBUGMEM>1) pari_warn(warnmem,"Wiedemann: second loop, %ld",i);
    1442         110 :         (void)gc_all(av, 2, &V, &W);
    1443             :       }
    1444             :     }
    1445         147 :     V = FpC_red(V, p);
    1446         147 :     W = FpC_sub(f(E,V), B, p);
    1447         147 :     if (ZV_equal0(W)) return gc_GEN(ltop, V);
    1448           0 :     av = avma;
    1449           0 :     for (i = 1; i <= n; ++i)
    1450             :     {
    1451           0 :       V = W;
    1452           0 :       W = f(E, V);
    1453           0 :       if (ZV_equal0(W))
    1454           0 :         return gc_GEN(ltop, shallowtrans(V));
    1455           0 :       (void)gc_all(av, 2, &V, &W);
    1456             :     }
    1457           0 :     set_avma(btop);
    1458             :   }
    1459           0 :   return NULL;
    1460             : }
    1461             : 
    1462             : GEN
    1463           0 : zMs_ZC_mul(GEN M, GEN B)
    1464             : {
    1465             :   long i, j;
    1466           0 :   long n = lg(B)-1;
    1467           0 :   GEN V = zerocol(n);
    1468           0 :   for (i = 1; i <= n; ++i)
    1469           0 :     if (signe(gel(B, i)))
    1470             :     {
    1471           0 :       GEN R = gel(M, i), C = gel(R, 1), E = gel(R, 2);
    1472           0 :       long l = lg(C);
    1473           0 :       for (j = 1; j < l; ++j)
    1474             :       {
    1475           0 :         long k = C[j];
    1476           0 :         switch(E[j])
    1477             :         {
    1478           0 :         case 1:
    1479           0 :           gel(V, k) = gel(V,k)==gen_0 ? gel(B,i) : addii(gel(V, k), gel(B,i));
    1480           0 :           break;
    1481           0 :         case -1:
    1482           0 :           gel(V, k) = gel(V,k)==gen_0 ? negi(gel(B,i)) : subii(gel(V, k), gel(B,i));
    1483           0 :           break;
    1484           0 :         default:
    1485           0 :           gel(V, k) = gel(V,k)==gen_0 ? mulis(gel(B, i), E[j]) : addii(gel(V, k), mulis(gel(B, i), E[j]));
    1486           0 :           break;
    1487             :         }
    1488             :       }
    1489             :     }
    1490           0 :   return V;
    1491             : }
    1492             : 
    1493             : GEN
    1494           0 : FpMs_FpC_mul(GEN M, GEN B, GEN p) { return FpC_red(zMs_ZC_mul(M, B), p); }
    1495             : 
    1496             : GEN
    1497       68961 : FpV_FpMs_mul(GEN B, GEN M, GEN p)
    1498             : {
    1499       68961 :   long i, j, lM = lg(M);
    1500       68961 :   GEN V = cgetg(lM,t_VEC);
    1501    28331907 :   for (i = 1; i < lM; ++i)
    1502             :   {
    1503    28262946 :     GEN z, R = gel(M, i), C = gel(R, 1), E = gel(R, 2);
    1504    28262946 :     pari_sp av = avma;
    1505    28262946 :     long lC = lg(C);
    1506    28262946 :     if (lC == 1) { gel(V,i) = gen_0; continue; }
    1507    28262946 :     z = mulis(gel(B, C[1]), E[1]);
    1508   228726530 :     for (j = 2; j < lC; ++j)
    1509             :     {
    1510   200463584 :       GEN b = gel(B, C[j]);
    1511   200463584 :       switch(E[j])
    1512             :       {
    1513   131566519 :         case  1: z = addii(z, b); break;
    1514    57522273 :         case -1: z = subii(z, b); break;
    1515    11374792 :         default: z = addii(z, mulis(b, E[j])); break;
    1516             :       }
    1517             :     }
    1518    28262946 :     gel(V,i) = gc_INT(av, p? Fp_red(z, p): z);
    1519             :   }
    1520       68961 :   return V;
    1521             : }
    1522             : GEN
    1523           0 : ZV_zMs_mul(GEN B, GEN M) { return FpV_FpMs_mul(B, M, NULL); }
    1524             : 
    1525             : GEN
    1526           0 : ZlM_gauss(GEN a, GEN b, ulong p, long e, GEN C)
    1527             : {
    1528           0 :   pari_sp av = avma, av2;
    1529           0 :   GEN xi, xb, pi = gen_1, P;
    1530             :   long i;
    1531           0 :   if (!C) {
    1532           0 :     C = Flm_inv(ZM_to_Flm(a, p), p);
    1533           0 :     if (!C) pari_err_INV("ZlM_gauss", a);
    1534             :   }
    1535           0 :   P = utoipos(p);
    1536           0 :   av2 = avma;
    1537           0 :   xi = Flm_mul(C, ZM_to_Flm(b, p), p);
    1538           0 :   xb = Flm_to_ZM(xi);
    1539           0 :   for (i = 2; i <= e; i++)
    1540             :   {
    1541           0 :     pi = muliu(pi, p); /* = p^(i-1) */
    1542           0 :     b = ZM_Z_divexact(ZM_sub(b, ZM_nm_mul(a, xi)), P);
    1543           0 :     if (gc_needed(av,2))
    1544             :     {
    1545           0 :       if(DEBUGMEM>1) pari_warn(warnmem,"ZlM_gauss. i=%ld/%ld",i,e);
    1546           0 :       (void)gc_all(av2,3, &pi,&b,&xb);
    1547             :     }
    1548           0 :     xi = Flm_mul(C, ZM_to_Flm(b, p), p);
    1549           0 :     xb = ZM_add(xb, nm_Z_mul(xi, pi));
    1550             :   }
    1551           0 :   return gc_upto(av, xb);
    1552             : }
    1553             : 
    1554             : struct wrapper_modp_s {
    1555             :   GEN (*f)(void*, GEN);
    1556             :   void *E;
    1557             :   GEN p;
    1558             : };
    1559             : 
    1560             : /* compute f(x) mod p */
    1561             : static GEN
    1562           0 : wrap_relcomb_modp(void *E, GEN x)
    1563             : {
    1564           0 :   struct wrapper_modp_s *W = (struct wrapper_modp_s*)E;
    1565           0 :   return FpC_red(W->f(W->E, x), W->p);
    1566             : }
    1567             : static GEN
    1568           0 : wrap_relcomb(void*E, GEN x) { return zMs_ZC_mul((GEN)E, x); }
    1569             : 
    1570             : static GEN
    1571       68814 : wrap_relker(void*E, GEN x)
    1572             : {
    1573       68814 :   struct wrapper_modp_s *W = (struct wrapper_modp_s*)E;
    1574       68814 :   return FpV_FpMs_mul(x, (GEN) W->E, W->p);
    1575             : }
    1576             : 
    1577             : /* Solve f(X) = B (mod p^e); blackbox version of ZlM_gauss */
    1578             : GEN
    1579           0 : gen_ZpM_Dixon_Wiedemann(void *E, GEN (*f)(void*, GEN), GEN B, GEN p, long e)
    1580             : {
    1581             :   struct wrapper_modp_s W;
    1582           0 :   pari_sp av = avma;
    1583           0 :   GEN xb, xi, pi = gen_1;
    1584             :   long i;
    1585           0 :   W.E = E;
    1586           0 :   W.f = f;
    1587           0 :   W.p = p;
    1588           0 :   xi = gen_FpM_Wiedemann((void*)&W, wrap_relcomb_modp, FpC_red(B, p), p); /* f^(-1) B */
    1589           0 :   if (!xi || e == 1 || typ(xi) == t_VEC) return xi;
    1590           0 :   xb = xi;
    1591           0 :   for (i = 2; i <= e; i++)
    1592             :   {
    1593           0 :     pi = mulii(pi, p); /* = p^(i-1) */
    1594           0 :     B = ZC_Z_divexact(ZC_sub(B, f(E, xi)), p);
    1595           0 :     if (gc_needed(av,2))
    1596             :     {
    1597           0 :       if(DEBUGMEM>1) pari_warn(warnmem,"gen_ZpM_Dixon_Wiedemann. i=%ld",i);
    1598           0 :       (void)gc_all(av,3, &pi,&B,&xb);
    1599             :     }
    1600           0 :     xi = gen_FpM_Wiedemann((void*)&W, wrap_relcomb_modp, FpC_red(B, p), p);
    1601           0 :     if (!xi) return NULL;
    1602           0 :     if (typ(xi) == t_VEC) return gc_upto(av, xi);
    1603           0 :     xb = ZC_add(xb, ZC_Z_mul(xi, pi));
    1604             :   }
    1605           0 :   return gc_upto(av, xb);
    1606             : }
    1607             : 
    1608             : static GEN
    1609       23036 : vecprow(GEN A, GEN prow)
    1610             : {
    1611       23036 :   return mkvec2(vecsmallpermute(prow,gel(A,1)), gel(A,2));
    1612             : }
    1613             : 
    1614             : /* Solve the equation MX = A. Return either a solution as a t_COL,
    1615             :  * or the index of a column which is linearly dependent from the others as a
    1616             :  * t_VECSMALL with a single component. */
    1617             : GEN
    1618           0 : ZpMs_ZpCs_solve(GEN M, GEN A, long nbrow, GEN p, long e)
    1619             : {
    1620           0 :   pari_sp av = avma;
    1621             :   GEN pcol, prow;
    1622           0 :   long nbi=lg(M)-1, lR;
    1623             :   long i, n;
    1624             :   GEN Mp, Ap, Rp;
    1625             :   pari_timer ti;
    1626           0 :   if (DEBUGLEVEL) timer_start(&ti);
    1627           0 :   RgMs_structelim(M, nbrow, gel(A, 1), &pcol, &prow);
    1628           0 :   if (!pcol) return gc_NULL(av);
    1629           0 :   if (DEBUGLEVEL)
    1630           0 :     timer_printf(&ti,"structured elimination (%ld -> %ld)",nbi,lg(pcol)-1);
    1631           0 :   n = lg(pcol)-1;
    1632           0 :   Mp = cgetg(n+1, t_MAT);
    1633           0 :   for(i=1; i<=n; i++)
    1634           0 :     gel(Mp, i) = vecprow(gel(M,pcol[i]), prow);
    1635           0 :   Ap = zCs_to_ZC(vecprow(A, prow), n);
    1636           0 :   if (DEBUGLEVEL) timer_start(&ti);
    1637           0 :   Rp = gen_ZpM_Dixon_Wiedemann((void*)Mp,wrap_relcomb, Ap, p, e);
    1638           0 :   if (DEBUGLEVEL) timer_printf(&ti,"linear algebra");
    1639           0 :   if (!Rp) return gc_NULL(av);
    1640           0 :   lR = lg(Rp)-1;
    1641           0 :   if (typ(Rp) == t_COL)
    1642             :   {
    1643           0 :     GEN R = zerocol(nbi+1);
    1644           0 :     for (i=1; i<=lR; i++)
    1645           0 :        gel(R,pcol[i]) = gel(Rp,i);
    1646           0 :     return gc_GEN(av, R);
    1647             :   }
    1648           0 :   for (i = 1; i <= lR; ++i)
    1649           0 :     if (signe(gel(Rp, i)))
    1650           0 :       return gc_leaf(av, mkvecsmall(pcol[i]));
    1651             :   return NULL; /* LCOV_EXCL_LINE */
    1652             : }
    1653             : 
    1654             : GEN
    1655           0 : FpMs_FpCs_solve(GEN M, GEN A, long nbrow, GEN p)
    1656             : {
    1657           0 :   return ZpMs_ZpCs_solve(M, A, nbrow, p, 1);
    1658             : }
    1659             : 
    1660             : GEN
    1661           0 : FpMs_FpCs_solve_safe(GEN M, GEN A, long nbrow, GEN p)
    1662             : {
    1663             :   GEN res;
    1664           0 :   pari_CATCH(e_INV)
    1665             :   {
    1666           0 :     GEN E = pari_err_last();
    1667           0 :     GEN x = err_get_compo(E,2);
    1668           0 :     if (typ(x) != t_INTMOD) pari_err(0,E);
    1669           0 :     if (DEBUGLEVEL)
    1670           0 :       pari_warn(warner,"FpMs_FpCs_solve_safe, impossible inverse %Ps", x);
    1671           0 :     res = NULL;
    1672             :   } pari_TRY {
    1673           0 :     res = ZpMs_ZpCs_solve(M, A, nbrow, p, 1);
    1674           0 :   } pari_ENDCATCH
    1675           0 :   return res;
    1676             : }
    1677             : 
    1678             : static GEN
    1679         147 : FpMs_structelim_back(GEN M, GEN V, GEN prow, GEN p)
    1680             : {
    1681         147 :   long i, j, oldf = 0, f = 0;
    1682         147 :   long lrow = lg(prow), lM = lg(M);
    1683         147 :   GEN W = const_vecsmall(lM-1,1);
    1684         147 :   GEN R = cgetg(lrow, t_VEC);
    1685      228354 :   for (i=1; i<lrow; i++)
    1686      228207 :     gel(R,i) = prow[i]==0 ? NULL: gel(V,prow[i]);
    1687             :   do
    1688             :   {
    1689         442 :     oldf = f;
    1690      374995 :     for(i=1; i<lM; i++)
    1691      374553 :       if (W[i])
    1692             :       {
    1693      131729 :         GEN C = gel(M,i), F = gel(C,1), E = gel(C,2);
    1694      131729 :         long c=0, cj=0, lF = lg(F);
    1695     1093639 :         for(j=1; j<lF; j++)
    1696      961910 :           if (!gel(R,F[j])) { c++; cj=j; }
    1697      131729 :         if (c>=2) continue;
    1698      112311 :         if (c==1)
    1699             :         {
    1700       32899 :           pari_sp av = avma;
    1701       32899 :           GEN s = gen_0;
    1702      272954 :           for(j=1; j<lF; j++)
    1703      240055 :             if (j!=cj) s = Fp_add(s, mulis(gel(R,F[j]), E[j]), p);
    1704             :           /* s /= -E[cj] mod p */
    1705       32899 :           s = E[cj] < 0? Fp_divu(s, -E[cj], p): Fp_divu(Fp_neg(s,p), E[cj], p);
    1706       32899 :           gel(R,F[cj]) = gc_INT(av, s);
    1707       32899 :           f++;
    1708             :         }
    1709      112311 :         W[i]=0;
    1710             :       }
    1711         442 :   } while(oldf!=f);
    1712      228354 :   for (i=1; i<lrow; i++)
    1713      228207 :     if (!gel(R,i)) gel(R,i) = gen_0;
    1714         147 :   return R;
    1715             : }
    1716             : 
    1717             : /* Return a linear form Y such that YM is essentially 0 */
    1718             : GEN
    1719         147 : FpMs_leftkernel_elt_col(GEN M, long nbcol, long nbrow, GEN p)
    1720             : {
    1721         147 :   pari_sp av = avma, av2;
    1722             :   GEN Mp, pcol, prow;
    1723             :   long i, n;
    1724             :   pari_timer ti;
    1725             :   struct wrapper_modp_s W;
    1726         147 :   if (DEBUGLEVEL) timer_start(&ti);
    1727         147 :   RgMs_structelim_col(M, nbcol, nbrow, cgetg(1,t_VECSMALL), &pcol, &prow);
    1728         147 :   if (!pcol) return gc_NULL(av);
    1729         147 :   if (DEBUGLEVEL)
    1730           0 :     timer_printf(&ti,"structured elimination (%ld -> %ld)",nbcol,lg(pcol)-1);
    1731         147 :   n = lg(pcol)-1;
    1732         147 :   Mp = cgetg(n+1, t_MAT);
    1733       23183 :   for (i=1; i<=n; i++) gel(Mp, i) = vecprow(gel(M,pcol[i]), prow);
    1734         147 :   W.E = (void*)Mp;
    1735         147 :   W.p = p;
    1736         147 :   av2 = avma;
    1737           0 :   for(;; set_avma(av2))
    1738           0 :   {
    1739         147 :     GEN R, Rp, B = random_FpV(n, p), MB = FpV_FpMs_mul(B, Mp, p);
    1740         147 :     if (DEBUGLEVEL) timer_start(&ti);
    1741         147 :     pari_CATCH(e_INV)
    1742             :     {
    1743           0 :       GEN E = pari_err_last(), x = err_get_compo(E,2);
    1744           0 :       if (typ(x) != t_INTMOD) pari_err(0,E);
    1745           0 :       if (DEBUGLEVEL)
    1746           0 :         pari_warn(warner,"FpMs_leftkernel_elt, impossible inverse %Ps", x);
    1747           0 :       Rp = NULL;
    1748             :     } pari_TRY {
    1749         147 :       Rp = gen_FpM_Wiedemann((void*)&W, wrap_relker, MB, p);
    1750         147 :     } pari_ENDCATCH
    1751         147 :     if (!Rp) continue;
    1752         147 :     if (typ(Rp)==t_COL)
    1753             :     {
    1754         147 :       Rp = FpC_sub(Rp,B,p);
    1755         147 :       if (ZV_equal0(Rp)) continue;
    1756             :     }
    1757         147 :     R = FpMs_structelim_back(M, Rp, prow, p);
    1758         147 :     if (DEBUGLEVEL) timer_printf(&ti,"Wiedemann left kernel");
    1759         147 :     return gc_GEN(av, R);
    1760             :   }
    1761             : }
    1762             : 
    1763             : GEN
    1764          42 : FpMs_leftkernel_elt(GEN M, long nbrow, GEN p)
    1765             : {
    1766          42 :   return FpMs_leftkernel_elt_col(M, lg(M)-1, nbrow, p);
    1767             : }

Generated by: LCOV version 1.16