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 - Flv.c (source / functions) Coverage Total Hit
Test: PARI/GP v2.18.1 lcov report (development 31042-0fbe168e69) Lines: 97.2 % 758 737
Test Date: 2026-07-23 17:04:59 Functions: 93.5 % 62 58
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Copyright (C) 2000-2019  The PARI group.
       2              : 
       3              : This file is part of the PARI/GP package.
       4              : 
       5              : PARI/GP is free software; you can redistribute it and/or modify it under the
       6              : terms of the GNU General Public License as published by the Free Software
       7              : Foundation; either version 2 of the License, or (at your option) any later
       8              : version. It is distributed in the hope that it will be useful, but WITHOUT
       9              : ANY WARRANTY WHATSOEVER.
      10              : 
      11              : Check the License for details. You should have received a copy of it, along
      12              : with the package; see the file 'COPYING'. If not, write to the Free Software
      13              : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      14              : 
      15              : #include "pari.h"
      16              : #include "paripriv.h"
      17              : 
      18              : GEN
      19       388519 : Flv_to_ZV(GEN x)
      20      4100741 : { pari_APPLY_type(t_VEC, utoi(x[i])) }
      21              : 
      22              : GEN
      23     30255117 : Flc_to_ZC(GEN x)
      24    258285544 : { pari_APPLY_type(t_COL, utoi(x[i])) }
      25              : 
      26              : GEN
      27     11838888 : Flm_to_ZM(GEN x)
      28     41001133 : { pari_APPLY_type(t_MAT, Flc_to_ZC(gel(x,i))) }
      29              : 
      30              : GEN
      31           14 : Flc_to_ZC_inplace(GEN z)
      32              : {
      33           14 :   long i, l = lg(z);
      34          252 :   for (i=1; i<l; i++) gel(z,i) = utoi(z[i]);
      35           14 :   settyp(z, t_COL);
      36           14 :   return z;
      37              : }
      38              : 
      39              : GEN
      40            0 : Flm_to_ZM_inplace(GEN z)
      41              : {
      42            0 :   long i, l = lg(z);
      43            0 :   for (i=1; i<l; i++) Flc_to_ZC_inplace(gel(z, i));
      44            0 :   return z;
      45              : }
      46              : 
      47              : static GEN
      48      1835375 : Flm_solve_upper_1(GEN U, GEN B, ulong p, ulong pi)
      49      1835375 : { return Flm_Fl_mul_pre(B, Fl_inv(ucoeff(U, 1, 1), p), p, pi); }
      50              : 
      51              : static GEN
      52      2894430 : Flm_rsolve_upper_2(GEN U, GEN B, ulong p, ulong pi)
      53              : {
      54      2894430 :   ulong a = ucoeff(U, 1, 1), b = ucoeff(U, 1, 2), d = ucoeff(U, 2, 2);
      55      2894430 :   ulong D = Fl_mul_pre(a, d, p, pi), Dinv = Fl_inv(D, p);
      56      2894430 :   ulong ainv = Fl_mul_pre(d, Dinv, p, pi);
      57      2894430 :   ulong dinv = Fl_mul_pre(a, Dinv, p, pi);
      58      2894430 :   GEN B1 = rowslice(B, 1, 1);
      59      2894430 :   GEN B2 = rowslice(B, 2, 2);
      60      2894430 :   GEN X2 = Flm_Fl_mul_pre(B2, dinv, p, pi);
      61      2894430 :   GEN X1 = Flm_Fl_mul_pre(Flm_sub(B1, Flm_Fl_mul_pre(X2, b, p, pi), p),
      62              :                       ainv, p, pi);
      63      2894430 :   return vconcat(X1, X2);
      64              : }
      65              : 
      66              : /* solve U*X = B,  U upper triangular and invertible */
      67              : static GEN
      68      6923655 : Flm_rsolve_upper_pre(GEN U, GEN B, ulong p, ulong pi)
      69              : {
      70      6923655 :   long n = lg(U) - 1, n1;
      71              :   GEN U2, U11, U12, U22, B1, B2, X1, X2, X;
      72      6923655 :   pari_sp av = avma;
      73              : 
      74      6923655 :   if (n == 0) return B;
      75      6923648 :   if (n == 1) return Flm_solve_upper_1(U, B, p, pi);
      76      5806208 :   if (n == 2) return Flm_rsolve_upper_2(U, B, p, pi);
      77      2911778 :   n1 = (n + 1)/2;
      78      2911778 :   U2 = vecslice(U, n1 + 1, n);
      79      2911778 :   U22 = rowslice(U2, n1 + 1, n);
      80      2911778 :   B2 = rowslice(B, n1 + 1, n);
      81      2911778 :   X2 = Flm_rsolve_upper_pre(U22, B2, p, pi);
      82      2911778 :   U12 = rowslice(U2, 1, n1);
      83      2911778 :   B1 = rowslice(B, 1, n1);
      84      2911778 :   B1 = Flm_sub(B1, Flm_mul_pre(U12, X2, p, pi), p);
      85      2911778 :   if (gc_needed(av, 1)) (void)gc_all(av, 2, &B1, &X2);
      86      2911778 :   U11 = matslice(U, 1,n1, 1,n1);
      87      2911778 :   X1 = Flm_rsolve_upper_pre(U11, B1, p, pi);
      88      2911778 :   X = vconcat(X1, X2);
      89      2911778 :   if (gc_needed(av, 1)) X = gc_GEN(av, X);
      90      2911778 :   return X;
      91              : }
      92              : 
      93              : static GEN
      94      2678915 : Flm_lsolve_upper_2(GEN U, GEN B, ulong p, ulong pi)
      95              : {
      96      2678915 :   ulong a = ucoeff(U, 1, 1), b = ucoeff(U, 1, 2), d = ucoeff(U, 2, 2);
      97      2678915 :   ulong D = Fl_mul_pre(a, d, p, pi), Dinv = Fl_inv(D, p);
      98      2678915 :   ulong ainv = Fl_mul_pre(d, Dinv, p, pi);
      99      2678915 :   ulong dinv = Fl_mul_pre(a, Dinv, p, pi);
     100      2678915 :   GEN B1 = vecslice(B, 1, 1);
     101      2678915 :   GEN B2 = vecslice(B, 2, 2);
     102      2678915 :   GEN X1 = Flm_Fl_mul_pre(B1, ainv, p, pi);
     103      2678915 :   GEN X2 = Flm_Fl_mul_pre(Flm_sub(B2, Flm_Fl_mul_pre(X1, b, p, pi), p),
     104              :                       dinv, p, pi);
     105      2678915 :   return shallowconcat(X1, X2);
     106              : }
     107              : 
     108              : /* solve X*U = B,  U upper triangular and invertible */
     109              : static GEN
     110      5739210 : Flm_lsolve_upper_pre(GEN U, GEN B, ulong p, ulong pi)
     111              : {
     112      5739210 :   long n = lg(U) - 1, n1;
     113              :   GEN U2, U11, U12, U22, B1, B2, X1, X2, X;
     114      5739210 :   pari_sp av = avma;
     115              : 
     116      5739210 :   if (n == 0) return B;
     117      5739210 :   if (n == 1) return Flm_solve_upper_1(U, B, p, pi);
     118      5021275 :   if (n == 2) return Flm_lsolve_upper_2(U, B, p, pi);
     119      2342360 :   n1 = (n + 1)/2;
     120      2342360 :   U2 = vecslice(U, n1 + 1, n);
     121      2342360 :   U11 = matslice(U, 1,n1, 1,n1);
     122      2342360 :   U12 = rowslice(U2, 1, n1);
     123      2342360 :   U22 = rowslice(U2, n1 + 1, n);
     124      2342360 :   B1 = vecslice(B, 1, n1);
     125      2342360 :   B2 = vecslice(B, n1 + 1, n);
     126      2342360 :   X1 = Flm_lsolve_upper_pre(U11, B1, p, pi);
     127      2342360 :   B2 = Flm_sub(B2, Flm_mul_pre(X1, U12, p, pi), p);
     128      2342360 :   if (gc_needed(av, 1)) (void)gc_all(av, 3, &B2, &U22, &X1);
     129      2342360 :   X2 = Flm_lsolve_upper_pre(U22, B2, p, pi);
     130      2342360 :   X = shallowconcat(X1, X2);
     131      2342360 :   if (gc_needed(av, 1)) X = gc_GEN(av, X);
     132      2342360 :   return X;
     133              : }
     134              : 
     135              : static GEN
     136      4921884 : Flm_rsolve_lower_unit_2(GEN L, GEN A, ulong p, ulong pi)
     137              : {
     138      4921884 :   GEN X1 = rowslice(A, 1, 1);
     139      4921884 :   GEN X2 = Flm_sub(rowslice(A, 2, 2),
     140      4921884 :                    Flm_Fl_mul_pre(X1, ucoeff(L, 2, 1), p, pi), p);
     141      4921884 :   return vconcat(X1, X2);
     142              : }
     143              : 
     144              : /* solve L*X = A,  L lower triangular with ones on the diagonal
     145              : * (at least as many rows as columns) */
     146              : static GEN
     147     11270195 : Flm_rsolve_lower_unit_pre(GEN L, GEN A, ulong p, ulong pi)
     148              : {
     149     11270195 :   long m = lg(L) - 1, m1, n;
     150              :   GEN L1, L11, L21, L22, A1, A2, X1, X2, X;
     151     11270195 :   pari_sp av = avma;
     152              : 
     153     11270195 :   if (m == 0) return zero_Flm(0, lg(A) - 1);
     154     11270195 :   if (m == 1) return rowslice(A, 1, 1);
     155      9646068 :   if (m == 2) return Flm_rsolve_lower_unit_2(L, A, p, pi);
     156      4724184 :   m1 = (m + 1)/2;
     157      4724184 :   n = nbrows(L);
     158      4724184 :   L1 = vecslice(L, 1, m1);
     159      4724184 :   L11 = rowslice(L1, 1, m1);
     160      4724184 :   L21 = rowslice(L1, m1 + 1, n);
     161      4724184 :   A1 = rowslice(A, 1, m1);
     162      4724184 :   X1 = Flm_rsolve_lower_unit_pre(L11, A1, p, pi);
     163      4724184 :   A2 = rowslice(A, m1 + 1, n);
     164      4724184 :   A2 = Flm_sub(A2, Flm_mul_pre(L21, X1, p, pi), p);
     165      4724184 :   if (gc_needed(av, 1)) (void)gc_all(av, 2, &A2, &X1);
     166      4724184 :   L22 = matslice(L, m1+1,n, m1+1,m);
     167      4724184 :   X2 = Flm_rsolve_lower_unit_pre(L22, A2, p, pi);
     168      4724184 :   X = vconcat(X1, X2);
     169      4724184 :   if (gc_needed(av, 1)) X = gc_GEN(av, X);
     170      4724184 :   return X;
     171              : }
     172              : 
     173              : static GEN
     174      1958114 : Flm_lsolve_lower_unit_2(GEN L, GEN A, ulong p, ulong pi)
     175              : {
     176      1958114 :   GEN X2 = vecslice(A, 2, 2);
     177      1958114 :   GEN X1 = Flm_sub(vecslice(A, 1, 1),
     178      1958114 :                    Flm_Fl_mul_pre(X2, ucoeff(L, 2, 1), p, pi), p);
     179      1958114 :   return shallowconcat(X1, X2);
     180              : }
     181              : 
     182              : /* solve L*X = A,  L square lower triangular with ones on the diagonal */
     183              : static GEN
     184      4552316 : Flm_lsolve_lower_unit_pre(GEN L, GEN A, ulong p, ulong pi)
     185              : {
     186      4552316 :   long m = lg(L) - 1, m1;
     187              :   GEN L1, L2, L11, L21, L22, A1, A2, X1, X2, X;
     188      4552316 :   pari_sp av = avma;
     189              : 
     190      4552316 :   if (m <= 1) return A;
     191      4056424 :   if (m == 2) return Flm_lsolve_lower_unit_2(L, A, p, pi);
     192      2098310 :   m1 = (m + 1)/2;
     193      2098310 :   L2 = vecslice(L, m1 + 1, m);
     194      2098310 :   L22 = rowslice(L2, m1 + 1, m);
     195      2098310 :   A2 = vecslice(A, m1 + 1, m);
     196      2098310 :   X2 = Flm_lsolve_lower_unit_pre(L22, A2, p, pi);
     197      2098310 :   if (gc_needed(av, 1)) X2 = gc_GEN(av, X2);
     198      2098310 :   L1 = vecslice(L, 1, m1);
     199      2098310 :   L21 = rowslice(L1, m1 + 1, m);
     200      2098310 :   A1 = vecslice(A, 1, m1);
     201      2098310 :   A1 = Flm_sub(A1, Flm_mul_pre(X2, L21, p, pi), p);
     202      2098310 :   L11 = rowslice(L1, 1, m1);
     203      2098310 :   if (gc_needed(av, 1)) (void)gc_all(av, 3, &A1, &L11, &X2);
     204      2098310 :   X1 = Flm_lsolve_lower_unit_pre(L11, A1, p, pi);
     205      2098310 :   X = shallowconcat(X1, X2);
     206      2098310 :   if (gc_needed(av, 1)) X = gc_GEN(av, X);
     207      2098310 :   return X;
     208              : }
     209              : 
     210              : /* destroy A */
     211              : static long
     212      3660875 : Flm_CUP_basecase(GEN A, GEN *R, GEN *C, GEN *U, GEN *P, ulong p, ulong pi)
     213              : {
     214      3660875 :   long i, j, k, m = nbrows(A), n = lg(A) - 1, pr, pc;
     215              :   ulong u, v;
     216              : 
     217      3660875 :   if (P) *P = identity_perm(n);
     218      3660875 :   *R = cgetg(m + 1, t_VECSMALL);
     219     18287803 :   for (j = 1, pr = 0; j <= n; j++)
     220              :   {
     221     20981187 :     for (pr++, pc = 0; pr <= m; pr++)
     222              :     {
     223    143559439 :       for (k = j; k <= n; k++) { v = ucoeff(A, pr, k); if (!pc && v) pc = k; }
     224     19538504 :       if (pc) break;
     225              :     }
     226     16069611 :     if (!pc) break;
     227     14626928 :     (*R)[j] = pr;
     228     14626928 :     if (pc != j)
     229              :     {
     230      2404982 :       swap(gel(A, j), gel(A, pc));
     231      2404982 :       if (P) lswap((*P)[j], (*P)[pc]);
     232              :     }
     233     14626928 :     u = Fl_inv(ucoeff(A, pr, j), p);
     234     98638796 :     for (i = pr + 1; i <= m; i++)
     235              :     {
     236     84011868 :       v = Fl_mul_pre(ucoeff(A, i, j), u, p, pi);
     237     84011868 :       ucoeff(A, i, j) = v;
     238     84011868 :       v = Fl_neg(v, p);
     239    393088329 :       for (k = j + 1; k <= n; k++)
     240    309076461 :         ucoeff(A, i, k) = Fl_addmul_pre(ucoeff(A, i, k),
     241    309076461 :                                         ucoeff(A, pr, k), v, p, pi);
     242              :     }
     243              :   }
     244      3660875 :   setlg(*R, j);
     245      3660875 :   *C = vecslice(A, 1, j - 1);
     246      3660875 :   if (U) *U = rowpermute(A, *R);
     247      3660875 :   return j - 1;
     248              : }
     249              : 
     250              : static const long Flm_CUP_LIMIT = 8;
     251              : 
     252              : static long
     253      3578930 : Flm_CUP_pre(GEN A, GEN *R, GEN *C, GEN *U, GEN *P, ulong p, ulong pi)
     254              : {
     255      3578930 :   long m = nbrows(A), m1, n = lg(A) - 1, i, r1, r2, r;
     256              :   GEN R1, C1, U1, P1, R2, C2, U2, P2;
     257              :   GEN A1, A2, B2, C21, U11, U12, T21, T22;
     258      3578930 :   pari_sp av = avma;
     259              : 
     260      3578930 :   if (m < Flm_CUP_LIMIT || n < Flm_CUP_LIMIT)
     261              :     /* destroy A; not called at the outermost recursion level */
     262      2497575 :     return Flm_CUP_basecase(A, R, C, U, P, p, pi);
     263      1081355 :   m1 = (minss(m, n) + 1)/2;
     264      1081355 :   A1 = rowslice(A, 1, m1);
     265      1081355 :   A2 = rowslice(A, m1 + 1, m);
     266      1081355 :   r1 = Flm_CUP_pre(A1, &R1, &C1, &U1, &P1, p, pi);
     267      1081355 :   if (r1 == 0)
     268              :   {
     269        26865 :     r2 = Flm_CUP_pre(A2, &R2, &C2, &U2, &P2, p, pi);
     270        26865 :     *R = cgetg(r2 + 1, t_VECSMALL);
     271        37026 :     for (i = 1; i <= r2; i++) (*R)[i] = R2[i] + m1;
     272        26865 :     *C = vconcat(zero_Flm(m1, r2), C2);
     273        26865 :     *U = U2;
     274        26865 :     *P = P2;
     275        26865 :     r = r2;
     276              :   }
     277              :   else
     278              :   {
     279      1054490 :     U11 = vecslice(U1, 1, r1);
     280      1054490 :     U12 = vecslice(U1, r1 + 1, n);
     281      1054490 :     T21 = vecslicepermute(A2, P1, 1, r1);
     282      1054490 :     T22 = vecslicepermute(A2, P1, r1 + 1, n);
     283      1054490 :     C21 = Flm_lsolve_upper_pre(U11, T21, p, pi);
     284      1054490 :     if (gc_needed(av, 1))
     285            0 :       (void)gc_all(av, 7, &R1, &C1, &P1, &U11, &U12, &T22, &C21);
     286      1054490 :     B2 = Flm_sub(T22, Flm_mul_pre(C21, U12, p, pi), p);
     287      1054490 :     r2 = Flm_CUP_pre(B2, &R2, &C2, &U2, &P2, p, pi);
     288      1054490 :     r = r1 + r2;
     289      1054490 :     *R = cgetg(r + 1, t_VECSMALL);
     290      7130255 :     for (i = 1; i <= r1; i++) (*R)[i] = R1[i];
     291      6643707 :     for (;      i <= r; i++)  (*R)[i] = R2[i - r1] + m1;
     292      1054490 :     *C = shallowconcat(vconcat(C1, C21),
     293              :                        vconcat(zero_Flm(m1, r2), C2));
     294      1054490 :     *U = shallowconcat(vconcat(U11, zero_Flm(r2, r1)),
     295              :                        vconcat(vecpermute(U12, P2), U2));
     296      1054490 :     *P = cgetg(n + 1, t_VECSMALL);
     297      7130255 :     for (i = 1; i <= r1; i++) (*P)[i] = P1[i];
     298     13367192 :     for (; i <= n; i++)       (*P)[i] = P1[P2[i - r1] + r1];
     299              :   }
     300      1081355 :   if (gc_needed(av, 1)) (void)gc_all(av, 4, R, C, U, P);
     301      1081355 :   return r;
     302              : }
     303              : 
     304              : static long
     305      1163300 : Flm_echelon_gauss(GEN A, GEN *R, GEN *C, ulong p, ulong pi)
     306      1163300 : { return Flm_CUP_basecase(A, R, C, NULL, NULL, p, pi); }
     307              : 
     308              : /* complement of a strictly increasing subsequence of (1, 2, ..., n) */
     309              : static GEN
     310      1077697 : indexcompl(GEN v, long n)
     311              : {
     312      1077697 :   long i, j, k, m = lg(v) - 1;
     313      1077697 :   GEN w = cgetg(n - m + 1, t_VECSMALL);
     314     23311346 :   for (i = j = k = 1; i <= n; i++)
     315     22233649 :     if (j <= m && v[j] == i) j++; else w[k++] = i;
     316      1077697 :   return w;
     317              : }
     318              : 
     319              : /* column echelon form */
     320              : static long
     321      1969310 : Flm_echelon_pre(GEN A, GEN *R, GEN *C, ulong p, ulong pi)
     322              : {
     323      1969310 :   long j, j1, j2, m = nbrows(A), n = lg(A) - 1, n1, r, r1, r2;
     324              :   GEN A1, A2, R1, R1c, C1, R2, C2;
     325              :   GEN A12, A22, B2, C11, C21, M12;
     326      1969310 :   pari_sp av = avma;
     327              : 
     328      1969310 :   if (m < Flm_CUP_LIMIT || n < Flm_CUP_LIMIT)
     329      1163300 :     return Flm_echelon_gauss(Flm_copy(A), R, C, p, pi);
     330              : 
     331       806010 :   n1 = (n + 1)/2;
     332       806010 :   A1 = vecslice(A, 1, n1);
     333       806010 :   A2 = vecslice(A, n1 + 1, n);
     334       806010 :   r1 = Flm_echelon_pre(A1, &R1, &C1, p, pi);
     335       806010 :   if (!r1) return Flm_echelon_pre(A2, R, C, p, pi);
     336       729801 :   if (r1 == m) { *R = R1; *C = C1; return r1; }
     337              : 
     338       721728 :   R1c = indexcompl(R1, m);
     339       721728 :   C11 = rowpermute(C1, R1);
     340       721728 :   C21 = rowpermute(C1, R1c);
     341       721728 :   A12 = rowpermute(A2, R1);
     342       721728 :   A22 = rowpermute(A2, R1c);
     343       721728 :   M12 = Flm_rsolve_lower_unit_pre(C11, A12, p, pi);
     344       721728 :   B2 = Flm_sub(A22, Flm_mul_pre(C21, M12, p, pi), p);
     345       721728 :   r2 = Flm_echelon_pre(B2, &R2, &C2, p, pi);
     346       721728 :   if (!r2) { *R = R1; *C = C1; r = r1; }
     347              :   else
     348              :   {
     349       675033 :     R2 = perm_mul(R1c, R2);
     350       675033 :     C2 = rowpermute(vconcat(zero_Flm(r1, r2), C2),
     351              :                     perm_inv(vecsmall_concat(R1, R1c)));
     352       675033 :     r = r1 + r2;
     353       675033 :     *R = cgetg(r + 1, t_VECSMALL);
     354       675033 :     *C = cgetg(r + 1, t_MAT);
     355      8453850 :     for (j = j1 = j2 = 1; j <= r; j++)
     356      7778817 :       if (j2 > r2 || (j1 <= r1 && R1[j1] < R2[j2]))
     357              :       {
     358      4122149 :         gel(*C, j) = gel(C1, j1);
     359      4122149 :         (*R)[j] = R1[j1++];
     360              :       }
     361              :       else
     362              :       {
     363      3656668 :         gel(*C, j) = gel(C2, j2);
     364      3656668 :         (*R)[j] = R2[j2++];
     365              :       }
     366              :   }
     367       721728 :   if (gc_needed(av, 1)) (void)gc_all(av, 2, R, C);
     368       721728 :   return r;
     369              : }
     370              : 
     371              : static void /* assume m < p */
     372     12629417 : _Fl_addmul(GEN b, long k, long i, ulong m, ulong p, ulong pi)
     373              : {
     374     12629417 :   uel(b,k) = Fl_addmul_pre(uel(b, k), m, uel(b, i), p, pi);
     375     12629417 : }
     376              : static void /* same m = 1 */
     377       681053 : _Fl_add(GEN b, long k, long i, ulong p)
     378              : {
     379       681053 :   uel(b,k) = Fl_add(uel(b,k), uel(b,i), p);
     380       681053 : }
     381              : static void /* assume m < p && SMALL_ULONG(p) && (! (b[i] & b[k] & HIGHMASK)) */
     382      4455295 : _Fl_addmul_OK(GEN b, long k, long i, ulong m, ulong p)
     383              : {
     384      4455295 :   uel(b,k) += m * uel(b,i);
     385      4455295 :   if (uel(b,k) & HIGHMASK) uel(b,k) %= p;
     386      4455295 : }
     387              : static void /* assume SMALL_ULONG(p) && (! (b[i] & b[k] & HIGHMASK)) */
     388      2273054 : _Fl_add_OK(GEN b, long k, long i, ulong p)
     389              : {
     390      2273054 :   uel(b,k) += uel(b,i);
     391      2273054 :   if (uel(b,k) & HIGHMASK) uel(b,k) %= p;
     392      2273054 : }
     393              : 
     394              : /* assume 0 <= a[i,j] < p */
     395              : static GEN
     396       455571 : Fl_get_col_OK(GEN a, GEN b, long li, ulong p)
     397              : {
     398       455571 :   GEN u = cgetg(li+1,t_VECSMALL);
     399       455571 :   ulong m = uel(b,li) % p;
     400              :   long i,j;
     401              : 
     402       455571 :   uel(u,li) = (m * ucoeff(a,li,li)) % p;
     403      1762180 :   for (i = li-1; i > 0; i--)
     404              :   {
     405      1306609 :     m = p - uel(b,i)%p;
     406      4189939 :     for (j = i+1; j <= li; j++) {
     407      2883330 :       if (m & HIGHBIT) m %= p;
     408      2883330 :       m += ucoeff(a,i,j) * uel(u,j); /* 0 <= u[j] < p */
     409              :     }
     410      1306609 :     m %= p;
     411      1306609 :     if (m) m = ((p-m) * ucoeff(a,i,i)) % p;
     412      1306609 :     uel(u,i) = m;
     413              :   }
     414       455571 :   return u;
     415              : }
     416              : static GEN
     417      2432200 : Fl_get_col(GEN a, GEN b, long li, ulong p)
     418              : {
     419      2432200 :   GEN u = cgetg(li+1,t_VECSMALL);
     420      2432200 :   ulong m = uel(b,li) % p;
     421              :   long i,j;
     422              : 
     423      2432200 :   uel(u,li) = Fl_mul(m, ucoeff(a,li,li), p);
     424      6309243 :   for (i=li-1; i>0; i--)
     425              :   {
     426      3877043 :     m = b[i]%p;
     427      9807041 :     for (j = i+1; j <= li; j++)
     428      5929998 :       m = Fl_sub(m, Fl_mul(ucoeff(a,i,j), uel(u,j), p), p);
     429      3877043 :     if (m) m = Fl_mul(m, ucoeff(a,i,i), p);
     430      3877043 :     uel(u,i) = m;
     431              :   }
     432      2432200 :   return u;
     433              : }
     434              : 
     435              : static GEN
     436       698546 : Flm_ker_gauss_OK(GEN x, ulong p, long deplin)
     437              : {
     438              :   GEN y, c, d;
     439              :   long i, j, k, r, t, m, n;
     440              :   ulong a;
     441              : 
     442       698546 :   n = lg(x)-1;
     443       698546 :   m=nbrows(x); r=0;
     444              : 
     445       698546 :   c = zero_zv(m);
     446       698546 :   d = cgetg(n+1, t_VECSMALL);
     447       698546 :   a = 0; /* for gcc -Wall */
     448      3400763 :   for (k=1; k<=n; k++)
     449              :   {
     450      9680524 :     for (j=1; j<=m; j++)
     451      8456327 :       if (!c[j])
     452              :       {
     453      4544031 :         a = ucoeff(x,j,k) % p;
     454      4544031 :         if (a) break;
     455              :       }
     456      2756209 :     if (j > m)
     457              :     {
     458      1224197 :       if (deplin==1) {
     459        53992 :         c = cgetg(n+1, t_VECSMALL);
     460       176404 :         for (i=1; i<k; i++) c[i] = ucoeff(x,d[i],k) % p;
     461       105538 :         c[k] = 1; for (i=k+1; i<=n; i++) c[i] = 0;
     462        53992 :         return c;
     463              :       }
     464      1170205 :       r++; d[k] = 0;
     465              :     }
     466              :     else
     467              :     {
     468      1532012 :       ulong piv = p - Fl_inv(a, p); /* -1/a */
     469      1532012 :       c[j] = k; d[k] = j;
     470      1532012 :       ucoeff(x,j,k) = p-1;
     471      1532012 :       if (piv != 1)
     472      3191027 :         for (i=k+1; i<=n; i++) ucoeff(x,j,i) = (piv * ucoeff(x,j,i)) % p;
     473      7745961 :       for (t=1; t<=m; t++)
     474              :       {
     475      6213949 :         if (t == j) continue;
     476              : 
     477      4681937 :         piv = ( ucoeff(x,t,k) %= p );
     478      4681937 :         if (!piv) continue;
     479      2203302 :         if (piv == 1)
     480      2641594 :           for (i=k+1; i<=n; i++) _Fl_add_OK(gel(x,i),t,j, p);
     481              :         else
     482      4875138 :           for (i=k+1; i<=n; i++) _Fl_addmul_OK(gel(x,i),t,j,piv, p);
     483              :       }
     484              :     }
     485              :   }
     486       644554 :   if (deplin==1) return NULL;
     487              : 
     488       644547 :   y = cgetg(r+1, t_MAT);
     489      1814752 :   for (j=k=1; j<=r; j++,k++)
     490              :   {
     491      1170205 :     GEN C = cgetg(n+1, t_VECSMALL);
     492              : 
     493      2278882 :     gel(y,j) = C; while (d[k]) k++;
     494      9467245 :     for (i=1; i<k; i++)
     495      8297040 :       if (d[i])
     496      2391920 :         uel(C,i) = ucoeff(x,d[i],k) % p;
     497              :       else
     498      5905120 :         uel(C,i) = 0UL;
     499      7806065 :     uel(C,k) = 1UL; for (i=k+1; i<=n; i++) uel(C,i) = 0UL;
     500              :   }
     501       644547 :   if (deplin == 2) {
     502            0 :     GEN pc = cgetg(n - r + 1, t_VECSMALL);  /* indices of pivot columns */
     503            0 :     for (i = j = 1; j <= n; j++)
     504            0 :       if (d[j]) pc[i++] = j;
     505            0 :     return mkvec2(y, pc);
     506              :   }
     507       644547 :   return y;
     508              : }
     509              : 
     510              : /* in place, destroy x */
     511              : static GEN
     512       780451 : Flm_ker_gauss(GEN x, ulong p, long deplin)
     513              : {
     514              :   GEN y, c, d;
     515              :   long i, j, k, r, t, m, n;
     516              :   ulong a, pi;
     517       780451 :   n = lg(x)-1;
     518       780451 :   if (!n) return cgetg(1,t_MAT);
     519       780444 :   if (SMALL_ULONG(p)) return Flm_ker_gauss_OK(x, p, deplin);
     520        81898 :   pi = get_Fl_red(p);
     521              : 
     522        81898 :   m=nbrows(x); r=0;
     523              : 
     524        81898 :   c = zero_zv(m);
     525        81898 :   d = cgetg(n+1, t_VECSMALL);
     526        81898 :   a = 0; /* for gcc -Wall */
     527       278700 :   for (k=1; k<=n; k++)
     528              :   {
     529       572408 :     for (j=1; j<=m; j++)
     530       526917 :       if (!c[j])
     531              :       {
     532       387303 :         a = ucoeff(x,j,k);
     533       387303 :         if (a) break;
     534              :       }
     535       196809 :     if (j > m)
     536              :     {
     537        45491 :       if (deplin==1) {
     538            7 :         c = cgetg(n+1, t_VECSMALL);
     539           21 :         for (i=1; i<k; i++) c[i] = ucoeff(x,d[i],k);
     540            7 :         c[k] = 1; for (i=k+1; i<=n; i++) c[i] = 0;
     541            7 :         return c;
     542              :       }
     543        45484 :       r++; d[k] = 0;
     544              :     }
     545              :     else
     546              :     {
     547       151318 :       ulong piv = p - Fl_inv(a, p); /* -1/a */
     548       151318 :       c[j] = k; d[k] = j;
     549       151318 :       ucoeff(x,j,k) = p-1;
     550       151318 :       if (piv != 1)
     551       292616 :         for (i=k+1; i<=n; i++)
     552       148365 :           ucoeff(x,j,i) = Fl_mul_pre(piv, ucoeff(x,j,i), p, pi);
     553       759129 :       for (t=1; t<=m; t++)
     554              :       {
     555       607811 :         if (t == j) continue;
     556              : 
     557       456493 :         piv = ucoeff(x,t,k);
     558       456493 :         if (!piv) continue;
     559       254725 :         if (piv == 1)
     560        77811 :           for (i=k+1; i<=n; i++) _Fl_add(gel(x,i),t,j,p);
     561              :         else
     562       603127 :           for (i=k+1; i<=n; i++) _Fl_addmul(gel(x,i),t,j,piv,p, pi);
     563              :       }
     564              :     }
     565              :   }
     566        81891 :   if (deplin==1) return NULL;
     567              : 
     568        81884 :   y = cgetg(r+1, t_MAT);
     569       127368 :   for (j=k=1; j<=r; j++,k++)
     570              :   {
     571        45484 :     GEN C = cgetg(n+1, t_VECSMALL);
     572              : 
     573        90075 :     gel(y,j) = C; while (d[k]) k++;
     574       128460 :     for (i=1; i<k; i++)
     575        82976 :       if (d[i])
     576        60924 :         uel(C,i) = ucoeff(x,d[i],k);
     577              :       else
     578        22052 :         uel(C,i) = 0UL;
     579        83754 :     uel(C,k) = 1UL; for (i=k+1; i<=n; i++) uel(C,i) = 0UL;
     580              :   }
     581        81884 :   if (deplin == 2) {
     582        77025 :     GEN pc = cgetg(n - r + 1, t_VECSMALL);  /* indices of pivot columns */
     583       246614 :     for (i = j = 1; j <= n; j++)
     584       169589 :       if (d[j]) pc[i++] = j;
     585        77025 :     return mkvec2(y, pc);
     586              :   }
     587         4859 :   return y;
     588              : }
     589              : 
     590              : GEN
     591       272411 : Flm_intersect_i(GEN x, GEN y, ulong p)
     592              : {
     593       272411 :   long j, lx = lg(x);
     594              :   GEN z;
     595              : 
     596       272411 :   if (lx==1 || lg(y)==1) return cgetg(1,t_MAT);
     597       272397 :   z = Flm_ker(shallowconcat(x,y), p);
     598      1480478 :   for (j=lg(z)-1; j; j--) setlg(gel(z,j),lx);
     599       272397 :   return Flm_mul(x,z,p);
     600              : }
     601              : GEN
     602            0 : Flm_intersect(GEN x, GEN y, ulong p)
     603              : {
     604            0 :   pari_sp av = avma;
     605            0 :   return gc_upto(av, Flm_image(Flm_intersect_i(x, y, p), p));
     606              : }
     607              : 
     608              : static GEN
     609       324889 : Flm_ker_echelon(GEN x, ulong p, long pivots) {
     610       324889 :   pari_sp av = avma;
     611              :   GEN R, Rc, C, C1, C2, S, K;
     612       324889 :   long n = lg(x) - 1, r;
     613       324889 :   ulong pi = get_Fl_red(p);
     614       324889 :   r = Flm_echelon_pre(Flm_transpose(x), &R, &C, p, pi);
     615       324889 :   Rc = indexcompl(R, n);
     616       324889 :   C1 = rowpermute(C, R);
     617       324889 :   C2 = rowpermute(C, Rc);
     618       324889 :   S = Flm_lsolve_lower_unit_pre(C1, C2, p, pi);
     619       324889 :   K = vecpermute(shallowconcat(Flm_neg(S, p), matid_Flm(n - r)),
     620              :                  perm_inv(vecsmall_concat(R, Rc)));
     621       324889 :   K = Flm_transpose(K);
     622       324889 :   if (pivots)
     623        33954 :     return gc_GEN(av, mkvec2(K, R));
     624       290935 :   return gc_upto(av, K);
     625              : }
     626              : 
     627              : static GEN
     628        30800 : Flm_deplin_echelon(GEN x, ulong p) {
     629        30800 :   pari_sp av = avma;
     630              :   GEN R, Rc, C, C1, C2, s, v;
     631        30800 :   long i, n = lg(x) - 1, r;
     632        30800 :   ulong pi = get_Fl_red(p);
     633        30800 :   r = Flm_echelon_pre(Flm_transpose(x), &R, &C, p, pi);
     634        30800 :   if (r == n) return gc_NULL(av);
     635        30793 :   Rc = indexcompl(R, n);
     636        30793 :   i = Rc[1];
     637        30793 :   C1 = rowpermute(C, R);
     638        30793 :   C2 = rowslice(C, i, i);
     639        30793 :   s = Flm_row(Flm_lsolve_lower_unit_pre(C1, C2, p, pi), 1);
     640        30793 :   v = vecsmallpermute(vecsmall_concat(Flv_neg(s, p), vecsmall_ei(n - r, 1)),
     641              :                  perm_inv(vecsmall_concat(R, Rc)));
     642        30793 :   return gc_leaf(av, v);
     643              : }
     644              : 
     645              : static GEN
     646      1136140 : Flm_ker_i(GEN x, ulong p, long deplin, long inplace) {
     647      1136140 :   if (lg(x) - 1 >= Flm_CUP_LIMIT && nbrows(x) >= Flm_CUP_LIMIT)
     648       355689 :     switch(deplin) {
     649       290935 :     case 0: return Flm_ker_echelon(x, p, 0);
     650        30800 :     case 1: return Flm_deplin_echelon(x, p);
     651        33954 :     case 2: return Flm_ker_echelon(x, p, 1);
     652              :     }
     653       780451 :   return Flm_ker_gauss(inplace? x: Flm_copy(x), p, deplin);
     654              : }
     655              : 
     656              : GEN
     657       555781 : Flm_ker_sp(GEN x, ulong p, long deplin) { return Flm_ker_i(x, p, deplin, 1); }
     658              : GEN
     659       580359 : Flm_ker(GEN x, ulong p) { return Flm_ker_i(x, p, 0, 0); }
     660              : GEN
     661            0 : Flm_deplin(GEN x, ulong p) { return Flm_ker_i(x, p, 1, 0); }
     662              : 
     663              : /* in place, destroy a, SMALL_ULONG(p) is TRUE */
     664              : static ulong
     665         2317 : Flm_det_gauss_OK(GEN a, long nbco, ulong p)
     666              : {
     667         2317 :   long i,j,k, s = 1;
     668         2317 :   ulong q, x = 1;
     669              : 
     670         9562 :   for (i=1; i<nbco; i++)
     671              :   {
     672         8904 :     for(k=i; k<=nbco; k++)
     673              :     {
     674         8715 :       ulong c = ucoeff(a,k,i) % p;
     675         8715 :       ucoeff(a,k,i) = c;
     676         8715 :       if (c) break;
     677              :     }
     678        23289 :     for(j=k+1; j<=nbco; j++) ucoeff(a,j,i) %= p;
     679         7434 :     if (k > nbco) return ucoeff(a,i,i);
     680         7245 :     if (k != i)
     681              :     { /* exchange the lines s.t. k = i */
     682         3192 :       for (j=i; j<=nbco; j++) lswap(ucoeff(a,i,j), ucoeff(a,k,j));
     683          791 :       s = -s;
     684              :     }
     685         7245 :     q = ucoeff(a,i,i);
     686              : 
     687         7245 :     if (x & HIGHMASK) x %= p;
     688         7245 :     x *= q;
     689         7245 :     q = Fl_inv(q,p);
     690        24185 :     for (k=i+1; k<=nbco; k++)
     691              :     {
     692        16940 :       ulong m = ucoeff(a,i,k) % p;
     693        16940 :       if (!m) continue;
     694              : 
     695         9898 :       m = p - ((m*q)%p);
     696        39165 :       for (j=i+1; j<=nbco; j++)
     697              :       {
     698        29267 :         ulong c = ucoeff(a,j,k);
     699        29267 :         if (c & HIGHMASK) c %= p;
     700        29267 :         ucoeff(a,j,k) = c  + m*ucoeff(a,j,i);
     701              :       }
     702              :     }
     703              :   }
     704         2128 :   if (x & HIGHMASK) x %= p;
     705         2128 :   q = ucoeff(a,nbco,nbco);
     706         2128 :   if (q & HIGHMASK) q %= p;
     707         2128 :   x = (x*q) % p;
     708         2128 :   if (s < 0 && x) x = p - x;
     709         2128 :   return x;
     710              : }
     711              : 
     712              : /* in place, destroy a */
     713              : static ulong
     714        53463 : Flm_det_gauss(GEN a, ulong p)
     715              : {
     716        53463 :   long i,j,k, s = 1, nbco = lg(a)-1;
     717        53463 :   ulong pi, q, x = 1;
     718              : 
     719        53463 :   if (SMALL_ULONG(p)) return Flm_det_gauss_OK(a, nbco, p);
     720        51146 :   pi = get_Fl_red(p);
     721       326155 :   for (i=1; i<nbco; i++)
     722              :   {
     723       275412 :     for(k=i; k<=nbco; k++)
     724       275412 :       if (ucoeff(a,k,i)) break;
     725       275009 :     if (k > nbco) return ucoeff(a,i,i);
     726       275009 :     if (k != i)
     727              :     { /* exchange the lines s.t. k = i */
     728         1090 :       for (j=i; j<=nbco; j++) lswap(ucoeff(a,i,j), ucoeff(a,k,j));
     729          212 :       s = -s;
     730              :     }
     731       275009 :     q = ucoeff(a,i,i);
     732              : 
     733       275009 :     x = Fl_mul_pre(x, q, p, pi);
     734       275009 :     q = Fl_inv(q,p);
     735      1178157 :     for (k=i+1; k<=nbco; k++)
     736              :     {
     737       903148 :       ulong m = ucoeff(a,i,k);
     738       903148 :       if (!m) continue;
     739              : 
     740       842739 :       m = Fl_mul_pre(m, q, p, pi);
     741      4331274 :       for (j=i+1; j<=nbco; j++)
     742      3488535 :         ucoeff(a,j,k) = Fl_sub(ucoeff(a,j,k), Fl_mul_pre(m,ucoeff(a,j,i), p, pi), p);
     743              :     }
     744              :   }
     745        51146 :   if (s < 0) x = Fl_neg(x, p);
     746        51146 :   return Fl_mul(x, ucoeff(a,nbco,nbco), p);
     747              : }
     748              : 
     749              : static ulong
     750        37414 : Flm_det_CUP(GEN a, ulong p) {
     751              :   GEN R, C, U, P;
     752        37414 :   long i, n = lg(a) - 1, r;
     753              :   ulong d;
     754        37414 :   ulong pi = get_Fl_red(p);
     755        37414 :   r = Flm_CUP_pre(a, &R, &C, &U, &P, p, pi);
     756        37414 :   if (r < n)
     757           42 :     d = 0;
     758              :   else {
     759        37372 :     d = perm_sign(P) == 1? 1: p-1;
     760       430084 :     for (i = 1; i <= n; i++)
     761       392712 :       d = Fl_mul_pre(d, ucoeff(U, i, i), p, pi);
     762              :   }
     763        37414 :   return d;
     764              : }
     765              : 
     766              : static ulong
     767        90877 : Flm_det_i(GEN x, ulong p, long inplace) {
     768        90877 :   pari_sp av = avma;
     769              :   ulong d;
     770        90877 :   if (lg(x) - 1 >= Flm_CUP_LIMIT)
     771        37414 :     d = Flm_det_CUP(x, p);
     772              :   else
     773        53463 :     d = Flm_det_gauss(inplace? x: Flm_copy(x), p);
     774        90877 :   return gc_ulong(av, d);
     775              : }
     776              : 
     777              : ulong
     778        90877 : Flm_det_sp(GEN x, ulong p) { return Flm_det_i(x, p, 1); }
     779              : ulong
     780            0 : Flm_det(GEN x, ulong p) { return Flm_det_i(x, p, 0); }
     781              : 
     782              : /* Destroy x */
     783              : static GEN
     784      4167354 : Flm_gauss_pivot(GEN x, ulong p, long *rr)
     785              : {
     786              :   GEN c,d;
     787              :   long i,j,k,r,t,n,m;
     788              : 
     789      4167354 :   n=lg(x)-1; if (!n) { *rr=0; return NULL; }
     790              : 
     791      4166045 :   m=nbrows(x); r=0;
     792      4166045 :   d=cgetg(n+1,t_VECSMALL);
     793      4166045 :   c = zero_zv(m);
     794     18417371 :   for (k=1; k<=n; k++)
     795              :   {
     796     36156667 :     for (j=1; j<=m; j++)
     797     34340318 :       if (!c[j])
     798              :       {
     799     18102025 :         ucoeff(x,j,k) %= p;
     800     18102025 :         if (ucoeff(x,j,k)) break;
     801              :       }
     802     14251326 :     if (j>m) { r++; d[k]=0; }
     803              :     else
     804              :     {
     805     12434977 :       ulong piv = p - Fl_inv(ucoeff(x,j,k), p);
     806     12434977 :       c[j]=k; d[k]=j;
     807     29234216 :       for (i=k+1; i<=n; i++)
     808     16799239 :         ucoeff(x,j,i) = Fl_mul(piv, ucoeff(x,j,i), p);
     809     61579876 :       for (t=1; t<=m; t++)
     810     49144899 :         if (!c[t]) /* no pivot on that line yet */
     811              :         {
     812     21863152 :           piv = ucoeff(x,t,k);
     813     21863152 :           if (piv)
     814              :           {
     815     13604329 :             ucoeff(x,t,k) = 0;
     816     41983044 :             for (i=k+1; i<=n; i++)
     817     28378715 :               ucoeff(x,t,i) = Fl_add(ucoeff(x,t,i),
     818     28378715 :                                      Fl_mul(piv,ucoeff(x,j,i),p),p);
     819              :           }
     820              :         }
     821     41669193 :       for (i=k; i<=n; i++) ucoeff(x,j,i) = 0; /* dummy */
     822              :     }
     823              :   }
     824      4166045 :   *rr = r; return gc_const((pari_sp)d, d);
     825              : }
     826              : 
     827              : static GEN
     828       278679 : Flm_pivots_CUP(GEN x, ulong p, long *rr)
     829              : {
     830       278679 :   long i, n = lg(x) - 1, r;
     831       278679 :   GEN R, C, U, P, d = zero_zv(n);
     832       278679 :   ulong pi = get_Fl_red(p);
     833       278679 :   r = Flm_CUP_pre(x, &R, &C, &U, &P, p, pi);
     834      3075104 :   for(i = 1; i <= r; i++)
     835      2796425 :     d[P[i]] = R[i];
     836       278679 :   *rr = n - r; return gc_const((pari_sp)d, d);
     837              : }
     838              : 
     839              : GEN
     840      4446033 : Flm_pivots(GEN x, ulong p, long *rr, long inplace)
     841              : {
     842      4446033 :   if (lg(x) - 1 >= Flm_CUP_LIMIT && nbrows(x) >= Flm_CUP_LIMIT)
     843       278679 :     return Flm_pivots_CUP(x, p, rr);
     844      4167354 :   return Flm_gauss_pivot(inplace? x: Flm_copy(x), p, rr);
     845              : }
     846              : 
     847              : long
     848        39788 : Flm_rank(GEN x, ulong p)
     849              : {
     850        39788 :   pari_sp av = avma;
     851              :   long r;
     852        39788 :   if (lg(x) - 1 >= Flm_CUP_LIMIT && nbrows(x) >= Flm_CUP_LIMIT) {
     853              :     GEN R, C;
     854         9674 :     ulong pi = get_Fl_red(p);
     855         9674 :     return gc_long(av, Flm_echelon_pre(x, &R, &C, p, pi));
     856              :   }
     857        30114 :   (void) Flm_pivots(x, p, &r, 0);
     858        30114 :   return gc_long(av, lg(x)-1 - r);
     859              : }
     860              : 
     861              : /* assume dim A >= 1, A invertible + upper triangular, 1s on diagonal,
     862              :  * reduced mod p */
     863              : static GEN
     864         1274 : Flm_inv_upper_1_ind(GEN A, long index, ulong p)
     865              : {
     866         1274 :   long n = lg(A)-1, i = index, j;
     867         1274 :   GEN u = const_vecsmall(n, 0);
     868         1274 :   u[i] = 1;
     869         1274 :   if (SMALL_ULONG(p))
     870         3269 :     for (i--; i>0; i--)
     871              :     {
     872         2009 :       ulong m = ucoeff(A,i,i+1) * uel(u,i+1); /* j = i+1 */
     873         7035 :       for (j=i+2; j<=n; j++)
     874              :       {
     875         5026 :         if (m & HIGHMASK) m %= p;
     876         5026 :         m += ucoeff(A,i,j) * uel(u,j);
     877              :       }
     878         2009 :       u[i] = Fl_neg(m % p, p);
     879              :     }
     880              :   else
     881           21 :     for (i--; i>0; i--)
     882              :     {
     883            7 :       ulong m = Fl_mul(ucoeff(A,i,i+1),uel(u,i+1), p); /* j = i+1 */
     884            7 :       for (j=i+2; j<=n; j++) m = Fl_add(m, Fl_mul(ucoeff(A,i,j),uel(u,j),p), p);
     885            7 :       u[i] = Fl_neg(m, p);
     886              :     }
     887         1274 :   return u;
     888              : }
     889              : static GEN
     890          490 : Flm_inv_upper_1(GEN A, ulong p)
     891              : {
     892              :   long i, l;
     893          490 :   GEN B = cgetg_copy(A, &l);
     894         1764 :   for (i = 1; i < l; i++) gel(B,i) = Flm_inv_upper_1_ind(A, i, p);
     895          490 :   return B;
     896              : }
     897              : /* destroy a, b */
     898              : static GEN
     899       122513 : Flm_gauss_sp_OK(GEN a, GEN b, ulong *detp, ulong p)
     900              : {
     901       122513 :   long i, j, k, li, bco, aco = lg(a)-1, s = 1;
     902       122513 :   ulong det = 1;
     903              :   GEN u;
     904              : 
     905       122513 :   li = nbrows(a);
     906       122513 :   bco = lg(b)-1;
     907       431849 :   for (i=1; i<=aco; i++)
     908              :   {
     909              :     ulong invpiv;
     910              :     /* Fl_get_col wants 0 <= a[i,j] < p for all i,j */
     911      1066280 :     for (k = 1; k < i; k++) ucoeff(a,k,i) %= p;
     912       489724 :     for (k = i; k <= li; k++)
     913              :     {
     914       489717 :       ulong piv = ( ucoeff(a,k,i) %= p );
     915       489717 :       if (piv)
     916              :       {
     917       431842 :         ucoeff(a,k,i) = Fl_inv(piv, p);
     918       431842 :         if (detp)
     919              :         {
     920            0 :           if (det & HIGHMASK) det %= p;
     921            0 :           det *= piv;
     922              :         }
     923       431842 :         break;
     924              :       }
     925              :     }
     926              :     /* found a pivot on line k */
     927       431849 :     if (k > li) return NULL;
     928       431842 :     if (k != i)
     929              :     { /* swap lines so that k = i */
     930        38969 :       s = -s;
     931       162017 :       for (j=i; j<=aco; j++) swap(gcoeff(a,i,j), gcoeff(a,k,j));
     932       211346 :       for (j=1; j<=bco; j++) swap(gcoeff(b,i,j), gcoeff(b,k,j));
     933              :     }
     934       431842 :     if (i == aco) break;
     935              : 
     936       309336 :     invpiv = p - ucoeff(a,i,i); /* -1/piv mod p */
     937       981570 :     for (k=i+1; k<=li; k++)
     938              :     {
     939       672234 :       ulong m = ( ucoeff(a,k,i) %= p );
     940       672234 :       if (!m) continue;
     941              : 
     942       192564 :       m = Fl_mul(m, invpiv, p);
     943       192564 :       if (m == 1) {
     944       150892 :         for (j=i+1; j<=aco; j++) _Fl_add_OK(gel(a,j),k,i, p);
     945       239566 :         for (j=1;   j<=bco; j++) _Fl_add_OK(gel(b,j),k,i, p);
     946              :       } else {
     947       531932 :         for (j=i+1; j<=aco; j++) _Fl_addmul_OK(gel(a,j),k,i,m, p);
     948       877657 :         for (j=1;   j<=bco; j++) _Fl_addmul_OK(gel(b,j),k,i,m, p);
     949              :       }
     950              :     }
     951              :   }
     952       122506 :   if (detp)
     953              :   {
     954            0 :     det %=  p;
     955            0 :     if (s < 0 && det) det = p - det;
     956            0 :     *detp = det;
     957              :   }
     958       122506 :   u = cgetg(bco+1,t_MAT);
     959       578077 :   for (j=1; j<=bco; j++) gel(u,j) = Fl_get_col_OK(a,gel(b,j), aco,p);
     960       122506 :   return u;
     961              : }
     962              : 
     963              : /* destroy a, b */
     964              : static GEN
     965      2429900 : Flm_gauss_sp_i(GEN a, GEN b, ulong *detp, ulong p)
     966              : {
     967      2429900 :   long i, j, k, li, bco, aco = lg(a)-1, s = 1;
     968      2429900 :   ulong det = 1;
     969              :   GEN u;
     970              :   ulong pi;
     971      2429900 :   if (!aco) { if (detp) *detp = 1; return cgetg(1,t_MAT); }
     972      2429900 :   if (SMALL_ULONG(p)) return Flm_gauss_sp_OK(a, b, detp, p);
     973      2307387 :   pi = get_Fl_red(p);
     974      2307387 :   li = nbrows(a);
     975      2307387 :   bco = lg(b)-1;
     976      5890599 :   for (i=1; i<=aco; i++)
     977              :   {
     978              :     ulong invpiv;
     979              :     /* Fl_get_col wants 0 <= a[i,j] < p for all i,j */
     980      6124268 :     for (k = i; k <= li; k++)
     981              :     {
     982      6124268 :       ulong piv = ucoeff(a,k,i);
     983      6124268 :       if (piv)
     984              :       {
     985      5890599 :         ucoeff(a,k,i) = Fl_inv(piv, p);
     986      5890599 :         if (detp) det = Fl_mul_pre(det, piv, p, pi);
     987      5890599 :         break;
     988              :       }
     989              :     }
     990              :     /* found a pivot on line k */
     991      5890599 :     if (k > li) return NULL;
     992      5890599 :     if (k != i)
     993              :     { /* swap lines so that k = i */
     994       177190 :       s = -s;
     995       663626 :       for (j=i; j<=aco; j++) swap(gcoeff(a,i,j), gcoeff(a,k,j));
     996       360110 :       for (j=1; j<=bco; j++) swap(gcoeff(b,i,j), gcoeff(b,k,j));
     997              :     }
     998      5890599 :     if (i == aco) break;
     999              : 
    1000      3583212 :     invpiv = p - ucoeff(a,i,i); /* -1/piv mod p */
    1001      8936874 :     for (k=i+1; k<=li; k++)
    1002              :     {
    1003      5353662 :       ulong m = ucoeff(a,k,i);
    1004      5353662 :       if (!m) continue;
    1005              : 
    1006      4483564 :       m = Fl_mul_pre(m, invpiv, p, pi);
    1007      4483564 :       if (m == 1) {
    1008       637090 :         for (j=i+1; j<=aco; j++) _Fl_add(gel(a,j),k,i, p);
    1009       440373 :         for (j=1;   j<=bco; j++) _Fl_add(gel(b,j),k,i, p);
    1010              :       } else {
    1011     12190192 :         for (j=i+1; j<=aco; j++) _Fl_addmul(gel(a,j),k,i,m, p, pi);
    1012      8583730 :         for (j=1;   j<=bco; j++) _Fl_addmul(gel(b,j),k,i,m, p, pi);
    1013              :       }
    1014              :     }
    1015              :   }
    1016      2307387 :   if (detp)
    1017              :   {
    1018            0 :     if (s < 0 && det) det = p - det;
    1019            0 :     *detp = det;
    1020              :   }
    1021      2307387 :   u = cgetg(bco+1,t_MAT);
    1022      4739587 :   for (j=1; j<=bco; j++) gel(u,j) = Fl_get_col(a,gel(b,j), aco,p);
    1023      2307387 :   return u;
    1024              : }
    1025              : 
    1026              : static GEN
    1027      1099812 : Flm_gauss_from_CUP(GEN b, GEN R, GEN C, GEN U, GEN P, ulong p, ulong pi, ulong *detp)
    1028              : {
    1029      1099812 :   GEN Y = Flm_rsolve_lower_unit_pre(rowpermute(C, R), rowpermute(b, R), p, pi);
    1030      1099812 :   GEN X = rowpermute(Flm_rsolve_upper_pre(U, Y, p, pi), perm_inv(P));
    1031      1099812 :   if (detp)
    1032              :   {
    1033       930523 :     ulong d = perm_sign(P) == 1? 1: p-1;
    1034       930523 :     long i, r = lg(R);
    1035      5887444 :     for (i = 1; i < r; i++)
    1036      4956921 :       d = Fl_mul_pre(d, ucoeff(U, i, i), p, pi);
    1037       930523 :     *detp = d;
    1038              :   }
    1039      1099812 :   return X;
    1040              : }
    1041              : 
    1042              : static GEN
    1043       169303 : Flm_gauss_CUP(GEN a, GEN b, ulong *detp, ulong p) {
    1044              :   GEN R, C, U, P;
    1045       169303 :   long n = lg(a) - 1, r;
    1046       169303 :   ulong pi = get_Fl_red(p);
    1047       169303 :   if (nbrows(a) < n || (r = Flm_CUP_pre(a, &R, &C, &U, &P, p, pi)) < n)
    1048           14 :     return NULL;
    1049       169289 :   return Flm_gauss_from_CUP(b, R, C, U, P, p, pi, detp);
    1050              : }
    1051              : 
    1052              : GEN
    1053      2478326 : Flm_gauss_sp(GEN a, GEN b, ulong *detp, ulong p) {
    1054      2478326 :   pari_sp av = avma;
    1055              :   GEN x;
    1056      2478326 :   if (lg(a) - 1 >= Flm_CUP_LIMIT)
    1057        48426 :     x = Flm_gauss_CUP(a, b, detp, p);
    1058              :   else
    1059      2429900 :     x = Flm_gauss_sp_i(a, b, detp, p);
    1060      2478326 :   if (!x) return gc_NULL(av);
    1061      2478319 :   return gc_upto(av, x);
    1062              : }
    1063              : 
    1064              : GEN
    1065      2412217 : Flm_gauss(GEN a, GEN b, ulong p) {
    1066      2412217 :   pari_sp av = avma;
    1067              :   GEN x;
    1068      2412217 :   if (lg(a) - 1 >= Flm_CUP_LIMIT)
    1069       104839 :     x = Flm_gauss_CUP(a, b, NULL, p);
    1070              :   else {
    1071      2307378 :     a = RgM_shallowcopy(a);
    1072      2307378 :     b = RgM_shallowcopy(b);
    1073      2307378 :     x = Flm_gauss_sp(a, b, NULL, p);
    1074              :   }
    1075      2412217 :   if (!x) return gc_NULL(av);
    1076      2412203 :   return gc_upto(av, x);
    1077              : }
    1078              : 
    1079              : static GEN
    1080        65546 : Flm_inv_i(GEN a, ulong *detp, ulong p, long inplace) {
    1081        65546 :   pari_sp av = avma;
    1082        65546 :   long n = lg(a) - 1;
    1083              :   GEN b, x;
    1084        65546 :   if (n == 0) return cgetg(1, t_MAT);
    1085        65546 :   b = matid_Flm(nbrows(a));
    1086        65546 :   if (n >= Flm_CUP_LIMIT)
    1087        16038 :     x = Flm_gauss_CUP(a, b, detp, p);
    1088              :   else {
    1089        49508 :     if (!inplace)
    1090        47912 :       a = RgM_shallowcopy(a);
    1091        49508 :     x = Flm_gauss_sp(a, b, detp, p);
    1092              :   }
    1093        65546 :   if (!x) return gc_NULL(av);
    1094        65539 :   return gc_upto(av, x);
    1095              : }
    1096              : 
    1097              : GEN
    1098         1827 : Flm_inv_sp(GEN a, ulong *detp, ulong p) {
    1099         1827 :   return Flm_inv_i(a, detp, p, 1);
    1100              : }
    1101              : 
    1102              : GEN
    1103        63719 : Flm_inv(GEN a, ulong p) {
    1104        63719 :   return Flm_inv_i(a, NULL, p, 0);
    1105              : }
    1106              : 
    1107              : GEN
    1108           21 : Flm_Flc_gauss(GEN a, GEN b, ulong p) {
    1109           21 :   pari_sp av = avma;
    1110           21 :   GEN z = Flm_gauss(a, mkmat(b), p);
    1111           21 :   if (!z) return gc_NULL(av);
    1112           14 :   if (lg(z) == 1) retgc_const(av, cgetg(1, t_VECSMALL));
    1113           14 :   return gc_leaf(av, gel(z,1));
    1114              : }
    1115              : 
    1116              : GEN
    1117       930537 : Flm_adjoint(GEN A, ulong p)
    1118              : {
    1119       930537 :   pari_sp av = avma;
    1120              :   GEN R, C, U, P, C1, U1, v, c, d;
    1121       930537 :   long r, i, q, n = lg(A)-1, m;
    1122              :   ulong D;
    1123       930537 :   ulong pi = get_Fl_red(p);
    1124       930537 :   if (n == 0) return cgetg(1, t_MAT);
    1125       930537 :   r = Flm_CUP_pre(A, &R, &C, &U, &P, p, pi);
    1126       930537 :   m = nbrows(A);
    1127       930537 :   if (r == n)
    1128              :   {
    1129       930523 :     GEN X = Flm_gauss_from_CUP(matid_Flm(m), R, C, U, P, p, pi, &D);
    1130       930523 :     return gc_upto(av, Flm_Fl_mul_pre(X, D, p, pi));
    1131              :   }
    1132           14 :   if (r < n-1) return zero_Flm(n, m);
    1133           28 :   for (q = n, i = 1; i < n; i++)
    1134           14 :     if (R[i] != i) { q = i; break; }
    1135           14 :   C1 = matslice(C, 1, q-1, 1, q-1);
    1136           14 :   c = vecslice(Flm_row(C, q), 1, q-1);
    1137           14 :   c = Flm_lsolve_lower_unit_pre(C1, Flm_transpose(mkmat(c)), p, pi);
    1138           14 :   d = cgetg(m+1, t_VECSMALL);
    1139           28 :   for (i=1; i<q; i++)    uel(d,i) = ucoeff(c,1,i);
    1140           14 :   uel(d,q) = p-1;
    1141           21 :   for (i=q+1; i<=m; i++) uel(d,i) = 0;
    1142           14 :   U1 = vecslice(U, 1, n-1);
    1143           14 :   v = gel(Flm_rsolve_upper_pre(U1, mkmat(gel(U,n)), p, pi),1);
    1144           14 :   v = vecsmall_append(v, p-1);
    1145           14 :   D = perm_sign(P) != (odd(q+n)?-1:1) ? p-1 : 1;
    1146           28 :   for (i = 1; i <= n-1; i++)
    1147           14 :     D = Fl_mul_pre(D, ucoeff(U1, i, i), p, pi);
    1148           14 :   d = Flv_Fl_mul(d, D, p);
    1149           14 :   return rowpermute(Flc_Flv_mul(v, d, p),perm_inv(P));
    1150              : }
    1151              : 
    1152              : static GEN
    1153          287 : Flm_invimage_CUP(GEN A, GEN B, ulong p) {
    1154          287 :   pari_sp av = avma;
    1155              :   GEN R, Rc, C, U, P, B1, B2, C1, C2, X, Y, Z;
    1156              :   long r;
    1157          287 :   ulong pi = get_Fl_red(p);
    1158          287 :   r = Flm_CUP_pre(A, &R, &C, &U, &P, p, pi);
    1159          287 :   Rc = indexcompl(R, nbrows(B));
    1160          287 :   C1 = rowpermute(C, R);
    1161          287 :   C2 = rowpermute(C, Rc);
    1162          287 :   B1 = rowpermute(B, R);
    1163          287 :   B2 = rowpermute(B, Rc);
    1164          287 :   Z = Flm_rsolve_lower_unit_pre(C1, B1, p, pi);
    1165          287 :   if (!gequal(Flm_mul_pre(C2, Z, p, pi), B2))
    1166           14 :     return NULL;
    1167          273 :   Y = vconcat(Flm_rsolve_upper_pre(vecslice(U, 1, r), Z, p, pi),
    1168          273 :               zero_Flm(lg(A) - 1 - r, lg(B) - 1));
    1169          273 :   X = rowpermute(Y, perm_inv(P));
    1170          273 :   return gc_upto(av, X);
    1171              : }
    1172              : 
    1173              : GEN
    1174          931 : Flm_invimage_i(GEN A, GEN B, ulong p)
    1175              : {
    1176              :   GEN d, x, X, Y;
    1177          931 :   long i, j, nY, nA = lg(A)-1, nB = lg(B)-1;
    1178              : 
    1179          931 :   if (!nB) return cgetg(1, t_MAT);
    1180          784 :   if (maxss(nA, nB) >= Flm_CUP_LIMIT && nbrows(B) >= Flm_CUP_LIMIT)
    1181          287 :     return Flm_invimage_CUP(A, B, p);
    1182              : 
    1183          497 :   x = Flm_ker(shallowconcat(Flm_neg(A,p), B), p);
    1184              :   /* AX = BY, Y in strict upper echelon form with pivots = 1.
    1185              :    * We must find T such that Y T = Id_nB then X T = Z. This exists iff
    1186              :    * Y has at least nB columns and full rank */
    1187          497 :   nY = lg(x)-1;
    1188          497 :   if (nY < nB) return NULL;
    1189          497 :   Y = rowslice(x, nA+1, nA+nB); /* nB rows */
    1190          497 :   d = cgetg(nB+1, t_VECSMALL);
    1191         1778 :   for (i = nB, j = nY; i >= 1; i--, j--)
    1192              :   {
    1193         1295 :     for (; j>=1; j--)
    1194         1288 :       if (coeff(Y,i,j)) { d[i] = j; break; }
    1195         1288 :     if (!j) return NULL;
    1196              :   }
    1197              :   /* reduce to the case Y square, upper triangular with 1s on diagonal */
    1198          490 :   Y = vecpermute(Y, d);
    1199          490 :   x = vecpermute(x, d);
    1200          490 :   X = rowslice(x, 1, nA);
    1201          490 :   return Flm_mul(X, Flm_inv_upper_1(Y,p), p);
    1202              : }
    1203              : GEN
    1204          889 : Flm_invimage(GEN A, GEN B, ulong p)
    1205              : {
    1206          889 :   pari_sp av = avma;
    1207          889 :   GEN X = Flm_invimage_i(A,B,p);
    1208          889 :   if (!X) return gc_NULL(av);
    1209          889 :   return gc_upto(av, X);
    1210              : }
    1211              : 
    1212              : GEN
    1213       139969 : Flm_Flc_invimage(GEN A, GEN y, ulong p)
    1214              : {
    1215       139969 :   pari_sp av = avma;
    1216       139969 :   long i, l = lg(A);
    1217              :   GEN M, x;
    1218              :   ulong t;
    1219              : 
    1220       139969 :   if (l==1) return NULL;
    1221       139829 :   if (lg(y) != lgcols(A)) pari_err_DIM("Flm_Flc_invimage");
    1222       139829 :   M = cgetg(l+1,t_MAT);
    1223      1105575 :   for (i=1; i<l; i++) gel(M,i) = gel(A,i);
    1224       139829 :   gel(M,l) = y; M = Flm_ker(M,p);
    1225       139829 :   i = lg(M)-1; if (!i) return gc_NULL(av);
    1226              : 
    1227       136596 :   x = gel(M,i); t = x[l];
    1228       136596 :   if (!t) return gc_NULL(av);
    1229              : 
    1230       136589 :   setlg(x,l); t = Fl_inv(Fl_neg(t,p),p);
    1231       136589 :   if (t!=1) x = Flv_Fl_mul(x, t, p);
    1232       136589 :   return gc_leaf(av, x);
    1233              : }
        

Generated by: LCOV version 2.0-1