Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2000, 2012 The PARI group.12This file is part of the PARI/GP package.34PARI/GP is free software; you can redistribute it and/or modify it under the5terms of the GNU General Public License as published by the Free Software6Foundation; either version 2 of the License, or (at your option) any later7version. It is distributed in the hope that it will be useful, but WITHOUT8ANY WARRANTY WHATSOEVER.910Check the License for details. You should have received a copy of it, along11with the package; see the file 'COPYING'. If not, write to the Free Software12Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */1314/********************************************************************/15/** **/16/** LINEAR ALGEBRA **/17/** (first part) **/18/** **/19/********************************************************************/20#include "pari.h"21#include "paripriv.h"2223#define DEBUGLEVEL DEBUGLEVEL_mat2425/*******************************************************************/26/* */27/* GEREPILE */28/* */29/*******************************************************************/3031static void32gerepile_mat(pari_sp av, pari_sp tetpil, GEN x, long k, long m, long n, long t)33{34pari_sp A, bot = pari_mainstack->bot;35long u, i;36size_t dec;3738(void)gerepile(av,tetpil,NULL); dec = av-tetpil;3940for (u=t+1; u<=m; u++)41{42A = (pari_sp)coeff(x,u,k);43if (A < av && A >= bot) coeff(x,u,k) += dec;44}45for (i=k+1; i<=n; i++)46for (u=1; u<=m; u++)47{48A = (pari_sp)coeff(x,u,i);49if (A < av && A >= bot) coeff(x,u,i) += dec;50}51}5253static void54gen_gerepile_gauss_ker(GEN x, long k, long t, pari_sp av, void *E, GEN (*copy)(void*, GEN))55{56pari_sp tetpil = avma;57long u,i, n = lg(x)-1, m = n? nbrows(x): 0;5859if (DEBUGMEM > 1) pari_warn(warnmem,"gauss_pivot_ker. k=%ld, n=%ld",k,n);60for (u=t+1; u<=m; u++) gcoeff(x,u,k) = copy(E,gcoeff(x,u,k));61for (i=k+1; i<=n; i++)62for (u=1; u<=m; u++) gcoeff(x,u,i) = copy(E,gcoeff(x,u,i));63gerepile_mat(av,tetpil,x,k,m,n,t);64}6566/* special gerepile for huge matrices */6768#define COPY(x) {\69GEN _t = (x); if (!is_universal_constant(_t)) x = gcopy(_t); \70}7172INLINE GEN73_copy(void *E, GEN x)74{75(void) E; COPY(x);76return x;77}7879static void80gerepile_gauss_ker(GEN x, long k, long t, pari_sp av)81{82gen_gerepile_gauss_ker(x, k, t, av, NULL, &_copy);83}8485static void86gerepile_gauss(GEN x,long k,long t,pari_sp av, long j, GEN c)87{88pari_sp tetpil = avma, A, bot;89long u,i, n = lg(x)-1, m = n? nbrows(x): 0;90size_t dec;9192if (DEBUGMEM > 1) pari_warn(warnmem,"gauss_pivot. k=%ld, n=%ld",k,n);93for (u=t+1; u<=m; u++)94if (u==j || !c[u]) COPY(gcoeff(x,u,k));95for (u=1; u<=m; u++)96if (u==j || !c[u])97for (i=k+1; i<=n; i++) COPY(gcoeff(x,u,i));9899(void)gerepile(av,tetpil,NULL); dec = av-tetpil;100bot = pari_mainstack->bot;101for (u=t+1; u<=m; u++)102if (u==j || !c[u])103{104A=(pari_sp)coeff(x,u,k);105if (A<av && A>=bot) coeff(x,u,k)+=dec;106}107for (u=1; u<=m; u++)108if (u==j || !c[u])109for (i=k+1; i<=n; i++)110{111A=(pari_sp)coeff(x,u,i);112if (A<av && A>=bot) coeff(x,u,i)+=dec;113}114}115116/*******************************************************************/117/* */118/* GENERIC */119/* */120/*******************************************************************/121GEN122gen_ker(GEN x, long deplin, void *E, const struct bb_field *ff)123{124pari_sp av0 = avma, av, tetpil;125GEN y, c, d;126long i, j, k, r, t, n, m;127128n=lg(x)-1; if (!n) return cgetg(1,t_MAT);129m=nbrows(x); r=0;130x = RgM_shallowcopy(x);131c = zero_zv(m);132d=new_chunk(n+1);133av=avma;134for (k=1; k<=n; k++)135{136for (j=1; j<=m; j++)137if (!c[j])138{139gcoeff(x,j,k) = ff->red(E, gcoeff(x,j,k));140if (!ff->equal0(gcoeff(x,j,k))) break;141}142if (j>m)143{144if (deplin)145{146GEN c = cgetg(n+1, t_COL), g0 = ff->s(E,0), g1=ff->s(E,1);147for (i=1; i<k; i++) gel(c,i) = ff->red(E, gcoeff(x,d[i],k));148gel(c,k) = g1; for (i=k+1; i<=n; i++) gel(c,i) = g0;149return gerepileupto(av0, c);150}151r++; d[k]=0;152for(j=1; j<k; j++)153if (d[j]) gcoeff(x,d[j],k) = gclone(gcoeff(x,d[j],k));154}155else156{157GEN piv = ff->neg(E,ff->inv(E,gcoeff(x,j,k)));158c[j] = k; d[k] = j;159gcoeff(x,j,k) = ff->s(E,-1);160for (i=k+1; i<=n; i++) gcoeff(x,j,i) = ff->red(E,ff->mul(E,piv,gcoeff(x,j,i)));161for (t=1; t<=m; t++)162{163if (t==j) continue;164165piv = ff->red(E,gcoeff(x,t,k));166if (ff->equal0(piv)) continue;167168gcoeff(x,t,k) = ff->s(E,0);169for (i=k+1; i<=n; i++)170gcoeff(x,t,i) = ff->red(E, ff->add(E, gcoeff(x,t,i),171ff->mul(E,piv,gcoeff(x,j,i))));172if (gc_needed(av,1))173gen_gerepile_gauss_ker(x,k,t,av,E,ff->red);174}175}176}177if (deplin) return gc_NULL(av0);178179tetpil=avma; y=cgetg(r+1,t_MAT);180for (j=k=1; j<=r; j++,k++)181{182GEN C = cgetg(n+1,t_COL);183GEN g0 = ff->s(E,0), g1 = ff->s(E,1);184gel(y,j) = C; while (d[k]) k++;185for (i=1; i<k; i++)186if (d[i])187{188GEN p1=gcoeff(x,d[i],k);189gel(C,i) = ff->red(E,p1); gunclone(p1);190}191else192gel(C,i) = g0;193gel(C,k) = g1; for (i=k+1; i<=n; i++) gel(C,i) = g0;194}195return gerepile(av0,tetpil,y);196}197198GEN199gen_Gauss_pivot(GEN x, long *rr, void *E, const struct bb_field *ff)200{201pari_sp av;202GEN c, d;203long i, j, k, r, t, m, n = lg(x)-1;204205if (!n) { *rr = 0; return NULL; }206207m=nbrows(x); r=0;208d = cgetg(n+1, t_VECSMALL);209x = RgM_shallowcopy(x);210c = zero_zv(m);211av=avma;212for (k=1; k<=n; k++)213{214for (j=1; j<=m; j++)215if (!c[j])216{217gcoeff(x,j,k) = ff->red(E,gcoeff(x,j,k));218if (!ff->equal0(gcoeff(x,j,k))) break;219}220if (j>m) { r++; d[k]=0; }221else222{223GEN piv = ff->neg(E,ff->inv(E,gcoeff(x,j,k)));224GEN g0 = ff->s(E,0);225c[j] = k; d[k] = j;226for (i=k+1; i<=n; i++) gcoeff(x,j,i) = ff->red(E,ff->mul(E,piv,gcoeff(x,j,i)));227for (t=1; t<=m; t++)228{229if (c[t]) continue; /* already a pivot on that line */230231piv = ff->red(E,gcoeff(x,t,k));232if (ff->equal0(piv)) continue;233gcoeff(x,t,k) = g0;234for (i=k+1; i<=n; i++)235gcoeff(x,t,i) = ff->red(E, ff->add(E,gcoeff(x,t,i), ff->mul(E,piv,gcoeff(x,j,i))));236if (gc_needed(av,1))237gerepile_gauss(x,k,t,av,j,c);238}239for (i=k; i<=n; i++) gcoeff(x,j,i) = g0; /* dummy */240}241}242*rr = r; return gc_const((pari_sp)d, d);243}244245GEN246gen_det(GEN a, void *E, const struct bb_field *ff)247{248pari_sp av = avma;249long i,j,k, s = 1, nbco = lg(a)-1;250GEN x = ff->s(E,1);251if (!nbco) return x;252a = RgM_shallowcopy(a);253for (i=1; i<nbco; i++)254{255GEN q;256for(k=i; k<=nbco; k++)257{258gcoeff(a,k,i) = ff->red(E,gcoeff(a,k,i));259if (!ff->equal0(gcoeff(a,k,i))) break;260}261if (k > nbco) return gerepileupto(av, gcoeff(a,i,i));262if (k != i)263{ /* exchange the lines s.t. k = i */264for (j=i; j<=nbco; j++) swap(gcoeff(a,i,j), gcoeff(a,k,j));265s = -s;266}267q = gcoeff(a,i,i);268x = ff->red(E,ff->mul(E,x,q));269q = ff->inv(E,q);270for (k=i+1; k<=nbco; k++)271{272GEN m = ff->red(E,gcoeff(a,i,k));273if (ff->equal0(m)) continue;274m = ff->neg(E, ff->red(E,ff->mul(E,m, q)));275for (j=i+1; j<=nbco; j++)276gcoeff(a,j,k) = ff->red(E, ff->add(E, gcoeff(a,j,k),277ff->mul(E, m, gcoeff(a,j,i))));278}279if (gc_needed(av,2))280{281if(DEBUGMEM>1) pari_warn(warnmem,"det. col = %ld",i);282gerepileall(av,2, &a,&x);283}284}285if (s < 0) x = ff->neg(E,x);286return gerepileupto(av, ff->red(E,ff->mul(E, x, gcoeff(a,nbco,nbco))));287}288289INLINE void290_gen_addmul(GEN b, long k, long i, GEN m, void *E, const struct bb_field *ff)291{292gel(b,i) = ff->red(E,gel(b,i));293gel(b,k) = ff->add(E,gel(b,k), ff->mul(E,m, gel(b,i)));294}295296static GEN297_gen_get_col(GEN a, GEN b, long li, void *E, const struct bb_field *ff)298{299GEN u = cgetg(li+1,t_COL);300pari_sp av = avma;301long i, j;302303gel(u,li) = gerepileupto(av, ff->red(E,ff->mul(E,gel(b,li), gcoeff(a,li,li))));304for (i=li-1; i>0; i--)305{306pari_sp av = avma;307GEN m = gel(b,i);308for (j=i+1; j<=li; j++) m = ff->add(E,m, ff->neg(E,ff->mul(E,gcoeff(a,i,j), gel(u,j))));309m = ff->red(E, m);310gel(u,i) = gerepileupto(av, ff->red(E,ff->mul(E,m, gcoeff(a,i,i))));311}312return u;313}314315GEN316gen_Gauss(GEN a, GEN b, void *E, const struct bb_field *ff)317{318long i, j, k, li, bco, aco;319GEN u, g0 = ff->s(E,0);320pari_sp av = avma;321a = RgM_shallowcopy(a);322b = RgM_shallowcopy(b);323aco = lg(a)-1; bco = lg(b)-1; li = nbrows(a);324for (i=1; i<=aco; i++)325{326GEN invpiv;327for (k = i; k <= li; k++)328{329GEN piv = ff->red(E,gcoeff(a,k,i));330if (!ff->equal0(piv)) { gcoeff(a,k,i) = ff->inv(E,piv); break; }331gcoeff(a,k,i) = g0;332}333/* found a pivot on line k */334if (k > li) return NULL;335if (k != i)336{ /* swap lines so that k = i */337for (j=i; j<=aco; j++) swap(gcoeff(a,i,j), gcoeff(a,k,j));338for (j=1; j<=bco; j++) swap(gcoeff(b,i,j), gcoeff(b,k,j));339}340if (i == aco) break;341342invpiv = gcoeff(a,i,i); /* 1/piv mod p */343for (k=i+1; k<=li; k++)344{345GEN m = ff->red(E,gcoeff(a,k,i)); gcoeff(a,k,i) = g0;346if (ff->equal0(m)) continue;347348m = ff->red(E,ff->neg(E,ff->mul(E,m, invpiv)));349for (j=i+1; j<=aco; j++) _gen_addmul(gel(a,j),k,i,m,E,ff);350for (j=1 ; j<=bco; j++) _gen_addmul(gel(b,j),k,i,m,E,ff);351}352if (gc_needed(av,1))353{354if(DEBUGMEM>1) pari_warn(warnmem,"gen_Gauss. i=%ld",i);355gerepileall(av,2, &a,&b);356}357}358359if(DEBUGLEVEL>4) err_printf("Solving the triangular system\n");360u = cgetg(bco+1,t_MAT);361for (j=1; j<=bco; j++) gel(u,j) = _gen_get_col(a, gel(b,j), aco, E, ff);362return u;363}364365/* compatible t_MAT * t_COL, lgA = lg(A) = lg(B) > 1, l = lgcols(A) */366static GEN367gen_matcolmul_i(GEN A, GEN B, ulong lgA, ulong l,368void *E, const struct bb_field *ff)369{370GEN C = cgetg(l, t_COL);371ulong i;372for (i = 1; i < l; i++) {373pari_sp av = avma;374GEN e = ff->mul(E, gcoeff(A, i, 1), gel(B, 1));375ulong k;376for(k = 2; k < lgA; k++)377e = ff->add(E, e, ff->mul(E, gcoeff(A, i, k), gel(B, k)));378gel(C, i) = gerepileupto(av, ff->red(E, e));379}380return C;381}382383GEN384gen_matcolmul(GEN A, GEN B, void *E, const struct bb_field *ff)385{386ulong lgA = lg(A);387if (lgA != (ulong)lg(B))388pari_err_OP("operation 'gen_matcolmul'", A, B);389if (lgA == 1)390return cgetg(1, t_COL);391return gen_matcolmul_i(A, B, lgA, lgcols(A), E, ff);392}393394static GEN395gen_matmul_classical(GEN A, GEN B, long l, long la, long lb,396void *E, const struct bb_field *ff)397{398long j;399GEN C = cgetg(lb, t_MAT);400for(j = 1; j < lb; j++)401gel(C, j) = gen_matcolmul_i(A, gel(B, j), la, l, E, ff);402return C;403}404405/* Strassen-Winograd algorithm */406407/*408Return A[ma+1..ma+da, na+1..na+ea] - B[mb+1..mb+db, nb+1..nb+eb]409as an (m x n)-matrix, padding the input with zeroes as necessary.410*/411static GEN412add_slices(long m, long n,413GEN A, long ma, long da, long na, long ea,414GEN B, long mb, long db, long nb, long eb,415void *E, const struct bb_field *ff)416{417long min_d = minss(da, db), min_e = minss(ea, eb), i, j;418GEN M = cgetg(n + 1, t_MAT), C;419420for (j = 1; j <= min_e; j++) {421gel(M, j) = C = cgetg(m + 1, t_COL);422for (i = 1; i <= min_d; i++)423gel(C, i) = ff->add(E, gcoeff(A, ma + i, na + j),424gcoeff(B, mb + i, nb + j));425for (; i <= da; i++)426gel(C, i) = gcoeff(A, ma + i, na + j);427for (; i <= db; i++)428gel(C, i) = gcoeff(B, mb + i, nb + j);429for (; i <= m; i++)430gel(C, i) = ff->s(E, 0);431}432for (; j <= ea; j++) {433gel(M, j) = C = cgetg(m + 1, t_COL);434for (i = 1; i <= da; i++)435gel(C, i) = gcoeff(A, ma + i, na + j);436for (; i <= m; i++)437gel(C, i) = ff->s(E, 0);438}439for (; j <= eb; j++) {440gel(M, j) = C = cgetg(m + 1, t_COL);441for (i = 1; i <= db; i++)442gel(C, i) = gcoeff(B, mb + i, nb + j);443for (; i <= m; i++)444gel(C, i) = ff->s(E, 0);445}446for (; j <= n; j++) {447gel(M, j) = C = cgetg(m + 1, t_COL);448for (i = 1; i <= m; i++)449gel(C, i) = ff->s(E, 0);450}451return M;452}453454/*455Return A[ma+1..ma+da, na+1..na+ea] - B[mb+1..mb+db, nb+1..nb+eb]456as an (m x n)-matrix, padding the input with zeroes as necessary.457*/458static GEN459subtract_slices(long m, long n,460GEN A, long ma, long da, long na, long ea,461GEN B, long mb, long db, long nb, long eb,462void *E, const struct bb_field *ff)463{464long min_d = minss(da, db), min_e = minss(ea, eb), i, j;465GEN M = cgetg(n + 1, t_MAT), C;466467for (j = 1; j <= min_e; j++) {468gel(M, j) = C = cgetg(m + 1, t_COL);469for (i = 1; i <= min_d; i++)470gel(C, i) = ff->add(E, gcoeff(A, ma + i, na + j),471ff->neg(E, gcoeff(B, mb + i, nb + j)));472for (; i <= da; i++)473gel(C, i) = gcoeff(A, ma + i, na + j);474for (; i <= db; i++)475gel(C, i) = ff->neg(E, gcoeff(B, mb + i, nb + j));476for (; i <= m; i++)477gel(C, i) = ff->s(E, 0);478}479for (; j <= ea; j++) {480gel(M, j) = C = cgetg(m + 1, t_COL);481for (i = 1; i <= da; i++)482gel(C, i) = gcoeff(A, ma + i, na + j);483for (; i <= m; i++)484gel(C, i) = ff->s(E, 0);485}486for (; j <= eb; j++) {487gel(M, j) = C = cgetg(m + 1, t_COL);488for (i = 1; i <= db; i++)489gel(C, i) = ff->neg(E, gcoeff(B, mb + i, nb + j));490for (; i <= m; i++)491gel(C, i) = ff->s(E, 0);492}493for (; j <= n; j++) {494gel(M, j) = C = cgetg(m + 1, t_COL);495for (i = 1; i <= m; i++)496gel(C, i) = ff->s(E, 0);497}498return M;499}500501static GEN gen_matmul_i(GEN A, GEN B, long l, long la, long lb,502void *E, const struct bb_field *ff);503504static GEN505gen_matmul_sw(GEN A, GEN B, long m, long n, long p,506void *E, const struct bb_field *ff)507{508pari_sp av = avma;509long m1 = (m + 1)/2, m2 = m/2,510n1 = (n + 1)/2, n2 = n/2,511p1 = (p + 1)/2, p2 = p/2;512GEN A11, A12, A22, B11, B21, B22,513S1, S2, S3, S4, T1, T2, T3, T4,514M1, M2, M3, M4, M5, M6, M7,515V1, V2, V3, C11, C12, C21, C22, C;516517T2 = subtract_slices(n1, p2, B, 0, n1, p1, p2, B, n1, n2, p1, p2, E, ff);518S1 = subtract_slices(m2, n1, A, m1, m2, 0, n1, A, 0, m2, 0, n1, E, ff);519M2 = gen_matmul_i(S1, T2, m2 + 1, n1 + 1, p2 + 1, E, ff);520if (gc_needed(av, 1))521gerepileall(av, 2, &T2, &M2); /* destroy S1 */522T3 = subtract_slices(n1, p1, T2, 0, n1, 0, p2, B, 0, n1, 0, p1, E, ff);523if (gc_needed(av, 1))524gerepileall(av, 2, &M2, &T3); /* destroy T2 */525S2 = add_slices(m2, n1, A, m1, m2, 0, n1, A, m1, m2, n1, n2, E, ff);526T1 = subtract_slices(n1, p1, B, 0, n1, p1, p2, B, 0, n1, 0, p2, E, ff);527M3 = gen_matmul_i(S2, T1, m2 + 1, n1 + 1, p2 + 1, E, ff);528if (gc_needed(av, 1))529gerepileall(av, 4, &M2, &T3, &S2, &M3); /* destroy T1 */530S3 = subtract_slices(m1, n1, S2, 0, m2, 0, n1, A, 0, m1, 0, n1, E, ff);531if (gc_needed(av, 1))532gerepileall(av, 4, &M2, &T3, &M3, &S3); /* destroy S2 */533A11 = matslice(A, 1, m1, 1, n1);534B11 = matslice(B, 1, n1, 1, p1);535M1 = gen_matmul_i(A11, B11, m1 + 1, n1 + 1, p1 + 1, E, ff);536if (gc_needed(av, 1))537gerepileall(av, 5, &M2, &T3, &M3, &S3, &M1); /* destroy A11, B11 */538A12 = matslice(A, 1, m1, n1 + 1, n);539B21 = matslice(B, n1 + 1, n, 1, p1);540M4 = gen_matmul_i(A12, B21, m1 + 1, n2 + 1, p1 + 1, E, ff);541if (gc_needed(av, 1))542gerepileall(av, 6, &M2, &T3, &M3, &S3, &M1, &M4); /* destroy A12, B21 */543C11 = add_slices(m1, p1, M1, 0, m1, 0, p1, M4, 0, m1, 0, p1, E, ff);544if (gc_needed(av, 1))545gerepileall(av, 6, &M2, &T3, &M3, &S3, &M1, &C11); /* destroy M4 */546M5 = gen_matmul_i(S3, T3, m1 + 1, n1 + 1, p1 + 1, E, ff);547S4 = subtract_slices(m1, n2, A, 0, m1, n1, n2, S3, 0, m1, 0, n2, E, ff);548if (gc_needed(av, 1))549gerepileall(av, 7, &M2, &T3, &M3, &M1, &C11, &M5, &S4); /* destroy S3 */550T4 = add_slices(n2, p1, B, n1, n2, 0, p1, T3, 0, n2, 0, p1, E, ff);551if (gc_needed(av, 1))552gerepileall(av, 7, &M2, &M3, &M1, &C11, &M5, &S4, &T4); /* destroy T3 */553V1 = subtract_slices(m1, p1, M1, 0, m1, 0, p1, M5, 0, m1, 0, p1, E, ff);554if (gc_needed(av, 1))555gerepileall(av, 6, &M2, &M3, &S4, &T4, &C11, &V1); /* destroy M1, M5 */556B22 = matslice(B, n1 + 1, n, p1 + 1, p);557M6 = gen_matmul_i(S4, B22, m1 + 1, n2 + 1, p2 + 1, E, ff);558if (gc_needed(av, 1))559gerepileall(av, 6, &M2, &M3, &T4, &C11, &V1, &M6); /* destroy S4, B22 */560A22 = matslice(A, m1 + 1, m, n1 + 1, n);561M7 = gen_matmul_i(A22, T4, m2 + 1, n2 + 1, p1 + 1, E, ff);562if (gc_needed(av, 1))563gerepileall(av, 6, &M2, &M3, &C11, &V1, &M6, &M7); /* destroy A22, T4 */564V3 = add_slices(m1, p2, V1, 0, m1, 0, p2, M3, 0, m2, 0, p2, E, ff);565C12 = add_slices(m1, p2, V3, 0, m1, 0, p2, M6, 0, m1, 0, p2, E, ff);566if (gc_needed(av, 1))567gerepileall(av, 6, &M2, &M3, &C11, &V1, &M7, &C12); /* destroy V3, M6 */568V2 = add_slices(m2, p1, V1, 0, m2, 0, p1, M2, 0, m2, 0, p2, E, ff);569if (gc_needed(av, 1))570gerepileall(av, 5, &M3, &C11, &M7, &C12, &V2); /* destroy V1, M2 */571C21 = add_slices(m2, p1, V2, 0, m2, 0, p1, M7, 0, m2, 0, p1, E, ff);572if (gc_needed(av, 1))573gerepileall(av, 5, &M3, &C11, &C12, &V2, &C21); /* destroy M7 */574C22 = add_slices(m2, p2, V2, 0, m2, 0, p2, M3, 0, m2, 0, p2, E, ff);575if (gc_needed(av, 1))576gerepileall(av, 4, &C11, &C12, &C21, &C22); /* destroy V2, M3 */577C = mkmat2(mkcol2(C11, C21), mkcol2(C12, C22));578return gerepileupto(av, matconcat(C));579}580581/* Strassen-Winograd used for dim >= gen_matmul_sw_bound */582static const long gen_matmul_sw_bound = 24;583584static GEN585gen_matmul_i(GEN A, GEN B, long l, long la, long lb,586void *E, const struct bb_field *ff)587{588if (l <= gen_matmul_sw_bound589|| la <= gen_matmul_sw_bound590|| lb <= gen_matmul_sw_bound)591return gen_matmul_classical(A, B, l, la, lb, E, ff);592else593return gen_matmul_sw(A, B, l - 1, la - 1, lb - 1, E, ff);594}595596GEN597gen_matmul(GEN A, GEN B, void *E, const struct bb_field *ff)598{599ulong lgA, lgB = lg(B);600if (lgB == 1)601return cgetg(1, t_MAT);602lgA = lg(A);603if (lgA != (ulong)lgcols(B))604pari_err_OP("operation 'gen_matmul'", A, B);605if (lgA == 1)606return zeromat(0, lgB - 1);607return gen_matmul_i(A, B, lgcols(A), lgA, lgB, E, ff);608}609610static GEN611gen_colneg(GEN A, void *E, const struct bb_field *ff)612{613long i, l;614GEN B = cgetg_copy(A, &l);615for (i = 1; i < l; i++)616gel(B, i) = ff->neg(E, gel(A, i));617return B;618}619620static GEN621gen_matneg(GEN A, void *E, const struct bb_field *ff)622{623long i, l;624GEN B = cgetg_copy(A, &l);625for (i = 1; i < l; i++)626gel(B, i) = gen_colneg(gel(A, i), E, ff);627return B;628}629630static GEN631gen_colscalmul(GEN A, GEN b, void *E, const struct bb_field *ff)632{633long i, l;634GEN B = cgetg_copy(A, &l);635for (i = 1; i < l; i++)636gel(B, i) = ff->red(E, ff->mul(E, gel(A, i), b));637return B;638}639640static GEN641gen_matscalmul(GEN A, GEN b, void *E, const struct bb_field *ff)642{643long i, l;644GEN B = cgetg_copy(A, &l);645for (i = 1; i < l; i++)646gel(B, i) = gen_colscalmul(gel(A, i), b, E, ff);647return B;648}649650static GEN651gen_colsub(GEN A, GEN C, void *E, const struct bb_field *ff)652{653long i, l;654GEN B = cgetg_copy(A, &l);655for (i = 1; i < l; i++)656gel(B, i) = ff->add(E, gel(A, i), ff->neg(E, gel(C, i)));657return B;658}659660static GEN661gen_matsub(GEN A, GEN C, void *E, const struct bb_field *ff)662{663long i, l;664GEN B = cgetg_copy(A, &l);665for (i = 1; i < l; i++)666gel(B, i) = gen_colsub(gel(A, i), gel(C, i), E, ff);667return B;668}669670static GEN671gen_zerocol(long n, void* data, const struct bb_field *R)672{673GEN C = cgetg(n+1,t_COL), zero = R->s(data, 0);674long i;675for (i=1; i<=n; i++) gel(C,i) = zero;676return C;677}678679static GEN680gen_zeromat(long m, long n, void* data, const struct bb_field *R)681{682GEN M = cgetg(n+1,t_MAT);683long i;684for (i=1; i<=n; i++) gel(M,i) = gen_zerocol(m, data, R);685return M;686}687688static GEN689gen_colei(long n, long i, void *E, const struct bb_field *S)690{691GEN y = cgetg(n+1,t_COL), _0, _1;692long j;693if (n < 0) pari_err_DOMAIN("gen_colei", "dimension","<",gen_0,stoi(n));694_0 = S->s(E,0);695_1 = S->s(E,1);696for (j=1; j<=n; j++)697gel(y, j) = i==j ? _1: _0;698return y;699}700701/* assume dim A >= 1, A invertible + upper triangular */702static GEN703gen_matinv_upper_ind(GEN A, long index, void *E, const struct bb_field *ff)704{705long n = lg(A) - 1, i, j;706GEN u = cgetg(n + 1, t_COL);707for (i = n; i > index; i--)708gel(u, i) = ff->s(E, 0);709gel(u, i) = ff->inv(E, gcoeff(A, i, i));710for (i--; i > 0; i--) {711pari_sp av = avma;712GEN m = ff->neg(E, ff->mul(E, gcoeff(A, i, i + 1), gel(u, i + 1)));713for (j = i + 2; j <= n; j++)714m = ff->add(E, m, ff->neg(E, ff->mul(E, gcoeff(A, i, j), gel(u, j))));715gel(u, i) = gerepileupto(av, ff->red(E, ff->mul(E, m, ff->inv(E, gcoeff(A, i, i)))));716}717return u;718}719720static GEN721gen_matinv_upper(GEN A, void *E, const struct bb_field *ff)722{723long i, l;724GEN B = cgetg_copy(A, &l);725for (i = 1; i < l; i++)726gel(B,i) = gen_matinv_upper_ind(A, i, E, ff);727return B;728}729730/* find z such that A z = y. Return NULL if no solution */731GEN732gen_matcolinvimage(GEN A, GEN y, void *E, const struct bb_field *ff)733{734pari_sp av = avma;735long i, l = lg(A);736GEN M, x, t;737738M = gen_ker(shallowconcat(A, y), 0, E, ff);739i = lg(M) - 1;740if (!i) return gc_NULL(av);741742x = gel(M, i);743t = gel(x, l);744if (ff->equal0(t)) return gc_NULL(av);745746t = ff->neg(E, ff->inv(E, t));747setlg(x, l);748for (i = 1; i < l; i++)749gel(x, i) = ff->red(E, ff->mul(E, t, gel(x, i)));750return gerepilecopy(av, x);751}752753/* find Z such that A Z = B. Return NULL if no solution */754GEN755gen_matinvimage(GEN A, GEN B, void *E, const struct bb_field *ff)756{757pari_sp av = avma;758GEN d, x, X, Y;759long i, j, nY, nA, nB;760x = gen_ker(shallowconcat(gen_matneg(A, E, ff), B), 0, E, ff);761/* AX = BY, Y in strict upper echelon form with pivots = 1.762* We must find T such that Y T = Id_nB then X T = Z. This exists763* iff Y has at least nB columns and full rank. */764nY = lg(x) - 1;765nB = lg(B) - 1;766if (nY < nB) return gc_NULL(av);767nA = lg(A) - 1;768Y = rowslice(x, nA + 1, nA + nB); /* nB rows */769d = cgetg(nB + 1, t_VECSMALL);770for (i = nB, j = nY; i >= 1; i--, j--) {771for (; j >= 1; j--)772if (!ff->equal0(gcoeff(Y, i, j))) { d[i] = j; break; }773if (!j) return gc_NULL(av);774}775/* reduce to the case Y square, upper triangular with 1s on diagonal */776Y = vecpermute(Y, d);777x = vecpermute(x, d);778X = rowslice(x, 1, nA);779return gerepileupto(av, gen_matmul(X, gen_matinv_upper(Y, E, ff), E, ff));780}781782static GEN783image_from_pivot(GEN x, GEN d, long r)784{785GEN y;786long j, k;787788if (!d) return gcopy(x);789/* d left on stack for efficiency */790r = lg(x)-1 - r; /* = dim Im(x) */791y = cgetg(r+1,t_MAT);792for (j=k=1; j<=r; k++)793if (d[k]) gel(y,j++) = gcopy(gel(x,k));794return y;795}796797/* r = dim Ker x, n = nbrows(x) */798static GEN799get_suppl(GEN x, GEN d, long n, long r, GEN(*ei)(long,long))800{801pari_sp av;802GEN y, c;803long j, k, rx = lg(x)-1; /* != 0 due to init_suppl() */804805if (rx == n && r == 0) return gcopy(x);806y = cgetg(n+1, t_MAT);807av = avma; c = zero_zv(n);808/* c = lines containing pivots (could get it from gauss_pivot, but cheap)809* In theory r = 0 and d[j] > 0 for all j, but why take chances? */810for (k = j = 1; j<=rx; j++)811if (d[j]) { c[ d[j] ] = 1; gel(y,k++) = gel(x,j); }812for (j=1; j<=n; j++)813if (!c[j]) gel(y,k++) = (GEN)j; /* HACK */814set_avma(av);815816rx -= r;817for (j=1; j<=rx; j++) gel(y,j) = gcopy(gel(y,j));818for ( ; j<=n; j++) gel(y,j) = ei(n, y[j]);819return y;820}821822/* n = dim x, r = dim Ker(x), d from gauss_pivot */823static GEN824indexrank0(long n, long r, GEN d)825{826GEN p1, p2, res = cgetg(3,t_VEC);827long i, j;828829r = n - r; /* now r = dim Im(x) */830p1 = cgetg(r+1,t_VECSMALL); gel(res,1) = p1;831p2 = cgetg(r+1,t_VECSMALL); gel(res,2) = p2;832if (d)833{834for (i=0,j=1; j<=n; j++)835if (d[j]) { i++; p1[i] = d[j]; p2[i] = j; }836vecsmall_sort(p1);837}838return res;839}840841/*******************************************************************/842/* */843/* Echelon form and CUP decomposition */844/* */845/*******************************************************************/846847/* By Peter Bruin, based on848C.-P. Jeannerod, C. Pernet and A. Storjohann, Rank-profile revealing849Gaussian elimination and the CUP matrix decomposition. J. Symbolic850Comput. 56 (2013), 46-68.851852Decompose an m x n-matrix A of rank r as C*U*P, with853- C: m x r-matrix in column echelon form (not necessarily reduced)854with all pivots equal to 1855- U: upper-triangular r x n-matrix856- P: permutation matrix857The pivots of C and the known zeroes in C and U are not necessarily858filled in; instead, we also return the vector R of pivot rows.859Instead of the matrix P, we return the permutation p of [1..n]860(t_VECSMALL) such that P[i,j] = 1 if and only if j = p[i].861*/862863/* complement of a strictly increasing subsequence of (1, 2, ..., n) */864static GEN865indexcompl(GEN v, long n)866{867long i, j, k, m = lg(v) - 1;868GEN w = cgetg(n - m + 1, t_VECSMALL);869for (i = j = k = 1; i <= n; i++)870if (j <= m && v[j] == i) j++; else w[k++] = i;871return w;872}873874static GEN875gen_solve_upper_1(GEN U, GEN B, void *E, const struct bb_field *ff)876{ return gen_matscalmul(B, ff->inv(E, gcoeff(U, 1, 1)), E, ff); }877878static GEN879gen_rsolve_upper_2(GEN U, GEN B, void *E, const struct bb_field *ff)880{881GEN a = gcoeff(U, 1, 1), b = gcoeff(U, 1, 2), d = gcoeff(U, 2, 2);882GEN D = ff->red(E, ff->mul(E, a, d)), Dinv = ff->inv(E, D);883GEN ainv = ff->red(E, ff->mul(E, d, Dinv));884GEN dinv = ff->red(E, ff->mul(E, a, Dinv));885GEN B1 = rowslice(B, 1, 1);886GEN B2 = rowslice(B, 2, 2);887GEN X2 = gen_matscalmul(B2, dinv, E, ff);888GEN X1 = gen_matscalmul(gen_matsub(B1, gen_matscalmul(X2, b, E, ff), E, ff),889ainv, E, ff);890return vconcat(X1, X2);891}892893/* solve U*X = B, U upper triangular and invertible */894static GEN895gen_rsolve_upper(GEN U, GEN B, void *E, const struct bb_field *ff,896GEN (*mul)(void *E, GEN a, GEN))897{898long n = lg(U) - 1, n1;899GEN U2, U11, U12, U22, B1, B2, X1, X2, X;900pari_sp av = avma;901902if (n == 0) return B;903if (n == 1) return gen_solve_upper_1(U, B, E, ff);904if (n == 2) return gen_rsolve_upper_2(U, B, E, ff);905n1 = (n + 1)/2;906U2 = vecslice(U, n1 + 1, n);907U11 = matslice(U, 1,n1, 1,n1);908U12 = rowslice(U2, 1, n1);909U22 = rowslice(U2, n1 + 1, n);910B1 = rowslice(B, 1, n1);911B2 = rowslice(B, n1 + 1, n);912X2 = gen_rsolve_upper(U22, B2, E, ff, mul);913B1 = gen_matsub(B1, mul(E, U12, X2), E, ff);914if (gc_needed(av, 1)) gerepileall(av, 3, &B1, &U11, &X2);915X1 = gen_rsolve_upper(U11, B1, E, ff, mul);916X = vconcat(X1, X2);917if (gc_needed(av, 1)) X = gerepilecopy(av, X);918return X;919}920921static GEN922gen_lsolve_upper_2(GEN U, GEN B, void *E, const struct bb_field *ff)923{924GEN a = gcoeff(U, 1, 1), b = gcoeff(U, 1, 2), d = gcoeff(U, 2, 2);925GEN D = ff->red(E, ff->mul(E, a, d)), Dinv = ff->inv(E, D);926GEN ainv = ff->red(E, ff->mul(E, d, Dinv)), dinv = ff->red(E, ff->mul(E, a, Dinv));927GEN B1 = vecslice(B, 1, 1);928GEN B2 = vecslice(B, 2, 2);929GEN X1 = gen_matscalmul(B1, ainv, E, ff);930GEN X2 = gen_matscalmul(gen_matsub(B2, gen_matscalmul(X1, b, E, ff), E, ff), dinv, E, ff);931return shallowconcat(X1, X2);932}933934/* solve X*U = B, U upper triangular and invertible */935static GEN936gen_lsolve_upper(GEN U, GEN B, void *E, const struct bb_field *ff,937GEN (*mul)(void *E, GEN a, GEN))938{939long n = lg(U) - 1, n1;940GEN U2, U11, U12, U22, B1, B2, X1, X2, X;941pari_sp av = avma;942943if (n == 0) return B;944if (n == 1) return gen_solve_upper_1(U, B, E, ff);945if (n == 2) return gen_lsolve_upper_2(U, B, E, ff);946n1 = (n + 1)/2;947U2 = vecslice(U, n1 + 1, n);948U11 = matslice(U, 1,n1, 1,n1);949U12 = rowslice(U2, 1, n1);950U22 = rowslice(U2, n1 + 1, n);951B1 = vecslice(B, 1, n1);952B2 = vecslice(B, n1 + 1, n);953X1 = gen_lsolve_upper(U11, B1, E, ff, mul);954B2 = gen_matsub(B2, mul(E, X1, U12), E, ff);955if (gc_needed(av, 1)) gerepileall(av, 3, &B2, &U22, &X1);956X2 = gen_lsolve_upper(U22, B2, E, ff, mul);957X = shallowconcat(X1, X2);958if (gc_needed(av, 1)) X = gerepilecopy(av, X);959return X;960}961962static GEN963gen_rsolve_lower_unit_2(GEN L, GEN A, void *E, const struct bb_field *ff)964{965GEN X1 = rowslice(A, 1, 1);966GEN X2 = gen_matsub(rowslice(A, 2, 2), gen_matscalmul(X1, gcoeff(L, 2, 1), E, ff), E, ff);967return vconcat(X1, X2);968}969970/* solve L*X = A, L lower triangular with ones on the diagonal971* (at least as many rows as columns) */972static GEN973gen_rsolve_lower_unit(GEN L, GEN A, void *E, const struct bb_field *ff,974GEN (*mul)(void *E, GEN a, GEN))975{976long m = lg(L) - 1, m1, n;977GEN L1, L11, L21, L22, A1, A2, X1, X2, X;978pari_sp av = avma;979980if (m == 0) return zeromat(0, lg(A) - 1);981if (m == 1) return rowslice(A, 1, 1);982if (m == 2) return gen_rsolve_lower_unit_2(L, A, E, ff);983m1 = (m + 1)/2;984n = nbrows(L);985L1 = vecslice(L, 1, m1);986L11 = rowslice(L1, 1, m1);987L21 = rowslice(L1, m1 + 1, n);988A1 = rowslice(A, 1, m1);989X1 = gen_rsolve_lower_unit(L11, A1, E, ff, mul);990A2 = rowslice(A, m1 + 1, n);991A2 = gen_matsub(A2, mul(E, L21, X1), E, ff);992if (gc_needed(av, 1)) gerepileall(av, 2, &A2, &X1);993L22 = matslice(L, m1+1,n, m1+1,m);994X2 = gen_rsolve_lower_unit(L22, A2, E, ff, mul);995X = vconcat(X1, X2);996if (gc_needed(av, 1)) X = gerepilecopy(av, X);997return X;998}9991000static GEN1001gen_lsolve_lower_unit_2(GEN L, GEN A, void *E, const struct bb_field *ff)1002{1003GEN X2 = vecslice(A, 2, 2);1004GEN X1 = gen_matsub(vecslice(A, 1, 1),1005gen_matscalmul(X2, gcoeff(L, 2, 1), E, ff), E, ff);1006return shallowconcat(X1, X2);1007}10081009/* solve L*X = A, L lower triangular with ones on the diagonal1010* (at least as many rows as columns) */1011static GEN1012gen_lsolve_lower_unit(GEN L, GEN A, void *E, const struct bb_field *ff,1013GEN (*mul)(void *E, GEN a, GEN))1014{1015long m = lg(L) - 1, m1;1016GEN L1, L2, L11, L21, L22, A1, A2, X1, X2, X;1017pari_sp av = avma;10181019if (m <= 1) return A;1020if (m == 2) return gen_lsolve_lower_unit_2(L, A, E, ff);1021m1 = (m + 1)/2;1022L2 = vecslice(L, m1 + 1, m);1023L22 = rowslice(L2, m1 + 1, m);1024A2 = vecslice(A, m1 + 1, m);1025X2 = gen_lsolve_lower_unit(L22, A2, E, ff, mul);1026if (gc_needed(av, 1)) X2 = gerepilecopy(av, X2);1027L1 = vecslice(L, 1, m1);1028L21 = rowslice(L1, m1 + 1, m);1029A1 = vecslice(A, 1, m1);1030A1 = gen_matsub(A1, mul(E, X2, L21), E, ff);1031L11 = rowslice(L1, 1, m1);1032if (gc_needed(av, 1)) gerepileall(av, 3, &A1, &L11, &X2);1033X1 = gen_lsolve_lower_unit(L11, A1, E, ff, mul);1034X = shallowconcat(X1, X2);1035if (gc_needed(av, 1)) X = gerepilecopy(av, X);1036return X;1037}10381039/* destroy A */1040static long1041gen_CUP_basecase(GEN A, GEN *R, GEN *C, GEN *U, GEN *P, void *E, const struct bb_field *ff)1042{1043long i, j, k, m = nbrows(A), n = lg(A) - 1, pr, pc;1044pari_sp av;1045GEN u, v;10461047if (P) *P = identity_perm(n);1048*R = cgetg(m + 1, t_VECSMALL);1049av = avma;1050for (j = 1, pr = 0; j <= n; j++)1051{1052for (pr++, pc = 0; pr <= m; pr++)1053{1054for (k = j; k <= n; k++)1055{1056v = ff->red(E, gcoeff(A, pr, k));1057gcoeff(A, pr, k) = v;1058if (!pc && !ff->equal0(v)) pc = k;1059}1060if (pc) break;1061}1062if (!pc) break;1063(*R)[j] = pr;1064if (pc != j)1065{1066swap(gel(A, j), gel(A, pc));1067if (P) lswap((*P)[j], (*P)[pc]);1068}1069u = ff->inv(E, gcoeff(A, pr, j));1070for (i = pr + 1; i <= m; i++)1071{1072v = ff->red(E, ff->mul(E, gcoeff(A, i, j), u));1073gcoeff(A, i, j) = v;1074v = ff->neg(E, v);1075for (k = j + 1; k <= n; k++)1076gcoeff(A, i, k) = ff->add(E, gcoeff(A, i, k),1077ff->red(E, ff->mul(E, gcoeff(A, pr, k), v)));1078}1079if (gc_needed(av, 2)) A = gerepilecopy(av, A);1080}1081setlg(*R, j);1082*C = vecslice(A, 1, j - 1);1083if (U) *U = rowpermute(A, *R);1084return j - 1;1085}10861087static const long gen_CUP_LIMIT = 5;10881089static long1090gen_CUP(GEN A, GEN *R, GEN *C, GEN *U, GEN *P, void *E, const struct bb_field *ff,1091GEN (*mul)(void *E, GEN a, GEN))1092{1093long m = nbrows(A), m1, n = lg(A) - 1, i, r1, r2, r;1094GEN R1, C1, U1, P1, R2, C2, U2, P2;1095GEN A1, A2, B2, C21, U11, U12, T21, T22;1096pari_sp av = avma;10971098if (m < gen_CUP_LIMIT || n < gen_CUP_LIMIT)1099/* destroy A; not called at the outermost recursion level */1100return gen_CUP_basecase(A, R, C, U, P, E, ff);1101m1 = (minss(m, n) + 1)/2;1102A1 = rowslice(A, 1, m1);1103A2 = rowslice(A, m1 + 1, m);1104r1 = gen_CUP(A1, &R1, &C1, &U1, &P1, E, ff, mul);1105if (r1 == 0)1106{1107r2 = gen_CUP(A2, &R2, &C2, &U2, &P2, E, ff, mul);1108*R = cgetg(r2 + 1, t_VECSMALL);1109for (i = 1; i <= r2; i++) (*R)[i] = R2[i] + m1;1110*C = vconcat(gen_zeromat(m1, r2, E, ff), C2);1111*U = U2;1112*P = P2;1113r = r2;1114}1115else1116{1117U11 = vecslice(U1, 1, r1);1118U12 = vecslice(U1, r1 + 1, n);1119T21 = vecslicepermute(A2, P1, 1, r1);1120T22 = vecslicepermute(A2, P1, r1 + 1, n);1121C21 = gen_lsolve_upper(U11, T21, E, ff, mul);1122if (gc_needed(av, 1))1123gerepileall(av, 7, &R1, &C1, &P1, &U11, &U12, &T22, &C21);1124B2 = gen_matsub(T22, mul(E, C21, U12), E, ff);1125r2 = gen_CUP(B2, &R2, &C2, &U2, &P2, E, ff, mul);1126r = r1 + r2;1127*R = cgetg(r + 1, t_VECSMALL);1128for (i = 1; i <= r1; i++) (*R)[i] = R1[i];1129for ( ; i <= r; i++) (*R)[i] = R2[i - r1] + m1;1130*C = shallowconcat(vconcat(C1, C21),1131vconcat(gen_zeromat(m1, r2, E, ff), C2));1132*U = shallowconcat(vconcat(U11, gen_zeromat(r2, r1, E, ff)),1133vconcat(vecpermute(U12, P2), U2));11341135*P = cgetg(n + 1, t_VECSMALL);1136for (i = 1; i <= r1; i++) (*P)[i] = P1[i];1137for ( ; i <= n; i++) (*P)[i] = P1[P2[i - r1] + r1];1138}1139if (gc_needed(av, 1)) gerepileall(av, 4, R, C, U, P);1140return r;1141}11421143/* column echelon form */1144static long1145gen_echelon(GEN A, GEN *R, GEN *C, void *E, const struct bb_field *ff,1146GEN (*mul)(void*, GEN, GEN))1147{1148long j, j1, j2, m = nbrows(A), n = lg(A) - 1, n1, r, r1, r2;1149GEN A1, A2, R1, R1c, C1, R2, C2;1150GEN A12, A22, B2, C11, C21, M12;1151pari_sp av = avma;11521153if (m < gen_CUP_LIMIT || n < gen_CUP_LIMIT)1154return gen_CUP_basecase(shallowcopy(A), R, C, NULL, NULL, E, ff);11551156n1 = (n + 1)/2;1157A1 = vecslice(A, 1, n1);1158A2 = vecslice(A, n1 + 1, n);1159r1 = gen_echelon(A1, &R1, &C1, E, ff, mul);1160if (!r1) return gen_echelon(A2, R, C, E, ff, mul);1161if (r1 == m) { *R = R1; *C = C1; return r1; }1162R1c = indexcompl(R1, m);1163C11 = rowpermute(C1, R1);1164C21 = rowpermute(C1, R1c);1165A12 = rowpermute(A2, R1);1166A22 = rowpermute(A2, R1c);1167M12 = gen_rsolve_lower_unit(C11, A12, E, ff, mul);1168B2 = gen_matsub(A22, mul(E, C21, M12), E, ff);1169r2 = gen_echelon(B2, &R2, &C2, E, ff, mul);1170if (!r2) { *R = R1; *C = C1; r = r1; }1171else1172{1173R2 = perm_mul(R1c, R2);1174C2 = rowpermute(vconcat(gen_zeromat(r1, r2, E, ff), C2),1175perm_inv(vecsmall_concat(R1, R1c)));1176r = r1 + r2;1177*R = cgetg(r + 1, t_VECSMALL);1178*C = cgetg(r + 1, t_MAT);1179for (j = j1 = j2 = 1; j <= r; j++)1180if (j2 > r2 || (j1 <= r1 && R1[j1] < R2[j2]))1181{1182gel(*C, j) = gel(C1, j1);1183(*R)[j] = R1[j1++];1184}1185else1186{1187gel(*C, j) = gel(C2, j2);1188(*R)[j] = R2[j2++];1189}1190}1191if (gc_needed(av, 1)) gerepileall(av, 2, R, C);1192return r;1193}11941195static GEN1196gen_pivots_CUP(GEN x, long *rr, void *E, const struct bb_field *ff,1197GEN (*mul)(void*, GEN, GEN))1198{1199pari_sp av;1200long i, n = lg(x) - 1, r;1201GEN R, C, U, P, d = zero_zv(n);1202av = avma;1203r = gen_CUP(x, &R, &C, &U, &P, E, ff, mul);1204for(i = 1; i <= r; i++)1205d[P[i]] = R[i];1206set_avma(av);1207*rr = n - r;1208return d;1209}12101211static GEN1212gen_det_CUP(GEN a, void *E, const struct bb_field *ff,1213GEN (*mul)(void*, GEN, GEN))1214{1215pari_sp av = avma;1216GEN R, C, U, P, d;1217long i, n = lg(a) - 1, r;1218r = gen_CUP(a, &R, &C, &U, &P, E, ff, mul);1219if (r < n)1220d = ff->s(E, 0);1221else {1222d = ff->s(E, perm_sign(P) == 1 ? 1: - 1);1223for (i = 1; i <= n; i++)1224d = ff->red(E, ff->mul(E, d, gcoeff(U, i, i)));1225}1226return gerepileupto(av, d);1227}12281229static long1230gen_matrank(GEN x, void *E, const struct bb_field *ff,1231GEN (*mul)(void*, GEN, GEN))1232{1233pari_sp av = avma;1234long r;1235if (lg(x) - 1 >= gen_CUP_LIMIT && nbrows(x) >= gen_CUP_LIMIT)1236{1237GEN R, C;1238return gc_long(av, gen_echelon(x, &R, &C, E, ff, mul));1239}1240(void) gen_Gauss_pivot(x, &r, E, ff);1241return gc_long(av, lg(x)-1 - r);1242}12431244static GEN1245gen_invimage_CUP(GEN A, GEN B, void *E, const struct bb_field *ff,1246GEN (*mul)(void*, GEN, GEN))1247{1248pari_sp av = avma;1249GEN R, Rc, C, U, P, B1, B2, C1, C2, X, Y, Z;1250long r = gen_CUP(A, &R, &C, &U, &P, E, ff, mul);1251Rc = indexcompl(R, nbrows(B));1252C1 = rowpermute(C, R);1253C2 = rowpermute(C, Rc);1254B1 = rowpermute(B, R);1255B2 = rowpermute(B, Rc);1256Z = gen_rsolve_lower_unit(C1, B1, E, ff, mul);1257if (!gequal(mul(E, C2, Z), B2))1258return NULL;1259Y = vconcat(gen_rsolve_upper(vecslice(U, 1, r), Z, E, ff, mul),1260gen_zeromat(lg(A) - 1 - r, lg(B) - 1, E, ff));1261X = rowpermute(Y, perm_inv(P));1262return gerepilecopy(av, X);1263}12641265static GEN1266gen_ker_echelon(GEN x, void *E, const struct bb_field *ff,1267GEN (*mul)(void*, GEN, GEN))1268{1269pari_sp av = avma;1270GEN R, Rc, C, C1, C2, S, K;1271long n = lg(x) - 1, r;1272r = gen_echelon(shallowtrans(x), &R, &C, E, ff, mul);1273Rc = indexcompl(R, n);1274C1 = rowpermute(C, R);1275C2 = rowpermute(C, Rc);1276S = gen_lsolve_lower_unit(C1, C2, E, ff, mul);1277K = vecpermute(shallowconcat(gen_matneg(S, E, ff), gen_matid(n - r, E, ff)),1278perm_inv(vecsmall_concat(R, Rc)));1279K = shallowtrans(K);1280return gerepilecopy(av, K);1281}12821283static GEN1284gen_deplin_echelon(GEN x, void *E, const struct bb_field *ff,1285GEN (*mul)(void*, GEN, GEN))1286{1287pari_sp av = avma;1288GEN R, Rc, C, C1, C2, s, v;1289long i, n = lg(x) - 1, r;1290r = gen_echelon(shallowtrans(x), &R, &C, E, ff, mul);1291if (r == n) return gc_NULL(av);1292Rc = indexcompl(R, n);1293i = Rc[1];1294C1 = rowpermute(C, R);1295C2 = rowslice(C, i, i);1296s = row(gen_lsolve_lower_unit(C1, C2, E, ff, mul), 1);1297settyp(s, t_COL);1298v = vecpermute(shallowconcat(gen_colneg(s, E, ff), gen_colei(n - r, 1, E, ff)),1299perm_inv(vecsmall_concat(R, Rc)));1300return gerepilecopy(av, v);1301}13021303static GEN1304gen_gauss_CUP(GEN a, GEN b, void *E, const struct bb_field *ff,1305GEN (*mul)(void*, GEN, GEN))1306{1307GEN R, C, U, P, Y;1308long n = lg(a) - 1, r;1309if (nbrows(a) < n || (r = gen_CUP(a, &R, &C, &U, &P, E, ff, mul)) < n)1310return NULL;1311Y = gen_rsolve_lower_unit(rowpermute(C, R), rowpermute(b, R), E, ff, mul);1312return rowpermute(gen_rsolve_upper(U, Y, E, ff, mul), perm_inv(P));1313}13141315static GEN1316gen_gauss(GEN a, GEN b, void *E, const struct bb_field *ff,1317GEN (*mul)(void*, GEN, GEN))1318{1319if (lg(a) - 1 >= gen_CUP_LIMIT)1320return gen_gauss_CUP(a, b, E, ff, mul);1321return gen_Gauss(a, b, E, ff);1322}13231324static GEN1325gen_ker_i(GEN x, long deplin, void *E, const struct bb_field *ff,1326GEN (*mul)(void*, GEN, GEN)) {1327if (lg(x) - 1 >= gen_CUP_LIMIT && nbrows(x) >= gen_CUP_LIMIT)1328return deplin? gen_deplin_echelon(x, E, ff, mul): gen_ker_echelon(x, E, ff, mul);1329return gen_ker(x, deplin, E, ff);1330}13311332static GEN1333gen_invimage(GEN A, GEN B, void *E, const struct bb_field *ff,1334GEN (*mul)(void*, GEN, GEN))1335{1336long nA = lg(A)-1, nB = lg(B)-1;13371338if (!nB) return cgetg(1, t_MAT);1339if (nA + nB >= gen_CUP_LIMIT && nbrows(B) >= gen_CUP_LIMIT)1340return gen_invimage_CUP(A, B, E, ff, mul);1341return gen_matinvimage(A, B, E, ff);1342}13431344/* find z such that A z = y. Return NULL if no solution */1345static GEN1346gen_matcolinvimage_i(GEN A, GEN y, void *E, const struct bb_field *ff,1347GEN (*mul)(void*, GEN, GEN))1348{1349pari_sp av = avma;1350long i, l = lg(A);1351GEN M, x, t;13521353M = gen_ker_i(shallowconcat(A, y), 0, E, ff, mul);1354i = lg(M) - 1;1355if (!i) return gc_NULL(av);13561357x = gel(M, i);1358t = gel(x, l);1359if (ff->equal0(t)) return gc_NULL(av);13601361t = ff->neg(E, ff->inv(E, t));1362setlg(x, l);1363for (i = 1; i < l; i++)1364gel(x, i) = ff->red(E, ff->mul(E, t, gel(x, i)));1365return gerepilecopy(av, x);1366}13671368static GEN1369gen_det_i(GEN a, void *E, const struct bb_field *ff,1370GEN (*mul)(void*, GEN, GEN))1371{1372if (lg(a) - 1 >= gen_CUP_LIMIT)1373return gen_det_CUP(a, E, ff, mul);1374else1375return gen_det(a, E, ff);1376}13771378static GEN1379gen_pivots(GEN x, long *rr, void *E, const struct bb_field *ff,1380GEN (*mul)(void*, GEN, GEN))1381{1382if (lg(x) - 1 >= gen_CUP_LIMIT && nbrows(x) >= gen_CUP_LIMIT)1383return gen_pivots_CUP(x, rr, E, ff, mul);1384return gen_Gauss_pivot(x, rr, E, ff);1385}13861387/* r = dim Ker x, n = nbrows(x) */1388static GEN1389gen_get_suppl(GEN x, GEN d, long n, long r, void *E, const struct bb_field *ff)1390{1391GEN y, c;1392long j, k, rx = lg(x)-1; /* != 0 due to init_suppl() */13931394if (rx == n && r == 0) return gcopy(x);1395c = zero_zv(n);1396y = cgetg(n+1, t_MAT);1397/* c = lines containing pivots (could get it from gauss_pivot, but cheap)1398* In theory r = 0 and d[j] > 0 for all j, but why take chances? */1399for (k = j = 1; j<=rx; j++)1400if (d[j]) { c[ d[j] ] = 1; gel(y,k++) = gcopy(gel(x,j)); }1401for (j=1; j<=n; j++)1402if (!c[j]) gel(y,k++) = gen_colei(n, j, E, ff);1403return y;1404}14051406static GEN1407gen_suppl(GEN x, void *E, const struct bb_field *ff,1408GEN (*mul)(void*, GEN, GEN))1409{1410GEN d;1411long n = nbrows(x), r;14121413if (lg(x) == 1) pari_err_IMPL("suppl [empty matrix]");1414d = gen_pivots(x, &r, E, ff, mul);1415return gen_get_suppl(x, d, n, r, E, ff);1416}14171418/*******************************************************************/1419/* */1420/* MATRIX MULTIPLICATION MODULO P */1421/* */1422/*******************************************************************/14231424GEN1425F2xqM_F2xqC_mul(GEN A, GEN B, GEN T) {1426void *E;1427const struct bb_field *ff = get_F2xq_field(&E, T);1428return gen_matcolmul(A, B, E, ff);1429}14301431GEN1432FlxqM_FlxqC_mul(GEN A, GEN B, GEN T, ulong p) {1433void *E;1434const struct bb_field *ff = get_Flxq_field(&E, T, p);1435return gen_matcolmul(A, B, E, ff);1436}14371438GEN1439FqM_FqC_mul(GEN A, GEN B, GEN T, GEN p) {1440void *E;1441const struct bb_field *ff = get_Fq_field(&E, T, p);1442return gen_matcolmul(A, B, E, ff);1443}14441445GEN1446F2xqM_mul(GEN A, GEN B, GEN T) {1447void *E;1448const struct bb_field *ff = get_F2xq_field(&E, T);1449return gen_matmul(A, B, E, ff);1450}14511452GEN1453FlxqM_mul(GEN A, GEN B, GEN T, ulong p) {1454void *E;1455const struct bb_field *ff;1456long n = lg(A) - 1;14571458if (n == 0)1459return cgetg(1, t_MAT);1460if (n > 1)1461return FlxqM_mul_Kronecker(A, B, T, p);1462ff = get_Flxq_field(&E, T, p);1463return gen_matmul(A, B, E, ff);1464}14651466GEN1467FqM_mul(GEN A, GEN B, GEN T, GEN p) {1468void *E;1469long n = lg(A) - 1;1470const struct bb_field *ff;1471if (n == 0)1472return cgetg(1, t_MAT);1473if (n > 1)1474return FqM_mul_Kronecker(A, B, T, p);1475ff = get_Fq_field(&E, T, p);1476return gen_matmul(A, B, E, ff);1477}14781479/*******************************************************************/1480/* */1481/* LINEAR ALGEBRA MODULO P */1482/* */1483/*******************************************************************/14841485static GEN1486_F2xqM_mul(void *E, GEN A, GEN B)1487{ return F2xqM_mul(A, B, (GEN) E); }14881489struct _Flxq {1490GEN aut;1491GEN T;1492ulong p;1493};14941495static GEN1496_FlxqM_mul(void *E, GEN A, GEN B)1497{1498struct _Flxq *D = (struct _Flxq*)E;1499return FlxqM_mul(A, B, D->T, D->p);1500}15011502static GEN1503_FpM_mul(void *E, GEN A, GEN B)1504{ return FpM_mul(A, B, (GEN) E); }15051506struct _Fq_field1507{1508GEN T, p;1509};15101511static GEN1512_FqM_mul(void *E, GEN A, GEN B)1513{1514struct _Fq_field *D = (struct _Fq_field*) E;1515return FqM_mul(A, B, D->T, D->p);1516}15171518static GEN1519FpM_init(GEN a, GEN p, ulong *pp)1520{1521if (lgefint(p) == 3)1522{1523*pp = uel(p,2);1524return (*pp==2)? ZM_to_F2m(a): ZM_to_Flm(a, *pp);1525}1526*pp = 0; return a;1527}1528GEN1529RgM_Fp_init(GEN a, GEN p, ulong *pp)1530{1531if (lgefint(p) == 3)1532{1533*pp = uel(p,2);1534return (*pp==2)? RgM_to_F2m(a): RgM_to_Flm(a, *pp);1535}1536*pp = 0; return RgM_to_FpM(a,p);1537}15381539static GEN1540FpM_det_gen(GEN a, GEN p)1541{1542void *E;1543const struct bb_field *S = get_Fp_field(&E,p);1544return gen_det_i(a, E, S, _FpM_mul);1545}1546GEN1547FpM_det(GEN a, GEN p)1548{1549pari_sp av = avma;1550ulong pp, d;1551a = FpM_init(a, p, &pp);1552switch(pp)1553{1554case 0: return FpM_det_gen(a, p);1555case 2: d = F2m_det_sp(a); break;1556default:d = Flm_det_sp(a,pp); break;1557}1558set_avma(av); return utoi(d);1559}15601561GEN1562F2xqM_det(GEN a, GEN T)1563{1564void *E;1565const struct bb_field *S = get_F2xq_field(&E, T);1566return gen_det_i(a, E, S, _F2xqM_mul);1567}15681569GEN1570FlxqM_det(GEN a, GEN T, ulong p) {1571void *E;1572const struct bb_field *S = get_Flxq_field(&E, T, p);1573return gen_det_i(a, E, S, _FlxqM_mul);1574}15751576GEN1577FqM_det(GEN x, GEN T, GEN p)1578{1579void *E;1580const struct bb_field *S = get_Fq_field(&E,T,p);1581return gen_det_i(x, E, S, _FqM_mul);1582}15831584static GEN1585FpM_gauss_pivot_gen(GEN x, GEN p, long *rr)1586{1587void *E;1588const struct bb_field *S = get_Fp_field(&E,p);1589return gen_pivots(x, rr, E, S, _FpM_mul);1590}15911592static GEN1593FpM_gauss_pivot(GEN x, GEN p, long *rr)1594{1595ulong pp;1596if (lg(x)==1) { *rr = 0; return NULL; }1597x = FpM_init(x, p, &pp);1598switch(pp)1599{1600case 0: return FpM_gauss_pivot_gen(x, p, rr);1601case 2: return F2m_gauss_pivot(x, rr);1602default:return Flm_pivots(x, pp, rr, 1);1603}1604}16051606static GEN1607F2xqM_gauss_pivot(GEN x, GEN T, long *rr)1608{1609void *E;1610const struct bb_field *S = get_F2xq_field(&E,T);1611return gen_pivots(x, rr, E, S, _F2xqM_mul);1612}16131614static GEN1615FlxqM_gauss_pivot(GEN x, GEN T, ulong p, long *rr) {1616void *E;1617const struct bb_field *S = get_Flxq_field(&E, T, p);1618return gen_pivots(x, rr, E, S, _FlxqM_mul);1619}16201621static GEN1622FqM_gauss_pivot_gen(GEN x, GEN T, GEN p, long *rr)1623{1624void *E;1625const struct bb_field *S = get_Fq_field(&E,T,p);1626return gen_pivots(x, rr, E, S, _FqM_mul);1627}1628static GEN1629FqM_gauss_pivot(GEN x, GEN T, GEN p, long *rr)1630{1631if (lg(x)==1) { *rr = 0; return NULL; }1632if (!T) return FpM_gauss_pivot(x, p, rr);1633if (lgefint(p) == 3)1634{1635pari_sp av = avma;1636ulong pp = uel(p,2);1637GEN Tp = ZXT_to_FlxT(T, pp);1638GEN d = FlxqM_gauss_pivot(ZXM_to_FlxM(x, pp, get_Flx_var(Tp)), Tp, pp, rr);1639return d ? gerepileuptoleaf(av, d): d;1640}1641return FqM_gauss_pivot_gen(x, T, p, rr);1642}16431644GEN1645FpM_image(GEN x, GEN p)1646{1647long r;1648GEN d = FpM_gauss_pivot(x,p,&r); /* d left on stack for efficiency */1649return image_from_pivot(x,d,r);1650}16511652GEN1653Flm_image(GEN x, ulong p)1654{1655long r;1656GEN d = Flm_pivots(x, p, &r, 0); /* d left on stack for efficiency */1657return image_from_pivot(x,d,r);1658}16591660GEN1661F2m_image(GEN x)1662{1663long r;1664GEN d = F2m_gauss_pivot(F2m_copy(x),&r); /* d left on stack for efficiency */1665return image_from_pivot(x,d,r);1666}16671668GEN1669F2xqM_image(GEN x, GEN T)1670{1671long r;1672GEN d = F2xqM_gauss_pivot(x,T,&r); /* d left on stack for efficiency */1673return image_from_pivot(x,d,r);1674}16751676GEN1677FlxqM_image(GEN x, GEN T, ulong p)1678{1679long r;1680GEN d = FlxqM_gauss_pivot(x, T, p, &r); /* d left on stack for efficiency */1681return image_from_pivot(x,d,r);1682}16831684GEN1685FqM_image(GEN x, GEN T, GEN p)1686{1687long r;1688GEN d = FqM_gauss_pivot(x,T,p,&r); /* d left on stack for efficiency */1689return image_from_pivot(x,d,r);1690}16911692long1693FpM_rank(GEN x, GEN p)1694{1695pari_sp av = avma;1696long r;1697(void)FpM_gauss_pivot(x,p,&r);1698return gc_long(av, lg(x)-1 - r);1699}17001701long1702F2xqM_rank(GEN x, GEN T)1703{1704pari_sp av = avma;1705long r;1706(void)F2xqM_gauss_pivot(x,T,&r);1707return gc_long(av, lg(x)-1 - r);1708}17091710long1711FlxqM_rank(GEN x, GEN T, ulong p)1712{1713void *E;1714const struct bb_field *S = get_Flxq_field(&E, T, p);1715return gen_matrank(x, E, S, _FlxqM_mul);1716}17171718long1719FqM_rank(GEN x, GEN T, GEN p)1720{1721pari_sp av = avma;1722long r;1723(void)FqM_gauss_pivot(x,T,p,&r);1724return gc_long(av, lg(x)-1 - r);1725}17261727static GEN1728FpM_invimage_gen(GEN A, GEN B, GEN p)1729{1730void *E;1731const struct bb_field *ff = get_Fp_field(&E, p);1732return gen_invimage(A, B, E, ff, _FpM_mul);1733}17341735GEN1736FpM_invimage(GEN A, GEN B, GEN p)1737{1738pari_sp av = avma;1739ulong pp;1740GEN y;17411742A = FpM_init(A, p, &pp);1743switch(pp)1744{1745case 0: return FpM_invimage_gen(A, B, p);1746case 2:1747y = F2m_invimage(A, ZM_to_F2m(B));1748if (!y) return gc_NULL(av);1749y = F2m_to_ZM(y);1750return gerepileupto(av, y);1751default:1752y = Flm_invimage_i(A, ZM_to_Flm(B, pp), pp);1753if (!y) return gc_NULL(av);1754y = Flm_to_ZM(y);1755return gerepileupto(av, y);1756}1757}17581759GEN1760F2xqM_invimage(GEN A, GEN B, GEN T) {1761void *E;1762const struct bb_field *ff = get_F2xq_field(&E, T);1763return gen_invimage(A, B, E, ff, _F2xqM_mul);1764}17651766GEN1767FlxqM_invimage(GEN A, GEN B, GEN T, ulong p) {1768void *E;1769const struct bb_field *ff = get_Flxq_field(&E, T, p);1770return gen_invimage(A, B, E, ff, _FlxqM_mul);1771}17721773GEN1774FqM_invimage(GEN A, GEN B, GEN T, GEN p) {1775void *E;1776const struct bb_field *ff = get_Fq_field(&E, T, p);1777return gen_invimage(A, B, E, ff, _FqM_mul);1778}17791780static GEN1781FpM_FpC_invimage_gen(GEN A, GEN y, GEN p)1782{1783void *E;1784const struct bb_field *ff = get_Fp_field(&E, p);1785return gen_matcolinvimage_i(A, y, E, ff, _FpM_mul);1786}17871788GEN1789FpM_FpC_invimage(GEN A, GEN x, GEN p)1790{1791pari_sp av = avma;1792ulong pp;1793GEN y;17941795A = FpM_init(A, p, &pp);1796switch(pp)1797{1798case 0: return FpM_FpC_invimage_gen(A, x, p);1799case 2:1800y = F2m_F2c_invimage(A, ZV_to_F2v(x));1801if (!y) return y;1802y = F2c_to_ZC(y);1803return gerepileupto(av, y);1804default:1805y = Flm_Flc_invimage(A, ZV_to_Flv(x, pp), pp);1806if (!y) return y;1807y = Flc_to_ZC(y);1808return gerepileupto(av, y);1809}1810}18111812GEN1813F2xqM_F2xqC_invimage(GEN A, GEN B, GEN T) {1814void *E;1815const struct bb_field *ff = get_F2xq_field(&E, T);1816return gen_matcolinvimage_i(A, B, E, ff, _F2xqM_mul);1817}18181819GEN1820FlxqM_FlxqC_invimage(GEN A, GEN B, GEN T, ulong p) {1821void *E;1822const struct bb_field *ff = get_Flxq_field(&E, T, p);1823return gen_matcolinvimage_i(A, B, E, ff, _FlxqM_mul);1824}18251826GEN1827FqM_FqC_invimage(GEN A, GEN B, GEN T, GEN p) {1828void *E;1829const struct bb_field *ff = get_Fq_field(&E, T, p);1830return gen_matcolinvimage_i(A, B, E, ff, _FqM_mul);1831}18321833static GEN1834FpM_ker_gen(GEN x, GEN p, long deplin)1835{1836void *E;1837const struct bb_field *S = get_Fp_field(&E,p);1838return gen_ker_i(x, deplin, E, S, _FpM_mul);1839}1840static GEN1841FpM_ker_i(GEN x, GEN p, long deplin)1842{1843pari_sp av = avma;1844ulong pp;1845GEN y;18461847if (lg(x)==1) return cgetg(1,t_MAT);1848x = FpM_init(x, p, &pp);1849switch(pp)1850{1851case 0: return FpM_ker_gen(x,p,deplin);1852case 2:1853y = F2m_ker_sp(x, deplin);1854if (!y) return gc_NULL(av);1855y = deplin? F2c_to_ZC(y): F2m_to_ZM(y);1856return gerepileupto(av, y);1857default:1858y = Flm_ker_sp(x, pp, deplin);1859if (!y) return gc_NULL(av);1860y = deplin? Flc_to_ZC(y): Flm_to_ZM(y);1861return gerepileupto(av, y);1862}1863}18641865GEN1866FpM_ker(GEN x, GEN p) { return FpM_ker_i(x,p,0); }18671868static GEN1869F2xqM_ker_i(GEN x, GEN T, long deplin)1870{1871const struct bb_field *ff;1872void *E;18731874if (lg(x)==1) return cgetg(1,t_MAT);1875ff = get_F2xq_field(&E,T);1876return gen_ker_i(x,deplin, E, ff, _F2xqM_mul);1877}18781879GEN1880F2xqM_ker(GEN x, GEN T)1881{1882return F2xqM_ker_i(x, T, 0);1883}18841885static GEN1886FlxqM_ker_i(GEN x, GEN T, ulong p, long deplin) {1887void *E;1888const struct bb_field *S = get_Flxq_field(&E, T, p);1889return gen_ker_i(x, deplin, E, S, _FlxqM_mul);1890}18911892GEN1893FlxqM_ker(GEN x, GEN T, ulong p)1894{1895return FlxqM_ker_i(x, T, p, 0);1896}18971898static GEN1899FqM_ker_gen(GEN x, GEN T, GEN p, long deplin)1900{1901void *E;1902const struct bb_field *S = get_Fq_field(&E,T,p);1903return gen_ker_i(x,deplin,E,S,_FqM_mul);1904}1905static GEN1906FqM_ker_i(GEN x, GEN T, GEN p, long deplin)1907{1908if (!T) return FpM_ker_i(x,p,deplin);1909if (lg(x)==1) return cgetg(1,t_MAT);19101911if (lgefint(p)==3)1912{1913pari_sp ltop=avma;1914ulong l= p[2];1915GEN Tl = ZXT_to_FlxT(T,l);1916GEN Ml = ZXM_to_FlxM(x, l, get_Flx_var(Tl));1917GEN p1 = FlxM_to_ZXM(FlxqM_ker(Ml,Tl,l));1918return gerepileupto(ltop,p1);1919}1920return FqM_ker_gen(x, T, p, deplin);1921}19221923GEN1924FqM_ker(GEN x, GEN T, GEN p) { return FqM_ker_i(x,T,p,0); }19251926GEN1927FpM_deplin(GEN x, GEN p) { return FpM_ker_i(x,p,1); }19281929GEN1930F2xqM_deplin(GEN x, GEN T)1931{1932return F2xqM_ker_i(x, T, 1);1933}19341935GEN1936FlxqM_deplin(GEN x, GEN T, ulong p)1937{1938return FlxqM_ker_i(x, T, p, 1);1939}19401941GEN1942FqM_deplin(GEN x, GEN T, GEN p) { return FqM_ker_i(x,T,p,1); }19431944static GEN1945FpM_gauss_gen(GEN a, GEN b, GEN p)1946{1947void *E;1948const struct bb_field *S = get_Fp_field(&E,p);1949return gen_gauss(a,b, E, S, _FpM_mul);1950}1951/* a an FpM, lg(a)>1; b an FpM or NULL (replace by identity) */1952static GEN1953FpM_gauss_i(GEN a, GEN b, GEN p, ulong *pp)1954{1955long n = nbrows(a);1956a = FpM_init(a,p,pp);1957switch(*pp)1958{1959case 0:1960if (!b) b = matid(n);1961return FpM_gauss_gen(a,b,p);1962case 2:1963if (b) b = ZM_to_F2m(b); else b = matid_F2m(n);1964return F2m_gauss_sp(a,b);1965default:1966if (b) b = ZM_to_Flm(b, *pp); else b = matid_Flm(n);1967return Flm_gauss_sp(a,b, NULL, *pp);1968}1969}1970GEN1971FpM_gauss(GEN a, GEN b, GEN p)1972{1973pari_sp av = avma;1974ulong pp;1975GEN u;1976if (lg(a) == 1 || lg(b)==1) return cgetg(1, t_MAT);1977u = FpM_gauss_i(a, b, p, &pp);1978if (!u) return gc_NULL(av);1979switch(pp)1980{1981case 0: return gerepilecopy(av, u);1982case 2: u = F2m_to_ZM(u); break;1983default: u = Flm_to_ZM(u); break;1984}1985return gerepileupto(av, u);1986}19871988static GEN1989F2xqM_gauss_gen(GEN a, GEN b, GEN T)1990{1991void *E;1992const struct bb_field *S = get_F2xq_field(&E, T);1993return gen_gauss(a, b, E, S, _F2xqM_mul);1994}19951996GEN1997F2xqM_gauss(GEN a, GEN b, GEN T)1998{1999pari_sp av = avma;2000long n = lg(a)-1;2001GEN u;2002if (!n || lg(b)==1) { set_avma(av); return cgetg(1, t_MAT); }2003u = F2xqM_gauss_gen(a, b, T);2004if (!u) return gc_NULL(av);2005return gerepilecopy(av, u);2006}20072008static GEN2009FlxqM_gauss_i(GEN a, GEN b, GEN T, ulong p) {2010void *E;2011const struct bb_field *S = get_Flxq_field(&E, T, p);2012return gen_gauss(a, b, E, S, _FlxqM_mul);2013}20142015GEN2016FlxqM_gauss(GEN a, GEN b, GEN T, ulong p)2017{2018pari_sp av = avma;2019long n = lg(a)-1;2020GEN u;2021if (!n || lg(b)==1) { set_avma(av); return cgetg(1, t_MAT); }2022u = FlxqM_gauss_i(a, b, T, p);2023if (!u) return gc_NULL(av);2024return gerepilecopy(av, u);2025}20262027static GEN2028FqM_gauss_gen(GEN a, GEN b, GEN T, GEN p)2029{2030void *E;2031const struct bb_field *S = get_Fq_field(&E,T,p);2032return gen_gauss(a,b,E,S,_FqM_mul);2033}2034GEN2035FqM_gauss(GEN a, GEN b, GEN T, GEN p)2036{2037pari_sp av = avma;2038GEN u;2039long n;2040if (!T) return FpM_gauss(a,b,p);2041n = lg(a)-1; if (!n || lg(b)==1) return cgetg(1, t_MAT);2042u = FqM_gauss_gen(a,b,T,p);2043if (!u) return gc_NULL(av);2044return gerepilecopy(av, u);2045}20462047GEN2048FpM_FpC_gauss(GEN a, GEN b, GEN p)2049{2050pari_sp av = avma;2051ulong pp;2052GEN u;2053if (lg(a) == 1) return cgetg(1, t_COL);2054u = FpM_gauss_i(a, mkmat(b), p, &pp);2055if (!u) return gc_NULL(av);2056switch(pp)2057{2058case 0: return gerepilecopy(av, gel(u,1));2059case 2: u = F2c_to_ZC(gel(u,1)); break;2060default: u = Flc_to_ZC(gel(u,1)); break;2061}2062return gerepileupto(av, u);2063}20642065GEN2066F2xqM_F2xqC_gauss(GEN a, GEN b, GEN T)2067{2068pari_sp av = avma;2069GEN u;2070if (lg(a) == 1) return cgetg(1, t_COL);2071u = F2xqM_gauss_gen(a, mkmat(b), T);2072if (!u) return gc_NULL(av);2073return gerepilecopy(av, gel(u,1));2074}20752076GEN2077FlxqM_FlxqC_gauss(GEN a, GEN b, GEN T, ulong p)2078{2079pari_sp av = avma;2080GEN u;2081if (lg(a) == 1) return cgetg(1, t_COL);2082u = FlxqM_gauss_i(a, mkmat(b), T, p);2083if (!u) return gc_NULL(av);2084return gerepilecopy(av, gel(u,1));2085}20862087GEN2088FqM_FqC_gauss(GEN a, GEN b, GEN T, GEN p)2089{2090pari_sp av = avma;2091GEN u;2092if (!T) return FpM_FpC_gauss(a,b,p);2093if (lg(a) == 1) return cgetg(1, t_COL);2094u = FqM_gauss_gen(a,mkmat(b),T,p);2095if (!u) return gc_NULL(av);2096return gerepilecopy(av, gel(u,1));2097}20982099GEN2100FpM_inv(GEN a, GEN p)2101{2102pari_sp av = avma;2103ulong pp;2104GEN u;2105if (lg(a) == 1) return cgetg(1, t_MAT);2106u = FpM_gauss_i(a, NULL, p, &pp);2107if (!u) return gc_NULL(av);2108switch(pp)2109{2110case 0: return gerepilecopy(av, u);2111case 2: u = F2m_to_ZM(u); break;2112default: u = Flm_to_ZM(u); break;2113}2114return gerepileupto(av, u);2115}21162117GEN2118F2xqM_inv(GEN a, GEN T)2119{2120pari_sp av = avma;2121GEN u;2122if (lg(a) == 1) { set_avma(av); return cgetg(1, t_MAT); }2123u = F2xqM_gauss_gen(a, matid_F2xqM(nbrows(a),T), T);2124if (!u) return gc_NULL(av);2125return gerepilecopy(av, u);2126}21272128GEN2129FlxqM_inv(GEN a, GEN T, ulong p)2130{2131pari_sp av = avma;2132GEN u;2133if (lg(a) == 1) { set_avma(av); return cgetg(1, t_MAT); }2134u = FlxqM_gauss_i(a, matid_FlxqM(nbrows(a),T,p), T,p);2135if (!u) return gc_NULL(av);2136return gerepilecopy(av, u);2137}21382139GEN2140FqM_inv(GEN a, GEN T, GEN p)2141{2142pari_sp av = avma;2143GEN u;2144if (!T) return FpM_inv(a,p);2145if (lg(a) == 1) return cgetg(1, t_MAT);2146u = FqM_gauss_gen(a,matid(nbrows(a)),T,p);2147if (!u) return gc_NULL(av);2148return gerepilecopy(av, u);2149}21502151GEN2152FpM_intersect_i(GEN x, GEN y, GEN p)2153{2154long j, lx = lg(x);2155GEN z;21562157if (lx == 1 || lg(y) == 1) return cgetg(1,t_MAT);2158if (lgefint(p) == 3)2159{2160ulong pp = p[2];2161return Flm_to_ZM(Flm_intersect_i(ZM_to_Flm(x,pp), ZM_to_Flm(y,pp), pp));2162}2163z = FpM_ker(shallowconcat(x,y), p);2164for (j=lg(z)-1; j; j--) setlg(gel(z,j),lx);2165return FpM_mul(x,z,p);2166}2167GEN2168FpM_intersect(GEN x, GEN y, GEN p)2169{2170pari_sp av = avma;2171GEN z;2172if (lgefint(p) == 3)2173{2174ulong pp = p[2];2175z = Flm_image(Flm_intersect_i(ZM_to_Flm(x,pp), ZM_to_Flm(y,pp), pp), pp);2176}2177else2178z = FpM_image(FpM_intersect_i(x,y,p), p);2179return gerepileupto(av, z);2180}21812182static void2183init_suppl(GEN x)2184{2185if (lg(x) == 1) pari_err_IMPL("suppl [empty matrix]");2186/* HACK: avoid overwriting d from gauss_pivot() after set_avma(av) */2187(void)new_chunk(lgcols(x) * 2);2188}21892190GEN2191FpM_suppl(GEN x, GEN p)2192{2193GEN d;2194long r;2195init_suppl(x); d = FpM_gauss_pivot(x,p, &r);2196return get_suppl(x,d,nbrows(x),r,&col_ei);2197}21982199GEN2200F2m_suppl(GEN x)2201{2202GEN d;2203long r;2204init_suppl(x); d = F2m_gauss_pivot(F2m_copy(x), &r);2205return get_suppl(x,d,mael(x,1,1),r,&F2v_ei);2206}22072208GEN2209Flm_suppl(GEN x, ulong p)2210{2211GEN d;2212long r;2213init_suppl(x); d = Flm_pivots(x, p, &r, 0);2214return get_suppl(x,d,nbrows(x),r,&vecsmall_ei);2215}22162217GEN2218F2xqM_suppl(GEN x, GEN T)2219{2220void *E;2221const struct bb_field *S = get_F2xq_field(&E, T);2222return gen_suppl(x, E, S, _F2xqM_mul);2223}22242225GEN2226FlxqM_suppl(GEN x, GEN T, ulong p)2227{2228void *E;2229const struct bb_field *S = get_Flxq_field(&E, T, p);2230return gen_suppl(x, E, S, _FlxqM_mul);2231}22322233GEN2234FqM_suppl(GEN x, GEN T, GEN p)2235{2236pari_sp av = avma;2237GEN d;2238long r;22392240if (!T) return FpM_suppl(x,p);2241init_suppl(x);2242d = FqM_gauss_pivot(x,T,p,&r);2243set_avma(av); return get_suppl(x,d,nbrows(x),r,&col_ei);2244}22452246static void2247init_indexrank(GEN x) {2248(void)new_chunk(3 + 2*lg(x)); /* HACK */2249}22502251GEN2252FpM_indexrank(GEN x, GEN p) {2253pari_sp av = avma;2254long r;2255GEN d;2256init_indexrank(x);2257d = FpM_gauss_pivot(x,p,&r);2258set_avma(av); return indexrank0(lg(x)-1, r, d);2259}22602261GEN2262Flm_indexrank(GEN x, ulong p) {2263pari_sp av = avma;2264long r;2265GEN d;2266init_indexrank(x);2267d = Flm_pivots(x, p, &r, 0);2268set_avma(av); return indexrank0(lg(x)-1, r, d);2269}22702271GEN2272F2m_indexrank(GEN x) {2273pari_sp av = avma;2274long r;2275GEN d;2276init_indexrank(x);2277d = F2m_gauss_pivot(F2m_copy(x),&r);2278set_avma(av); return indexrank0(lg(x)-1, r, d);2279}22802281GEN2282F2xqM_indexrank(GEN x, GEN T) {2283pari_sp av = avma;2284long r;2285GEN d;2286init_indexrank(x);2287d = F2xqM_gauss_pivot(x, T, &r);2288set_avma(av); return indexrank0(lg(x) - 1, r, d);2289}22902291GEN2292FlxqM_indexrank(GEN x, GEN T, ulong p) {2293pari_sp av = avma;2294long r;2295GEN d;2296init_indexrank(x);2297d = FlxqM_gauss_pivot(x, T, p, &r);2298set_avma(av); return indexrank0(lg(x) - 1, r, d);2299}23002301GEN2302FqM_indexrank(GEN x, GEN T, GEN p) {2303pari_sp av = avma;2304long r;2305GEN d;2306init_indexrank(x);2307d = FqM_gauss_pivot(x, T, p, &r);2308set_avma(av); return indexrank0(lg(x) - 1, r, d);2309}23102311/*******************************************************************/2312/* */2313/* Solve A*X=B (Gauss pivot) */2314/* */2315/*******************************************************************/2316/* x ~ 0 compared to reference y */2317int2318approx_0(GEN x, GEN y)2319{2320long tx = typ(x);2321if (tx == t_COMPLEX)2322return approx_0(gel(x,1), y) && approx_0(gel(x,2), y);2323return gequal0(x) ||2324(tx == t_REAL && gexpo(y) - gexpo(x) > bit_prec(x));2325}2326/* x a column, x0 same column in the original input matrix (for reference),2327* c list of pivots so far */2328static long2329gauss_get_pivot_max(GEN X, GEN X0, long ix, GEN c)2330{2331GEN p, r, x = gel(X,ix), x0 = gel(X0,ix);2332long i, k = 0, ex = - (long)HIGHEXPOBIT, lx = lg(x);2333if (c)2334{2335for (i=1; i<lx; i++)2336if (!c[i])2337{2338long e = gexpo(gel(x,i));2339if (e > ex) { ex = e; k = i; }2340}2341}2342else2343{2344for (i=ix; i<lx; i++)2345{2346long e = gexpo(gel(x,i));2347if (e > ex) { ex = e; k = i; }2348}2349}2350if (!k) return lx;2351p = gel(x,k);2352r = gel(x0,k); if (isrationalzero(r)) r = x0;2353return approx_0(p, r)? lx: k;2354}2355static long2356gauss_get_pivot_padic(GEN X, GEN p, long ix, GEN c)2357{2358GEN x = gel(X, ix);2359long i, k = 0, ex = (long)HIGHVALPBIT, lx = lg(x);2360if (c)2361{2362for (i=1; i<lx; i++)2363if (!c[i] && !gequal0(gel(x,i)))2364{2365long e = gvaluation(gel(x,i), p);2366if (e < ex) { ex = e; k = i; }2367}2368}2369else2370{2371for (i=ix; i<lx; i++)2372if (!gequal0(gel(x,i)))2373{2374long e = gvaluation(gel(x,i), p);2375if (e < ex) { ex = e; k = i; }2376}2377}2378return k? k: lx;2379}2380static long2381gauss_get_pivot_NZ(GEN X, GEN x0/*unused*/, long ix, GEN c)2382{2383GEN x = gel(X, ix);2384long i, lx = lg(x);2385(void)x0;2386if (c)2387{2388for (i=1; i<lx; i++)2389if (!c[i] && !gequal0(gel(x,i))) return i;2390}2391else2392{2393for (i=ix; i<lx; i++)2394if (!gequal0(gel(x,i))) return i;2395}2396return lx;2397}23982399/* Return pivot seeking function appropriate for the domain of the RgM x2400* (first non zero pivot, maximal pivot...)2401* x0 is a reference point used when guessing whether x[i,j] ~ 02402* (iff x[i,j] << x0[i,j]); typical case: mateigen, Gauss pivot on x - vp.Id,2403* but use original x when deciding whether a prospective pivot is nonzero */2404static pivot_fun2405get_pivot_fun(GEN x, GEN x0, GEN *data)2406{2407long i, j, hx, lx = lg(x);2408int res = t_INT;2409GEN p = NULL;24102411*data = NULL;2412if (lx == 1) return &gauss_get_pivot_NZ;2413hx = lgcols(x);2414for (j=1; j<lx; j++)2415{2416GEN xj = gel(x,j);2417for (i=1; i<hx; i++)2418{2419GEN c = gel(xj,i);2420switch(typ(c))2421{2422case t_REAL:2423res = t_REAL;2424break;2425case t_COMPLEX:2426if (typ(gel(c,1)) == t_REAL || typ(gel(c,2)) == t_REAL) res = t_REAL;2427break;2428case t_INT: case t_INTMOD: case t_FRAC: case t_FFELT: case t_QUAD:2429case t_POLMOD: /* exact types */2430break;2431case t_PADIC:2432p = gel(c,2);2433res = t_PADIC;2434break;2435default: return &gauss_get_pivot_NZ;2436}2437}2438}2439switch(res)2440{2441case t_REAL: *data = x0; return &gauss_get_pivot_max;2442case t_PADIC: *data = p; return &gauss_get_pivot_padic;2443default: return &gauss_get_pivot_NZ;2444}2445}24462447static GEN2448get_col(GEN a, GEN b, GEN p, long li)2449{2450GEN u = cgetg(li+1,t_COL);2451long i, j;24522453gel(u,li) = gdiv(gel(b,li), p);2454for (i=li-1; i>0; i--)2455{2456pari_sp av = avma;2457GEN m = gel(b,i);2458for (j=i+1; j<=li; j++) m = gsub(m, gmul(gcoeff(a,i,j), gel(u,j)));2459gel(u,i) = gerepileupto(av, gdiv(m, gcoeff(a,i,i)));2460}2461return u;2462}24632464/* bk -= m * bi */2465static void2466_submul(GEN b, long k, long i, GEN m)2467{2468gel(b,k) = gsub(gel(b,k), gmul(m, gel(b,i)));2469}2470static int2471init_gauss(GEN a, GEN *b, long *aco, long *li, int *iscol)2472{2473*iscol = *b ? (typ(*b) == t_COL): 0;2474*aco = lg(a) - 1;2475if (!*aco) /* a empty */2476{2477if (*b && lg(*b) != 1) pari_err_DIM("gauss");2478*li = 0; return 0;2479}2480*li = nbrows(a);2481if (*li < *aco) pari_err_INV("gauss [no left inverse]", a);2482if (*b)2483{2484switch(typ(*b))2485{2486case t_MAT:2487if (lg(*b) == 1) return 0;2488*b = RgM_shallowcopy(*b);2489break;2490case t_COL:2491*b = mkmat( leafcopy(*b) );2492break;2493default: pari_err_TYPE("gauss",*b);2494}2495if (nbrows(*b) != *li) pari_err_DIM("gauss");2496}2497else2498*b = matid(*li);2499return 1;2500}25012502static GEN2503RgM_inv_FpM(GEN a, GEN p)2504{2505ulong pp;2506a = RgM_Fp_init(a, p, &pp);2507switch(pp)2508{2509case 0:2510a = FpM_inv(a,p);2511if (a) a = FpM_to_mod(a, p);2512break;2513case 2:2514a = F2m_inv(a);2515if (a) a = F2m_to_mod(a);2516break;2517default:2518a = Flm_inv_sp(a, NULL, pp);2519if (a) a = Flm_to_mod(a, pp);2520}2521return a;2522}25232524static GEN2525RgM_inv_FqM(GEN x, GEN pol, GEN p)2526{2527pari_sp av = avma;2528GEN b, T = RgX_to_FpX(pol, p);2529if (signe(T) == 0) pari_err_OP("^",x,gen_m1);2530b = FqM_inv(RgM_to_FqM(x, T, p), T, p);2531if (!b) return gc_NULL(av);2532return gerepileupto(av, FqM_to_mod(b, T, p));2533}25342535#define code(t1,t2) ((t1 << 6) | t2)2536static GEN2537RgM_inv_fast(GEN x)2538{2539GEN p, pol;2540long pa;2541long t = RgM_type(x, &p,&pol,&pa);2542switch(t)2543{2544case t_INT: /* Fall back */2545case t_FRAC: return QM_inv(x);2546case t_FFELT: return FFM_inv(x, pol);2547case t_INTMOD: return RgM_inv_FpM(x, p);2548case code(t_POLMOD, t_INTMOD):2549return RgM_inv_FqM(x, pol, p);2550default: return gen_0;2551}2552}2553#undef code25542555static GEN2556RgM_RgC_solve_FpC(GEN a, GEN b, GEN p)2557{2558pari_sp av = avma;2559ulong pp;2560a = RgM_Fp_init(a, p, &pp);2561switch(pp)2562{2563case 0:2564b = RgC_to_FpC(b, p);2565a = FpM_FpC_gauss(a,b,p);2566return a ? gerepileupto(av, FpC_to_mod(a, p)): NULL;2567case 2:2568b = RgV_to_F2v(b);2569a = F2m_F2c_gauss(a,b);2570return a ? gerepileupto(av, F2c_to_mod(a)): NULL;2571default:2572b = RgV_to_Flv(b, pp);2573a = Flm_Flc_gauss(a, b, pp);2574return a ? gerepileupto(av, Flc_to_mod(a, pp)): NULL;2575}2576}25772578static GEN2579RgM_solve_FpM(GEN a, GEN b, GEN p)2580{2581pari_sp av = avma;2582ulong pp;2583a = RgM_Fp_init(a, p, &pp);2584switch(pp)2585{2586case 0:2587b = RgM_to_FpM(b, p);2588a = FpM_gauss(a,b,p);2589return a ? gerepileupto(av, FpM_to_mod(a, p)): NULL;2590case 2:2591b = RgM_to_F2m(b);2592a = F2m_gauss(a,b);2593return a ? gerepileupto(av, F2m_to_mod(a)): NULL;2594default:2595b = RgM_to_Flm(b, pp);2596a = Flm_gauss(a,b,pp);2597return a ? gerepileupto(av, Flm_to_mod(a, pp)): NULL;2598}2599}26002601/* Gaussan Elimination. If a is square, return a^(-1)*b;2602* if a has more rows than columns and b is NULL, return c such that c a = Id.2603* a is a (not necessarily square) matrix2604* b is a matrix or column vector, NULL meaning: take the identity matrix,2605* effectively returning the inverse of a2606* If a and b are empty, the result is the empty matrix.2607*2608* li: number of rows of a and b2609* aco: number of columns of a2610* bco: number of columns of b (if matrix)2611*/2612static GEN2613RgM_solve_basecase(GEN a, GEN b)2614{2615pari_sp av = avma;2616long i, j, k, li, bco, aco;2617int iscol;2618pivot_fun pivot;2619GEN p, u, data;26202621set_avma(av);26222623if (lg(a)-1 == 2 && nbrows(a) == 2) {2624/* 2x2 matrix, start by inverting a */2625GEN u = gcoeff(a,1,1), v = gcoeff(a,1,2);2626GEN w = gcoeff(a,2,1), x = gcoeff(a,2,2);2627GEN D = gsub(gmul(u,x), gmul(v,w)), ainv;2628if (gequal0(D)) return NULL;2629ainv = mkmat2(mkcol2(x, gneg(w)), mkcol2(gneg(v), u));2630ainv = gmul(ainv, ginv(D));2631if (b) ainv = gmul(ainv, b);2632return gerepileupto(av, ainv);2633}26342635if (!init_gauss(a, &b, &aco, &li, &iscol)) return cgetg(1, iscol?t_COL:t_MAT);2636pivot = get_pivot_fun(a, a, &data);2637a = RgM_shallowcopy(a);2638bco = lg(b)-1;2639if(DEBUGLEVEL>4) err_printf("Entering gauss\n");26402641p = NULL; /* gcc -Wall */2642for (i=1; i<=aco; i++)2643{2644/* k is the line where we find the pivot */2645k = pivot(a, data, i, NULL);2646if (k > li) return NULL;2647if (k != i)2648{ /* exchange the lines s.t. k = i */2649for (j=i; j<=aco; j++) swap(gcoeff(a,i,j), gcoeff(a,k,j));2650for (j=1; j<=bco; j++) swap(gcoeff(b,i,j), gcoeff(b,k,j));2651}2652p = gcoeff(a,i,i);2653if (i == aco) break;26542655for (k=i+1; k<=li; k++)2656{2657GEN m = gcoeff(a,k,i);2658if (!gequal0(m))2659{2660m = gdiv(m,p);2661for (j=i+1; j<=aco; j++) _submul(gel(a,j),k,i,m);2662for (j=1; j<=bco; j++) _submul(gel(b,j),k,i,m);2663}2664}2665if (gc_needed(av,1))2666{2667if(DEBUGMEM>1) pari_warn(warnmem,"gauss. i=%ld",i);2668gerepileall(av,2, &a,&b);2669}2670}26712672if(DEBUGLEVEL>4) err_printf("Solving the triangular system\n");2673u = cgetg(bco+1,t_MAT);2674for (j=1; j<=bco; j++) gel(u,j) = get_col(a,gel(b,j),p,aco);2675return gerepilecopy(av, iscol? gel(u,1): u);2676}26772678static GEN2679RgM_RgC_solve_fast(GEN x, GEN y)2680{2681GEN p, pol;2682long pa;2683long t = RgM_RgC_type(x, y, &p,&pol,&pa);2684switch(t)2685{2686case t_INT: return ZM_gauss(x, y);2687case t_FRAC: return QM_gauss(x, y);2688case t_INTMOD: return RgM_RgC_solve_FpC(x, y, p);2689case t_FFELT: return FFM_FFC_gauss(x, y, pol);2690default: return gen_0;2691}2692}26932694static GEN2695RgM_solve_fast(GEN x, GEN y)2696{2697GEN p, pol;2698long pa;2699long t = RgM_type2(x, y, &p,&pol,&pa);2700switch(t)2701{2702case t_INT: return ZM_gauss(x, y);2703case t_FRAC: return QM_gauss(x, y);2704case t_INTMOD: return RgM_solve_FpM(x, y, p);2705case t_FFELT: return FFM_gauss(x, y, pol);2706default: return gen_0;2707}2708}27092710GEN2711RgM_solve(GEN a, GEN b)2712{2713pari_sp av = avma;2714GEN u;2715if (!b) return RgM_inv(a);2716u = typ(b)==t_MAT ? RgM_solve_fast(a, b): RgM_RgC_solve_fast(a, b);2717if (!u) return gc_NULL(av);2718if (u != gen_0) return u;2719return RgM_solve_basecase(a, b);2720}27212722GEN2723RgM_inv(GEN a)2724{2725GEN b = RgM_inv_fast(a);2726return b==gen_0? RgM_solve_basecase(a, NULL): b;2727}27282729/* assume dim A >= 1, A invertible + upper triangular */2730static GEN2731RgM_inv_upper_ind(GEN A, long index)2732{2733long n = lg(A)-1, i = index, j;2734GEN u = zerocol(n);2735gel(u,i) = ginv(gcoeff(A,i,i));2736for (i--; i>0; i--)2737{2738pari_sp av = avma;2739GEN m = gneg(gmul(gcoeff(A,i,i+1),gel(u,i+1))); /* j = i+1 */2740for (j=i+2; j<=n; j++) m = gsub(m, gmul(gcoeff(A,i,j),gel(u,j)));2741gel(u,i) = gerepileupto(av, gdiv(m, gcoeff(A,i,i)));2742}2743return u;2744}2745GEN2746RgM_inv_upper(GEN A)2747{2748long i, l;2749GEN B = cgetg_copy(A, &l);2750for (i = 1; i < l; i++) gel(B,i) = RgM_inv_upper_ind(A, i);2751return B;2752}27532754static GEN2755split_realimag_col(GEN z, long r1, long r2)2756{2757long i, ru = r1+r2;2758GEN x = cgetg(ru+r2+1,t_COL), y = x + r2;2759for (i=1; i<=r1; i++) {2760GEN a = gel(z,i);2761if (typ(a) == t_COMPLEX) a = gel(a,1); /* paranoia: a should be real */2762gel(x,i) = a;2763}2764for ( ; i<=ru; i++) {2765GEN b, a = gel(z,i);2766if (typ(a) == t_COMPLEX) { b = gel(a,2); a = gel(a,1); } else b = gen_0;2767gel(x,i) = a;2768gel(y,i) = b;2769}2770return x;2771}2772GEN2773split_realimag(GEN x, long r1, long r2)2774{2775long i,l; GEN y;2776if (typ(x) == t_COL) return split_realimag_col(x,r1,r2);2777y = cgetg_copy(x, &l);2778for (i=1; i<l; i++) gel(y,i) = split_realimag_col(gel(x,i), r1, r2);2779return y;2780}27812782/* assume M = (r1+r2) x (r1+2r2) matrix and y compatible vector or matrix2783* r1 first lines of M,y are real. Solve the system obtained by splitting2784* real and imaginary parts. */2785GEN2786RgM_solve_realimag(GEN M, GEN y)2787{2788long l = lg(M), r2 = l - lgcols(M), r1 = l-1 - 2*r2;2789return RgM_solve(split_realimag(M, r1,r2),2790split_realimag(y, r1,r2));2791}27922793GEN2794gauss(GEN a, GEN b)2795{2796GEN z;2797long t = typ(b);2798if (typ(a)!=t_MAT) pari_err_TYPE("gauss",a);2799if (t!=t_COL && t!=t_MAT) pari_err_TYPE("gauss",b);2800z = RgM_solve(a,b);2801if (!z) pari_err_INV("gauss",a);2802return z;2803}28042805static GEN2806ZlM_gauss_ratlift(GEN a, GEN b, ulong p, long e, GEN C)2807{2808pari_sp av = avma, av2;2809GEN bb, xi, xb, pi, q, B, r;2810long i, f, k;2811ulong mask;2812if (!C) {2813C = Flm_inv(ZM_to_Flm(a, p), p);2814if (!C) pari_err_INV("ZlM_gauss", a);2815}2816k = f = ZM_max_lg(a)-1;2817mask = quadratic_prec_mask((e+f-1)/f);2818pi = q = powuu(p, f);2819bb = b;2820C = ZpM_invlift(FpM_red(a, q), Flm_to_ZM(C), utoipos(p), f);2821av2 = avma;2822xb = xi = FpM_mul(C, b, q);2823for (i = f; i <= e; i+=f)2824{2825if (i==k)2826{2827k = (mask&1UL) ? 2*k-f: 2*k;2828mask >>= 1;2829B = sqrti(shifti(pi,-1));2830r = FpM_ratlift(xb, pi, B, B, NULL);2831if (r)2832{2833GEN dr, nr = Q_remove_denom(r,&dr);2834if (ZM_equal(ZM_mul(a,nr), dr? ZM_Z_mul(b,dr): b))2835{2836if (DEBUGLEVEL>=4)2837err_printf("ZlM_gauss: early solution: %ld/%ld\n",i,e);2838return gerepilecopy(av, r);2839}2840}2841}2842bb = ZM_Z_divexact(ZM_sub(bb, ZM_mul(a, xi)), q);2843if (gc_needed(av,2))2844{2845if(DEBUGMEM>1) pari_warn(warnmem,"ZlM_gauss. i=%ld/%ld",i,e);2846gerepileall(av2,3, &pi,&bb,&xb);2847}2848xi = FpM_mul(C, bb, q);2849xb = ZM_add(xb, ZM_Z_mul(xi, pi));2850pi = mulii(pi, q);2851}2852B = sqrti(shifti(pi,-1));2853return gerepileupto(av, FpM_ratlift(xb, pi, B, B, NULL));2854}28552856/* Dixon p-adic lifting algorithm.2857* Numer. Math. 40, 137-141 (1982), DOI: 10.1007/BF01459082 */2858GEN2859ZM_gauss(GEN a, GEN b0)2860{2861pari_sp av = avma, av2;2862int iscol;2863long n, ncol, i, m, elim;2864ulong p;2865GEN C, delta, nb, nmin, res, b = b0;2866forprime_t S;28672868if (!init_gauss(a, &b, &n, &ncol, &iscol)) return cgetg(1, iscol?t_COL:t_MAT);2869nb = gen_0; ncol = lg(b);2870for (i = 1; i < ncol; i++)2871{2872GEN ni = gnorml2(gel(b, i));2873if (cmpii(nb, ni) < 0) nb = ni;2874}2875if (!signe(nb)) {set_avma(av); return iscol? zerocol(n): zeromat(n,lg(b)-1);}2876delta = gen_1; nmin = nb;2877for (i = 1; i <= n; i++)2878{2879GEN ni = gnorml2(gel(a, i));2880if (cmpii(ni, nmin) < 0)2881{2882delta = mulii(delta, nmin); nmin = ni;2883}2884else2885delta = mulii(delta, ni);2886}2887if (!signe(nmin)) return NULL;2888elim = expi(delta)+1;2889av2 = avma;2890init_modular_big(&S);2891for(;;)2892{2893p = u_forprime_next(&S);2894C = Flm_inv_sp(ZM_to_Flm(a, p), NULL, p);2895if (C) break;2896elim -= expu(p);2897if (elim < 0) return NULL;2898set_avma(av2);2899}2900/* N.B. Our delta/lambda are SQUARES of those in the paper2901* log(delta lambda) / log p, where lambda is 3+sqrt(5) / 2,2902* whose log is < 1, hence + 1 (to cater for rounding errors) */2903m = (long)ceil((dbllog2(delta)*M_LN2 + 1) / log((double)p));2904res = ZlM_gauss_ratlift(a, b, p, m, C);2905if (iscol) return gerepilecopy(av, gel(res, 1));2906return gerepileupto(av, res);2907}29082909/* #C = n, C[z[i]] = K[i], complete by 0s */2910static GEN2911RgC_inflate(GEN K, GEN z, long n)2912{2913GEN c = zerocol(n);2914long j, l = lg(K);2915for (j = 1; j < l; j++) gel(c, z[j]) = gel(K, j);2916return c;2917}2918/* in place: C[i] *= cB / v[i] */2919static void2920QC_normalize(GEN C, GEN v, GEN cB)2921{2922long l = lg(C), i;2923for (i = 1; i < l; i++)2924{2925GEN c = cB, k = gel(C,i), d = gel(v,i);2926if (d)2927{2928if (isintzero(d)) { gel(C,i) = gen_0; continue; }2929c = div_content(c, d);2930}2931gel(C,i) = c? gmul(k,c): k;2932}2933}29342935/* same as above, M rational; if flag = 1, call indexrank and return 1 sol */2936GEN2937QM_gauss_i(GEN M, GEN B, long flag)2938{2939pari_sp av = avma;2940long i, l, n;2941int col = typ(B) == t_COL;2942GEN K, cB, N = cgetg_copy(M, &l), v = cgetg(l, t_VEC), z2 = NULL;29432944for (i = 1; i < l; i++)2945gel(N,i) = Q_primitive_part(gel(M,i), &gel(v,i));2946if (flag)2947{2948GEN z = ZM_indexrank(N), z1 = gel(z,1);2949z2 = gel(z,2);2950N = shallowmatextract(N, z1, z2);2951B = col? vecpermute(B,z1): rowpermute(B,z1);2952if (lg(z2) == l) z2 = NULL; else v = vecpermute(v, z2);2953}2954B = Q_primitive_part(B, &cB);2955K = ZM_gauss(N, B); if (!K) return gc_NULL(av);2956n = l - 1;2957if (col)2958{2959QC_normalize(K, v, cB);2960if (z2) K = RgC_inflate(K, z2, n);2961}2962else2963{2964long lK = lg(K);2965for (i = 1; i < lK; i++)2966{2967QC_normalize(gel(K,i), v, cB);2968if (z2) gel(K,i) = RgC_inflate(gel(K,i), z2, n);2969}2970}2971return gerepilecopy(av, K);2972}2973GEN2974QM_gauss(GEN M, GEN B) { return QM_gauss_i(M, B, 0); }29752976static GEN2977ZM_inv_slice(GEN A, GEN P, GEN *mod)2978{2979pari_sp av = avma;2980long i, n = lg(P)-1;2981GEN H, T;2982if (n == 1)2983{2984ulong p = uel(P,1);2985GEN Hp, a = ZM_to_Flm(A, p);2986Hp = Flm_adjoint(a, p);2987Hp = gerepileupto(av, Flm_to_ZM(Hp));2988*mod = utoipos(p); return Hp;2989}2990T = ZV_producttree(P);2991A = ZM_nv_mod_tree(A, P, T);2992H = cgetg(n+1, t_VEC);2993for(i=1; i <= n; i++)2994gel(H,i) = Flm_adjoint(gel(A, i), uel(P,i));2995H = nmV_chinese_center_tree_seq(H, P, T, ZV_chinesetree(P,T));2996*mod = gmael(T, lg(T)-1, 1);2997gerepileall(av, 2, &H, mod);2998return H;2999}30003001static GEN3002RgM_true_Hadamard(GEN a)3003{3004pari_sp av = avma;3005long n = lg(a)-1, i;3006GEN B;3007if (n == 0) return gen_1;3008a = RgM_gtofp(a, LOWDEFAULTPREC);3009B = gnorml2(gel(a,1));3010for (i = 2; i <= n; i++) B = gmul(B, gnorml2(gel(a,i)));3011return gerepileuptoint(av, ceil_safe(sqrtr(B)));3012}30133014GEN3015ZM_inv_worker(GEN P, GEN A)3016{3017GEN V = cgetg(3, t_VEC);3018gel(V,1) = ZM_inv_slice(A, P, &gel(V,2));3019return V;3020}30213022static GEN3023ZM_inv0(GEN A, GEN *pden)3024{3025if (pden) *pden = gen_1;3026(void)A; return cgetg(1, t_MAT);3027}3028static GEN3029ZM_inv1(GEN A, GEN *pden)3030{3031GEN a = gcoeff(A,1,1);3032long s = signe(a);3033if (!s) return NULL;3034if (pden) *pden = absi(a);3035retmkmat(mkcol(s == 1? gen_1: gen_m1));3036}3037static GEN3038ZM_inv2(GEN A, GEN *pden)3039{3040GEN a, b, c, d, D, cA;3041long s;3042A = Q_primitive_part(A, &cA);3043a = gcoeff(A,1,1); b = gcoeff(A,1,2);3044c = gcoeff(A,2,1); d = gcoeff(A,2,2);3045D = subii(mulii(a,d), mulii(b,c)); /* left on stack */3046s = signe(D);3047if (!s) return NULL;3048if (s < 0) D = negi(D);3049if (pden) *pden = mul_denom(D, cA);3050if (s > 0)3051retmkmat2(mkcol2(icopy(d), negi(c)), mkcol2(negi(b), icopy(a)));3052else3053retmkmat2(mkcol2(negi(d), icopy(c)), mkcol2(icopy(b), negi(a)));3054}30553056/* to be used when denom(M^(-1)) << det(M) and a sharp multiple is3057* not available. Return H primitive such that M*H = den*Id */3058GEN3059ZM_inv_ratlift(GEN M, GEN *pden)3060{3061pari_sp av2, av = avma;3062GEN Hp, q, H;3063ulong p;3064long m = lg(M)-1;3065forprime_t S;3066pari_timer ti;30673068if (m == 0) return ZM_inv0(M,pden);3069if (m == 1 && nbrows(M)==1) return ZM_inv1(M,pden);3070if (m == 2 && nbrows(M)==2) return ZM_inv2(M,pden);30713072if (DEBUGLEVEL>5) timer_start(&ti);3073init_modular_big(&S);3074av2 = avma;3075H = NULL;3076while ((p = u_forprime_next(&S)))3077{3078GEN Mp, B, Hr;3079Mp = ZM_to_Flm(M,p);3080Hp = Flm_inv_sp(Mp, NULL, p);3081if (!Hp) continue;3082if (!H)3083{3084H = ZM_init_CRT(Hp, p);3085q = utoipos(p);3086}3087else3088ZM_incremental_CRT(&H, Hp, &q, p);3089B = sqrti(shifti(q,-1));3090Hr = FpM_ratlift(H,q,B,B,NULL);3091if (DEBUGLEVEL>5)3092timer_printf(&ti,"ZM_inv mod %lu (ratlift=%ld)", p,!!Hr);3093if (Hr) {/* DONE ? */3094GEN Hl = Q_remove_denom(Hr, pden);3095if (ZM_isscalar(ZM_mul(Hl, M), *pden)) { H = Hl; break; }3096}30973098if (gc_needed(av,2))3099{3100if (DEBUGMEM>1) pari_warn(warnmem,"ZM_inv_ratlift");3101gerepileall(av2, 2, &H, &q);3102}3103}3104if (!*pden) *pden = gen_1;3105gerepileall(av, 2, &H, pden);3106return H;3107}31083109GEN3110FpM_ratlift_worker(GEN A, GEN mod, GEN B)3111{3112long l, i;3113GEN H = cgetg_copy(A, &l);3114for (i = 1; i < l; i++)3115{3116GEN c = FpC_ratlift(gel(A,i), mod, B, B, NULL);3117gel(H,i) = c? c: gen_0;3118}3119return H;3120}3121static int3122can_ratlift(GEN x, GEN mod, GEN B)3123{3124pari_sp av = avma;3125GEN a, b;3126return gc_bool(av, Fp_ratlift(x, mod, B, B, &a,&b));3127}3128static GEN3129FpM_ratlift_parallel(GEN A, GEN mod, GEN B)3130{3131pari_sp av = avma;3132GEN worker;3133long i, l = lg(A), m = mt_nbthreads();3134int test = !!B;31353136if (l == 1 || lgcols(A) == 1) return gcopy(A);3137if (!B) B = sqrti(shifti(mod,-1));3138if (m == 1 || l == 2 || lgcols(A) < 10)3139{3140A = FpM_ratlift(A, mod, B, B, NULL);3141return A? A: gc_NULL(av);3142}3143/* test one coefficient first */3144if (test && !can_ratlift(gcoeff(A,1,1), mod, B)) return gc_NULL(av);3145worker = snm_closure(is_entry("_FpM_ratlift_worker"), mkvec2(mod,B));3146A = gen_parapply_slice(worker, A, m);3147for (i = 1; i < l; i++) if (typ(gel(A,i)) != t_COL) return gc_NULL(av);3148return A;3149}31503151static GEN3152ZM_adj_ratlift(GEN A, GEN H, GEN mod, GEN T)3153{3154pari_sp av = avma;3155GEN B, D, g;3156D = ZMrow_ZC_mul(H, gel(A,1), 1);3157if (T) D = mulii(T, D);3158g = gcdii(D, mod);3159if (!equali1(g))3160{3161mod = diviiexact(mod, g);3162H = FpM_red(H, mod);3163}3164D = Fp_inv(Fp_red(D, mod), mod);3165/* test 1 coeff first */3166B = sqrti(shifti(mod,-1));3167if (!can_ratlift(Fp_mul(D, gcoeff(A,1,1), mod), mod, B)) return gc_NULL(av);3168H = FpM_Fp_mul(H, D, mod);3169H = FpM_ratlift_parallel(H, mod, B);3170return H? H: gc_NULL(av);3171}31723173/* if (T) return T A^(-1) in Mn(Q), else B in Mn(Z) such that A B = den*Id */3174static GEN3175ZM_inv_i(GEN A, GEN *pden, GEN T)3176{3177pari_sp av = avma;3178long m = lg(A)-1, n, k1 = 1, k2;3179GEN H = NULL, D, H1 = NULL, mod1 = NULL, worker;3180ulong bnd, mask;3181forprime_t S;3182pari_timer ti;31833184if (m == 0) return ZM_inv0(A,pden);3185if (pden) *pden = gen_1;3186if (nbrows(A) < m) return NULL;3187if (m == 1 && nbrows(A)==1 && !T) return ZM_inv1(A,pden);3188if (m == 2 && nbrows(A)==2 && !T) return ZM_inv2(A,pden);31893190if (DEBUGLEVEL>=5) timer_start(&ti);3191init_modular_big(&S);3192bnd = expi(RgM_true_Hadamard(A));3193worker = snm_closure(is_entry("_ZM_inv_worker"), mkvec(A));3194gen_inccrt("ZM_inv_r", worker, NULL, k1, 0, &S, &H1, &mod1, nmV_chinese_center, FpM_center);3195n = (bnd+1)/expu(S.p)+1;3196if (DEBUGLEVEL>=5) timer_printf(&ti,"inv (%ld/%ld primes)", k1, n);3197mask = quadratic_prec_mask(n);3198for (k2 = 0;;)3199{3200GEN Hr;3201if (k2 > 0)3202{3203gen_inccrt("ZM_inv_r", worker, NULL, k2, 0, &S, &H1, &mod1,nmV_chinese_center,FpM_center);3204k1 += k2;3205if (DEBUGLEVEL>=5) timer_printf(&ti,"CRT (%ld/%ld primes)", k1, n);3206}3207if (mask == 1) break;3208k2 = (mask&1UL) ? k1-1: k1;3209mask >>= 1;32103211Hr = ZM_adj_ratlift(A, H1, mod1, T);3212if (DEBUGLEVEL>=5) timer_printf(&ti,"ratlift (%ld/%ld primes)", k1, n);3213if (Hr) {/* DONE ? */3214GEN Hl = Q_primpart(Hr), R = ZM_mul(Hl, A), d = gcoeff(R,1,1);3215if (gsigne(d) < 0) { d = gneg(d); Hl = ZM_neg(Hl); }3216if (DEBUGLEVEL>=5) timer_printf(&ti,"mult (%ld/%ld primes)", k1, n);3217if (equali1(d))3218{3219if (ZM_isidentity(R)) { H = Hl; break; }3220}3221else if (ZM_isscalar(R, d))3222{3223if (T) T = gdiv(T,d);3224else if (pden) *pden = d;3225H = Hl; break;3226}3227}3228}3229if (!H)3230{3231GEN d;3232H = H1;3233D = ZMrow_ZC_mul(H, gel(A,1), 1);3234if (signe(D)==0) pari_err_INV("ZM_inv", A);3235if (T) T = gdiv(T, D);3236else3237{3238d = gcdii(Q_content_safe(H), D);3239if (signe(D) < 0) d = negi(d);3240if (!equali1(d))3241{3242H = ZM_Z_divexact(H, d);3243D = diviiexact(D, d);3244}3245if (pden) *pden = D;3246}3247}3248if (T && !isint1(T)) H = ZM_Q_mul(H, T);3249gerepileall(av, pden? 2: 1, &H, pden);3250return H;3251}3252GEN3253ZM_inv(GEN A, GEN *pden) { return ZM_inv_i(A, pden, NULL); }32543255/* same as above, M rational */3256GEN3257QM_inv(GEN M)3258{3259pari_sp av = avma;3260GEN den, dM, K;3261M = Q_remove_denom(M, &dM);3262K = ZM_inv_i(M, &den, dM);3263if (!K) return gc_NULL(av);3264if (den && !equali1(den)) K = ZM_Q_mul(K, ginv(den));3265return gerepileupto(av, K);3266}32673268static GEN3269ZM_ker_filter(GEN A, GEN P)3270{3271long i, j, l = lg(A), n = 1, d = lg(gmael(A,1,1));3272GEN B, Q, D = gmael(A,1,2);3273for (i=2; i<l; i++)3274{3275GEN Di = gmael(A,i,2);3276long di = lg(gmael(A,i,1));3277int c = vecsmall_lexcmp(D, Di);3278if (di==d && c==0) n++;3279else if (d > di || (di==d && c>0))3280{ n = 1; d = di; D = Di; }3281}3282B = cgetg(n+1, t_VEC);3283Q = cgetg(n+1, typ(P));3284for (i=1, j=1; i<l; i++)3285{3286if (lg(gmael(A,i,1))==d && vecsmall_lexcmp(D, gmael(A,i,2))==0)3287{3288gel(B,j) = gmael(A,i,1);3289Q[j] = P[i];3290j++;3291}3292}3293return mkvec3(B,Q,D);3294}32953296static GEN3297ZM_ker_chinese(GEN A, GEN P, GEN *mod)3298{3299GEN BQD = ZM_ker_filter(A, P);3300return mkvec2(nmV_chinese_center(gel(BQD,1), gel(BQD,2), mod), gel(BQD,3));3301}33023303static GEN3304ZM_ker_slice(GEN A, GEN P, GEN *mod)3305{3306pari_sp av = avma;3307long i, n = lg(P)-1;3308GEN BQD, D, H, T, Q;3309if (n == 1)3310{3311ulong p = uel(P,1);3312GEN K = Flm_ker_sp(ZM_to_Flm(A, p), p, 2);3313*mod = utoipos(p); return mkvec2(Flm_to_ZM(gel(K,1)), gel(K,2));3314}3315T = ZV_producttree(P);3316A = ZM_nv_mod_tree(A, P, T);3317H = cgetg(n+1, t_VEC);3318for(i=1 ; i <= n; i++)3319gel(H,i) = Flm_ker_sp(gel(A, i), P[i], 2);3320BQD = ZM_ker_filter(H, P); Q = gel(BQD,2);3321if (lg(Q) != lg(P)) T = ZV_producttree(Q);3322H = nmV_chinese_center_tree_seq(gel(BQD,1), Q, T, ZV_chinesetree(Q,T));3323*mod = gmael(T, lg(T)-1, 1);3324D = gel(BQD, 3);3325gerepileall(av, 3, &H, &D, mod);3326return mkvec2(H,D);3327}33283329GEN3330ZM_ker_worker(GEN P, GEN A)3331{3332GEN V = cgetg(3, t_VEC);3333gel(V,1) = ZM_ker_slice(A, P, &gel(V,2));3334return V;3335}33363337/* assume lg(A) > 1 */3338static GEN3339ZM_ker_i(GEN A)3340{3341pari_sp av;3342long k, m = lg(A)-1;3343GEN HD = NULL, mod = gen_1, worker;3344forprime_t S;33453346if (m >= 2*nbrows(A))3347{3348GEN v = ZM_indexrank(A), y = gel(v,2), z = indexcompl(y, m);3349GEN B, A1, A1i, d;3350A = rowpermute(A, gel(v,1)); /* same kernel */3351A1 = vecpermute(A, y); /* maximal rank submatrix */3352B = vecpermute(A, z);3353A1i = ZM_inv(A1, &d);3354if (!d) d = gen_1;3355B = vconcat(ZM_mul(ZM_neg(A1i), B), scalarmat_shallow(d, lg(B)-1));3356if (!gequal(y, identity_perm(lg(y)-1)))3357B = rowpermute(B, perm_inv(shallowconcat(y,z)));3358return vec_Q_primpart(B);3359}3360init_modular_big(&S);3361worker = snm_closure(is_entry("_ZM_ker_worker"), mkvec(A));3362av = avma;3363for (k = 1;; k <<= 1)3364{3365pari_timer ti;3366GEN H, Hr;3367gen_inccrt_i("ZM_ker", worker, NULL, (k+1)>>1, 0,3368&S, &HD, &mod, ZM_ker_chinese, NULL);3369gerepileall(av, 2, &HD, &mod);3370H = gel(HD, 1); if (lg(H) == 1) return H;3371if (DEBUGLEVEL >= 4) timer_start(&ti);3372Hr = FpM_ratlift_parallel(H, mod, NULL);3373if (DEBUGLEVEL >= 4) timer_printf(&ti,"ZM_ker: ratlift (%ld)",!!Hr);3374if (Hr)3375{3376GEN MH;3377Hr = vec_Q_primpart(Hr);3378MH = ZM_mul(A, Hr);3379if (DEBUGLEVEL >= 4) timer_printf(&ti,"ZM_ker: QM_mul");3380if (ZM_equal0(MH)) return Hr;3381}3382}3383}33843385GEN3386ZM_ker(GEN M)3387{3388pari_sp av = avma;3389long l = lg(M)-1;3390if (l==0) return cgetg(1, t_MAT);3391if (lgcols(M)==1) return matid(l);3392return gerepilecopy(av, ZM_ker_i(M));3393}33943395GEN3396QM_ker(GEN M)3397{3398pari_sp av = avma;3399long l = lg(M)-1;3400if (l==0) return cgetg(1, t_MAT);3401if (lgcols(M)==1) return matid(l);3402return gerepilecopy(av, ZM_ker_i(row_Q_primpart(M)));3403}34043405/* x a ZM. Return a multiple of the determinant of the lattice generated by3406* the columns of x. From Algorithm 2.2.6 in GTM138 */3407GEN3408detint(GEN A)3409{3410if (typ(A) != t_MAT) pari_err_TYPE("detint",A);3411RgM_check_ZM(A, "detint");3412return ZM_detmult(A);3413}3414GEN3415ZM_detmult(GEN A)3416{3417pari_sp av1, av = avma;3418GEN B, c, v, piv;3419long rg, i, j, k, m, n = lg(A) - 1;34203421if (!n) return gen_1;3422m = nbrows(A);3423if (n < m) return gen_0;3424c = zero_zv(m);3425av1 = avma;3426B = zeromatcopy(m,m);3427v = cgetg(m+1, t_COL);3428piv = gen_1; rg = 0;3429for (k=1; k<=n; k++)3430{3431GEN pivprec = piv;3432long t = 0;3433for (i=1; i<=m; i++)3434{3435pari_sp av2 = avma;3436GEN vi;3437if (c[i]) continue;34383439vi = mulii(piv, gcoeff(A,i,k));3440for (j=1; j<=m; j++)3441if (c[j]) vi = addii(vi, mulii(gcoeff(B,j,i),gcoeff(A,j,k)));3442if (!t && signe(vi)) t = i;3443gel(v,i) = gerepileuptoint(av2, vi);3444}3445if (!t) continue;3446/* at this point c[t] = 0 */34473448if (++rg >= m) { /* full rank; mostly done */3449GEN det = gel(v,t); /* last on stack */3450if (++k > n)3451det = absi(det);3452else3453{3454/* improve further; at this point c[i] is set for all i != t */3455gcoeff(B,t,t) = piv; v = centermod(gel(B,t), det);3456for ( ; k<=n; k++)3457det = gcdii(det, ZV_dotproduct(v, gel(A,k)));3458}3459return gerepileuptoint(av, det);3460}34613462piv = gel(v,t);3463for (i=1; i<=m; i++)3464{3465GEN mvi;3466if (c[i] || i == t) continue;34673468gcoeff(B,t,i) = mvi = negi(gel(v,i));3469for (j=1; j<=m; j++)3470if (c[j]) /* implies j != t */3471{3472pari_sp av2 = avma;3473GEN z = addii(mulii(gcoeff(B,j,i), piv), mulii(gcoeff(B,j,t), mvi));3474if (rg > 1) z = diviiexact(z, pivprec);3475gcoeff(B,j,i) = gerepileuptoint(av2, z);3476}3477}3478c[t] = k;3479if (gc_needed(av,1))3480{3481if(DEBUGMEM>1) pari_warn(warnmem,"detint. k=%ld",k);3482gerepileall(av1, 2, &piv,&B); v = zerovec(m);3483}3484}3485return gc_const(av, gen_0);3486}34873488/* Reduce x modulo (invertible) y */3489GEN3490closemodinvertible(GEN x, GEN y)3491{3492return gmul(y, ground(RgM_solve(y,x)));3493}3494GEN3495reducemodinvertible(GEN x, GEN y)3496{3497return gsub(x, closemodinvertible(x,y));3498}3499GEN3500reducemodlll(GEN x,GEN y)3501{3502return reducemodinvertible(x, ZM_lll(y, 0.75, LLL_INPLACE));3503}35043505/*******************************************************************/3506/* */3507/* KERNEL of an m x n matrix */3508/* return n - rk(x) linearly independent vectors */3509/* */3510/*******************************************************************/3511static GEN3512RgM_deplin_i(GEN x0)3513{3514pari_sp av = avma, av2;3515long i, j, k, nl, nc = lg(x0)-1;3516GEN D, x, y, c, l, d, ck;35173518if (!nc) return NULL;3519nl = nbrows(x0);3520c = zero_zv(nl);3521l = cgetg(nc+1, t_VECSMALL); /* not initialized */3522av2 = avma;3523x = RgM_shallowcopy(x0);3524d = const_vec(nl, gen_1); /* pivot list */3525ck = NULL; /* gcc -Wall */3526for (k=1; k<=nc; k++)3527{3528ck = gel(x,k);3529for (j=1; j<k; j++)3530{3531GEN cj = gel(x,j), piv = gel(d,j), q = gel(ck,l[j]);3532for (i=1; i<=nl; i++)3533if (i!=l[j]) gel(ck,i) = gsub(gmul(piv, gel(ck,i)), gmul(q, gel(cj,i)));3534}35353536i = gauss_get_pivot_NZ(x, NULL, k, c);3537if (i > nl) break;3538if (gc_needed(av,1))3539{3540if (DEBUGMEM>1) pari_warn(warnmem,"deplin k = %ld/%ld",k,nc);3541gerepileall(av2, 2, &x, &d);3542ck = gel(x,k);3543}3544gel(d,k) = gel(ck,i);3545c[i] = k; l[k] = i; /* pivot d[k] in x[i,k] */3546}3547if (k > nc) return gc_NULL(av);3548if (k == 1) { set_avma(av); return scalarcol_shallow(gen_1,nc); }3549y = cgetg(nc+1,t_COL);3550gel(y,1) = gcopy(gel(ck, l[1]));3551for (D=gel(d,1),j=2; j<k; j++)3552{3553gel(y,j) = gmul(gel(ck, l[j]), D);3554D = gmul(D, gel(d,j));3555}3556gel(y,j) = gneg(D);3557for (j++; j<=nc; j++) gel(y,j) = gen_0;3558y = primitive_part(y, &c);3559return c? gerepileupto(av, y): gerepilecopy(av, y);3560}3561static GEN3562RgV_deplin(GEN v)3563{3564pari_sp av = avma;3565long n = lg(v)-1;3566GEN y, p = NULL;3567if (n <= 1)3568{3569if (n == 1 && gequal0(gel(v,1))) return mkcol(gen_1);3570return cgetg(1, t_COL);3571}3572if (gequal0(gel(v,1))) return scalarcol_shallow(gen_1, n);3573v = primpart(mkvec2(gel(v,1),gel(v,2)));3574if (RgV_is_FpV(v, &p) && p) v = centerlift(v);3575y = zerocol(n);3576gel(y,1) = gneg(gel(v,2));3577gel(y,2) = gcopy(gel(v,1));3578return gerepileupto(av, y);35793580}35813582static GEN3583RgM_deplin_FpM(GEN x, GEN p)3584{3585pari_sp av = avma;3586ulong pp;3587x = RgM_Fp_init(x, p, &pp);3588switch(pp)3589{3590case 0:3591x = FpM_ker_gen(x,p,1);3592if (!x) return gc_NULL(av);3593x = FpC_center(x,p,shifti(p,-1));3594break;3595case 2:3596x = F2m_ker_sp(x,1);3597if (!x) return gc_NULL(av);3598x = F2c_to_ZC(x); break;3599default:3600x = Flm_ker_sp(x,pp,1);3601if (!x) return gc_NULL(av);3602x = Flv_center(x, pp, pp>>1);3603x = zc_to_ZC(x);3604break;3605}3606return gerepileupto(av, x);3607}36083609/* FIXME: implement direct modular ZM_deplin ? */3610static GEN3611QM_deplin(GEN M)3612{3613pari_sp av = avma;3614long l = lg(M)-1;3615GEN k;3616if (l==0) return NULL;3617if (lgcols(M)==1) return col_ei(l, 1);3618k = ZM_ker_i(row_Q_primpart(M));3619if (lg(k)== 1) return gc_NULL(av);3620return gerepilecopy(av, gel(k,1));3621}36223623static GEN3624RgM_deplin_FqM(GEN x, GEN pol, GEN p)3625{3626pari_sp av = avma;3627GEN b, T = RgX_to_FpX(pol, p);3628if (signe(T) == 0) pari_err_OP("deplin",x,pol);3629b = FqM_deplin(RgM_to_FqM(x, T, p), T, p);3630return gerepileupto(av, b);3631}36323633#define code(t1,t2) ((t1 << 6) | t2)3634static GEN3635RgM_deplin_fast(GEN x)3636{3637GEN p, pol;3638long pa;3639long t = RgM_type(x, &p,&pol,&pa);3640switch(t)3641{3642case t_INT: /* fall through */3643case t_FRAC: return QM_deplin(x);3644case t_FFELT: return FFM_deplin(x, pol);3645case t_INTMOD: return RgM_deplin_FpM(x, p);3646case code(t_POLMOD, t_INTMOD):3647return RgM_deplin_FqM(x, pol, p);3648default: return gen_0;3649}3650}3651#undef code36523653static GEN3654RgM_deplin(GEN x)3655{3656GEN z = RgM_deplin_fast(x);3657if (z!= gen_0) return z;3658return RgM_deplin_i(x);3659}36603661GEN3662deplin(GEN x)3663{3664switch(typ(x))3665{3666case t_MAT:3667{3668GEN z = RgM_deplin(x);3669if (z) return z;3670return cgetg(1, t_COL);3671}3672case t_VEC: return RgV_deplin(x);3673default: pari_err_TYPE("deplin",x);3674}3675return NULL;/*LCOV_EXCL_LINE*/3676}36773678/*******************************************************************/3679/* */3680/* GAUSS REDUCTION OF MATRICES (m lines x n cols) */3681/* (kernel, image, complementary image, rank) */3682/* */3683/*******************************************************************/3684/* return the transform of x under a standard Gauss pivot.3685* x0 is a reference point when guessing whether x[i,j] ~ 03686* (iff x[i,j] << x0[i,j])3687* Set r = dim ker(x). d[k] contains the index of the first nonzero pivot3688* in column k */3689static GEN3690gauss_pivot_ker(GEN x, GEN x0, GEN *dd, long *rr)3691{3692GEN c, d, p, data;3693pari_sp av;3694long i, j, k, r, t, n, m;3695pivot_fun pivot;36963697n=lg(x)-1; if (!n) { *dd=NULL; *rr=0; return cgetg(1,t_MAT); }3698m=nbrows(x); r=0;3699pivot = get_pivot_fun(x, x0, &data);3700x = RgM_shallowcopy(x);3701c = zero_zv(m);3702d = cgetg(n+1,t_VECSMALL);3703av=avma;3704for (k=1; k<=n; k++)3705{3706j = pivot(x, data, k, c);3707if (j > m)3708{3709r++; d[k]=0;3710for(j=1; j<k; j++)3711if (d[j]) gcoeff(x,d[j],k) = gclone(gcoeff(x,d[j],k));3712}3713else3714{ /* pivot for column k on row j */3715c[j]=k; d[k]=j; p = gdiv(gen_m1,gcoeff(x,j,k));3716gcoeff(x,j,k) = gen_m1;3717/* x[j,] /= - x[j,k] */3718for (i=k+1; i<=n; i++) gcoeff(x,j,i) = gmul(p,gcoeff(x,j,i));3719for (t=1; t<=m; t++)3720if (t!=j)3721{ /* x[t,] -= 1 / x[j,k] x[j,] */3722p = gcoeff(x,t,k); gcoeff(x,t,k) = gen_0;3723if (gequal0(p)) continue;3724for (i=k+1; i<=n; i++)3725gcoeff(x,t,i) = gadd(gcoeff(x,t,i),gmul(p,gcoeff(x,j,i)));3726if (gc_needed(av,1)) gerepile_gauss_ker(x,k,t,av);3727}3728}3729}3730*dd=d; *rr=r; return x;3731}37323733/* r = dim ker(x).3734* Returns d:3735* d[k] != 0 contains the index of a nonzero pivot in column k3736* d[k] == 0 if column k is a linear combination of the (k-1) first ones */3737GEN3738RgM_pivots(GEN x0, GEN data, long *rr, pivot_fun pivot)3739{3740GEN x, c, d, p;3741long i, j, k, r, t, m, n = lg(x0)-1;3742pari_sp av;37433744if (RgM_is_ZM(x0)) return ZM_pivots(x0, rr);3745if (!n) { *rr = 0; return NULL; }37463747d = cgetg(n+1, t_VECSMALL);3748x = RgM_shallowcopy(x0);3749m = nbrows(x); r = 0;3750c = zero_zv(m);3751av = avma;3752for (k=1; k<=n; k++)3753{3754j = pivot(x, data, k, c);3755if (j > m) { r++; d[k] = 0; }3756else3757{3758c[j] = k; d[k] = j; p = gdiv(gen_m1, gcoeff(x,j,k));3759for (i=k+1; i<=n; i++) gcoeff(x,j,i) = gmul(p,gcoeff(x,j,i));37603761for (t=1; t<=m; t++)3762if (!c[t]) /* no pivot on that line yet */3763{3764p = gcoeff(x,t,k); gcoeff(x,t,k) = gen_0;3765for (i=k+1; i<=n; i++)3766gcoeff(x,t,i) = gadd(gcoeff(x,t,i), gmul(p, gcoeff(x,j,i)));3767if (gc_needed(av,1)) gerepile_gauss(x,k,t,av,j,c);3768}3769for (i=k; i<=n; i++) gcoeff(x,j,i) = gen_0; /* dummy */3770}3771}3772*rr = r; return gc_const((pari_sp)d, d);3773}37743775static long3776ZM_count_0_cols(GEN M)3777{3778long i, l = lg(M), n = 0;3779for (i = 1; i < l; i++)3780if (ZV_equal0(gel(M,i))) n++;3781return n;3782}37833784static void indexrank_all(long m, long n, long r, GEN d, GEN *prow, GEN *pcol);3785/* As RgM_pivots, integer entries. Set *rr = dim Ker M0 */3786GEN3787ZM_pivots(GEN M0, long *rr)3788{3789GEN d, dbest = NULL;3790long m, mm, n, nn, i, imax, rmin, rbest, zc;3791int beenthere = 0;3792pari_sp av, av0 = avma;3793forprime_t S;37943795rbest = n = lg(M0)-1;3796if (n == 0) { *rr = 0; return NULL; }3797zc = ZM_count_0_cols(M0);3798if (n == zc) { *rr = zc; return zero_zv(n); }37993800m = nbrows(M0);3801rmin = maxss(zc, n-m);3802init_modular_small(&S);3803if (n <= m) { nn = n; mm = m; } else { nn = m; mm = n; }3804imax = (nn < 16)? 1: (nn < 64)? 2: 3; /* heuristic */38053806for(;;)3807{3808GEN row, col, M, KM, IM, RHS, X, cX;3809long rk;3810for (av = avma, i = 0;; set_avma(av), i++)3811{3812ulong p = u_forprime_next(&S);3813long rp;3814if (!p) pari_err_OVERFLOW("ZM_pivots [ran out of primes]");3815d = Flm_pivots(ZM_to_Flm(M0, p), p, &rp, 1);3816if (rp == rmin) { rbest = rp; goto END; } /* maximal rank, return */3817if (rp < rbest) { /* save best r so far */3818rbest = rp;3819guncloneNULL(dbest);3820dbest = gclone(d);3821if (beenthere) break;3822}3823if (!beenthere && i >= imax) break;3824}3825beenthere = 1;3826/* Dubious case: there is (probably) a non trivial kernel */3827indexrank_all(m,n, rbest, dbest, &row, &col);3828M = rowpermute(vecpermute(M0, col), row);3829rk = n - rbest; /* (probable) dimension of image */3830if (n > m) M = shallowtrans(M);3831IM = vecslice(M,1,rk);3832KM = vecslice(M,rk+1, nn);3833M = rowslice(IM, 1,rk); /* square maximal rank */3834X = ZM_gauss(M, rowslice(KM, 1,rk));3835RHS = rowslice(KM,rk+1,mm);3836M = rowslice(IM,rk+1,mm);3837X = Q_remove_denom(X, &cX);3838if (cX) RHS = ZM_Z_mul(RHS, cX);3839if (ZM_equal(ZM_mul(M, X), RHS)) { d = vecsmall_copy(dbest); goto END; }3840set_avma(av);3841}3842END:3843*rr = rbest; guncloneNULL(dbest);3844return gerepileuptoleaf(av0, d);3845}38463847/* set *pr = dim Ker x */3848static GEN3849gauss_pivot(GEN x, long *pr) {3850GEN data;3851pivot_fun pivot = get_pivot_fun(x, x, &data);3852return RgM_pivots(x, data, pr, pivot);3853}38543855/* compute ker(x), x0 is a reference point when guessing whether x[i,j] ~ 03856* (iff x[i,j] << x0[i,j]) */3857static GEN3858ker_aux(GEN x, GEN x0)3859{3860pari_sp av = avma;3861GEN d,y;3862long i,j,k,r,n;38633864x = gauss_pivot_ker(x,x0,&d,&r);3865if (!r) { set_avma(av); return cgetg(1,t_MAT); }3866n = lg(x)-1; y=cgetg(r+1,t_MAT);3867for (j=k=1; j<=r; j++,k++)3868{3869GEN p = cgetg(n+1,t_COL);38703871gel(y,j) = p; while (d[k]) k++;3872for (i=1; i<k; i++)3873if (d[i])3874{3875GEN p1=gcoeff(x,d[i],k);3876gel(p,i) = gcopy(p1); gunclone(p1);3877}3878else3879gel(p,i) = gen_0;3880gel(p,k) = gen_1; for (i=k+1; i<=n; i++) gel(p,i) = gen_0;3881}3882return gerepileupto(av,y);3883}38843885static GEN3886RgM_ker_FpM(GEN x, GEN p)3887{3888pari_sp av = avma;3889ulong pp;3890x = RgM_Fp_init(x, p, &pp);3891switch(pp)3892{3893case 0: x = FpM_to_mod(FpM_ker_gen(x,p,0),p); break;3894case 2: x = F2m_to_mod(F2m_ker_sp(x,0)); break;3895default:x = Flm_to_mod(Flm_ker_sp(x,pp,0), pp); break;3896}3897return gerepileupto(av, x);3898}38993900static GEN3901RgM_ker_FqM(GEN x, GEN pol, GEN p)3902{3903pari_sp av = avma;3904GEN b, T = RgX_to_FpX(pol, p);3905if (signe(T) == 0) pari_err_OP("ker",x,pol);3906b = FqM_ker(RgM_to_FqM(x, T, p), T, p);3907return gerepileupto(av, FqM_to_mod(b, T, p));3908}39093910#define code(t1,t2) ((t1 << 6) | t2)3911static GEN3912RgM_ker_fast(GEN x)3913{3914GEN p, pol;3915long pa;3916long t = RgM_type(x, &p,&pol,&pa);3917switch(t)3918{3919case t_INT: /* fall through */3920case t_FRAC: return QM_ker(x);3921case t_FFELT: return FFM_ker(x, pol);3922case t_INTMOD: return RgM_ker_FpM(x, p);3923case code(t_POLMOD, t_INTMOD):3924return RgM_ker_FqM(x, pol, p);3925default: return NULL;3926}3927}3928#undef code39293930GEN3931ker(GEN x)3932{3933GEN b = RgM_ker_fast(x);3934if (b) return b;3935return ker_aux(x,x);3936}39373938GEN3939matker0(GEN x,long flag)3940{3941if (typ(x)!=t_MAT) pari_err_TYPE("matker",x);3942if (!flag) return ker(x);3943RgM_check_ZM(x, "matker");3944return ZM_ker(x);3945}39463947static GEN3948RgM_image_FpM(GEN x, GEN p)3949{3950pari_sp av = avma;3951ulong pp;3952x = RgM_Fp_init(x, p, &pp);3953switch(pp)3954{3955case 0: x = FpM_to_mod(FpM_image(x,p),p); break;3956case 2: x = F2m_to_mod(F2m_image(x)); break;3957default:x = Flm_to_mod(Flm_image(x,pp), pp); break;3958}3959return gerepileupto(av, x);3960}39613962static GEN3963RgM_image_FqM(GEN x, GEN pol, GEN p)3964{3965pari_sp av = avma;3966GEN b, T = RgX_to_FpX(pol, p);3967if (signe(T) == 0) pari_err_OP("image",x,pol);3968b = FqM_image(RgM_to_FqM(x, T, p), T, p);3969return gerepileupto(av, FqM_to_mod(b, T, p));3970}39713972GEN3973QM_image_shallow(GEN A)3974{3975A = vec_Q_primpart(A);3976return vecpermute(A, ZM_indeximage(A));3977}3978GEN3979QM_image(GEN A)3980{3981pari_sp av = avma;3982return gerepilecopy(av, QM_image_shallow(A));3983}39843985#define code(t1,t2) ((t1 << 6) | t2)3986static GEN3987RgM_image_fast(GEN x)3988{3989GEN p, pol;3990long pa;3991long t = RgM_type(x, &p,&pol,&pa);3992switch(t)3993{3994case t_INT: /* fall through */3995case t_FRAC: return QM_image(x);3996case t_FFELT: return FFM_image(x, pol);3997case t_INTMOD: return RgM_image_FpM(x, p);3998case code(t_POLMOD, t_INTMOD):3999return RgM_image_FqM(x, pol, p);4000default: return NULL;4001}4002}4003#undef code40044005GEN4006image(GEN x)4007{4008GEN d, M;4009long r;40104011if (typ(x)!=t_MAT) pari_err_TYPE("matimage",x);4012M = RgM_image_fast(x);4013if (M) return M;4014d = gauss_pivot(x,&r); /* d left on stack for efficiency */4015return image_from_pivot(x,d,r);4016}40174018static GEN4019imagecompl_aux(GEN x, GEN(*PIVOT)(GEN,long*))4020{4021pari_sp av = avma;4022GEN d,y;4023long j,i,r;40244025if (typ(x)!=t_MAT) pari_err_TYPE("imagecompl",x);4026(void)new_chunk(lg(x) * 4 + 1); /* HACK */4027d = PIVOT(x,&r); /* if (!d) then r = 0 */4028set_avma(av); y = cgetg(r+1,t_VECSMALL);4029for (i=j=1; j<=r; i++)4030if (!d[i]) y[j++] = i;4031return y;4032}4033GEN4034imagecompl(GEN x) { return imagecompl_aux(x, &gauss_pivot); }4035GEN4036ZM_imagecompl(GEN x) { return imagecompl_aux(x, &ZM_pivots); }40374038static GEN4039RgM_RgC_invimage_FpC(GEN A, GEN y, GEN p)4040{4041pari_sp av = avma;4042ulong pp;4043GEN x;4044A = RgM_Fp_init(A,p,&pp);4045switch(pp)4046{4047case 0:4048y = RgC_to_FpC(y,p);4049x = FpM_FpC_invimage(A, y, p);4050return x ? gerepileupto(av, FpC_to_mod(x,p)): NULL;4051case 2:4052y = RgV_to_F2v(y);4053x = F2m_F2c_invimage(A, y);4054return x ? gerepileupto(av, F2c_to_mod(x)): NULL;4055default:4056y = RgV_to_Flv(y,pp);4057x = Flm_Flc_invimage(A, y, pp);4058return x ? gerepileupto(av, Flc_to_mod(x,pp)): NULL;4059}4060}40614062static GEN4063RgM_RgC_invimage_fast(GEN x, GEN y)4064{4065GEN p, pol;4066long pa;4067long t = RgM_RgC_type(x, y, &p,&pol,&pa);4068switch(t)4069{4070case t_INTMOD: return RgM_RgC_invimage_FpC(x, y, p);4071case t_FFELT: return FFM_FFC_invimage(x, y, pol);4072default: return gen_0;4073}4074}40754076GEN4077RgM_RgC_invimage(GEN A, GEN y)4078{4079pari_sp av = avma;4080long i, l = lg(A);4081GEN M, x, t;4082if (l==1) return NULL;4083if (lg(y) != lgcols(A)) pari_err_DIM("inverseimage");4084M = RgM_RgC_invimage_fast(A, y);4085if (!M) return gc_NULL(av);4086if (M != gen_0) return M;4087M = ker(shallowconcat(A, y));4088i = lg(M)-1;4089if (!i) return gc_NULL(av);40904091x = gel(M,i); t = gel(x,l);4092if (gequal0(t)) return gc_NULL(av);40934094t = gneg_i(t); setlg(x,l);4095return gerepileupto(av, RgC_Rg_div(x, t));4096}40974098/* Return X such that m X = v (t_COL or t_MAT), resp. an empty t_COL / t_MAT4099* if no solution exist */4100GEN4101inverseimage(GEN m, GEN v)4102{4103GEN y;4104if (typ(m)!=t_MAT) pari_err_TYPE("inverseimage",m);4105switch(typ(v))4106{4107case t_COL:4108y = RgM_RgC_invimage(m,v);4109return y? y: cgetg(1,t_COL);4110case t_MAT:4111y = RgM_invimage(m, v);4112return y? y: cgetg(1,t_MAT);4113}4114pari_err_TYPE("inverseimage",v);4115return NULL;/*LCOV_EXCL_LINE*/4116}41174118static GEN4119RgM_invimage_FpM(GEN A, GEN B, GEN p)4120{4121pari_sp av = avma;4122ulong pp;4123GEN x;4124A = RgM_Fp_init(A,p,&pp);4125switch(pp)4126{4127case 0:4128B = RgM_to_FpM(B,p);4129x = FpM_invimage_gen(A, B, p);4130return x ? gerepileupto(av, FpM_to_mod(x, p)): x;4131case 2:4132B = RgM_to_F2m(B);4133x = F2m_invimage_i(A, B);4134return x ? gerepileupto(av, F2m_to_mod(x)): x;4135default:4136B = RgM_to_Flm(B,pp);4137x = Flm_invimage_i(A, B, pp);4138return x ? gerepileupto(av, Flm_to_mod(x, pp)): x;4139}4140}41414142static GEN4143RgM_invimage_fast(GEN x, GEN y)4144{4145GEN p, pol;4146long pa;4147long t = RgM_type2(x, y, &p,&pol,&pa);4148switch(t)4149{4150case t_INTMOD: return RgM_invimage_FpM(x, y, p);4151case t_FFELT: return FFM_invimage(x, y, pol);4152default: return gen_0;4153}4154}41554156/* find Z such that A Z = B. Return NULL if no solution */4157GEN4158RgM_invimage(GEN A, GEN B)4159{4160pari_sp av = avma;4161GEN d, x, X, Y;4162long i, j, nY, nA = lg(A)-1, nB = lg(B)-1;4163X = RgM_invimage_fast(A, B);4164if (!X) return gc_NULL(av);4165if (X != gen_0) return X;4166x = ker(shallowconcat(RgM_neg(A), B));4167/* AX = BY, Y in strict upper echelon form with pivots = 1.4168* We must find T such that Y T = Id_nB then X T = Z. This exists iff4169* Y has at least nB columns and full rank */4170nY = lg(x)-1;4171if (nY < nB) return gc_NULL(av);4172Y = rowslice(x, nA+1, nA+nB); /* nB rows */4173d = cgetg(nB+1, t_VECSMALL);4174for (i = nB, j = nY; i >= 1; i--, j--)4175{4176for (; j>=1; j--)4177if (!gequal0(gcoeff(Y,i,j))) { d[i] = j; break; }4178if (!j) return gc_NULL(av);4179}4180/* reduce to the case Y square, upper triangular with 1s on diagonal */4181Y = vecpermute(Y, d);4182x = vecpermute(x, d);4183X = rowslice(x, 1, nA);4184return gerepileupto(av, RgM_mul(X, RgM_inv_upper(Y)));4185}41864187static GEN4188RgM_suppl_FpM(GEN x, GEN p)4189{4190pari_sp av = avma;4191ulong pp;4192x = RgM_Fp_init(x, p, &pp);4193switch(pp)4194{4195case 0: x = FpM_to_mod(FpM_suppl(x,p), p); break;4196case 2: x = F2m_to_mod(F2m_suppl(x)); break;4197default:x = Flm_to_mod(Flm_suppl(x,pp), pp); break;4198}4199return gerepileupto(av, x);4200}42014202static GEN4203RgM_suppl_fast(GEN x)4204{4205GEN p, pol;4206long pa;4207long t = RgM_type(x,&p,&pol,&pa);4208switch(t)4209{4210case t_INTMOD: return RgM_suppl_FpM(x, p);4211case t_FFELT: return FFM_suppl(x, pol);4212default: return NULL;4213}4214}42154216/* x is an n x k matrix, rank(x) = k <= n. Return an invertible n x n matrix4217* whose first k columns are given by x. If rank(x) < k, undefined result. */4218GEN4219suppl(GEN x)4220{4221pari_sp av = avma;4222GEN d, M;4223long r;4224if (typ(x)!=t_MAT) pari_err_TYPE("suppl",x);4225M = RgM_suppl_fast(x);4226if (M) return M;4227init_suppl(x);4228d = gauss_pivot(x,&r);4229set_avma(av); return get_suppl(x,d,nbrows(x),r,&col_ei);4230}42314232GEN4233image2(GEN x)4234{4235pari_sp av = avma;4236long k, n, i;4237GEN A, B;42384239if (typ(x)!=t_MAT) pari_err_TYPE("image2",x);4240if (lg(x) == 1) return cgetg(1,t_MAT);4241A = ker(x); k = lg(A)-1;4242if (!k) { set_avma(av); return gcopy(x); }4243A = suppl(A); n = lg(A)-1;4244B = cgetg(n-k+1, t_MAT);4245for (i = k+1; i <= n; i++) gel(B,i-k) = RgM_RgC_mul(x, gel(A,i));4246return gerepileupto(av, B);4247}42484249GEN4250matimage0(GEN x,long flag)4251{4252switch(flag)4253{4254case 0: return image(x);4255case 1: return image2(x);4256default: pari_err_FLAG("matimage");4257}4258return NULL; /* LCOV_EXCL_LINE */4259}42604261static long4262RgM_rank_FpM(GEN x, GEN p)4263{4264pari_sp av = avma;4265ulong pp;4266long r;4267x = RgM_Fp_init(x,p,&pp);4268switch(pp)4269{4270case 0: r = FpM_rank(x,p); break;4271case 2: r = F2m_rank(x); break;4272default:r = Flm_rank(x,pp); break;4273}4274return gc_long(av, r);4275}42764277static long4278RgM_rank_FqM(GEN x, GEN pol, GEN p)4279{4280pari_sp av = avma;4281long r;4282GEN T = RgX_to_FpX(pol, p);4283if (signe(T) == 0) pari_err_OP("rank",x,pol);4284r = FqM_rank(RgM_to_FqM(x, T, p), T, p);4285return gc_long(av,r);4286}42874288#define code(t1,t2) ((t1 << 6) | t2)4289static long4290RgM_rank_fast(GEN x)4291{4292GEN p, pol;4293long pa;4294long t = RgM_type(x,&p,&pol,&pa);4295switch(t)4296{4297case t_INT: return ZM_rank(x);4298case t_FRAC: return QM_rank(x);4299case t_INTMOD: return RgM_rank_FpM(x, p);4300case t_FFELT: return FFM_rank(x, pol);4301case code(t_POLMOD, t_INTMOD):4302return RgM_rank_FqM(x, pol, p);4303default: return -1;4304}4305}4306#undef code43074308long4309rank(GEN x)4310{4311pari_sp av = avma;4312long r;43134314if (typ(x)!=t_MAT) pari_err_TYPE("rank",x);4315r = RgM_rank_fast(x);4316if (r >= 0) return r;4317(void)gauss_pivot(x, &r);4318return gc_long(av, lg(x)-1 - r);4319}43204321/* d a t_VECSMALL of integers in 1..n. Return the vector of the d[i]4322* followed by the missing indices */4323static GEN4324perm_complete(GEN d, long n)4325{4326GEN y = cgetg(n+1, t_VECSMALL);4327long i, j = 1, k = n, l = lg(d);4328pari_sp av = avma;4329char *T = stack_calloc(n+1);4330for (i = 1; i < l; i++) T[d[i]] = 1;4331for (i = 1; i <= n; i++)4332if (T[i]) y[j++] = i; else y[k--] = i;4333return gc_const(av, y);4334}43354336/* n = dim x, r = dim Ker(x), d from gauss_pivot */4337static GEN4338indeximage0(long n, long r, GEN d)4339{4340long i, j;4341GEN v;43424343r = n - r; /* now r = dim Im(x) */4344v = cgetg(r+1,t_VECSMALL);4345if (d) for (i=j=1; j<=n; j++)4346if (d[j]) v[i++] = j;4347return v;4348}4349/* x an m x n t_MAT, n > 0, r = dim Ker(x), d from gauss_pivot */4350static void4351indexrank_all(long m, long n, long r, GEN d, GEN *prow, GEN *pcol)4352{4353GEN IR = indexrank0(n, r, d);4354*prow = perm_complete(gel(IR,1), m);4355*pcol = perm_complete(gel(IR,2), n);4356}43574358static GEN4359RgM_indexrank_FpM(GEN x, GEN p)4360{4361pari_sp av = avma;4362ulong pp;4363GEN r;4364x = RgM_Fp_init(x,p,&pp);4365switch(pp)4366{4367case 0: r = FpM_indexrank(x,p); break;4368case 2: r = F2m_indexrank(x); break;4369default: r = Flm_indexrank(x,pp); break;4370}4371return gerepileupto(av, r);4372}43734374static GEN4375RgM_indexrank_FqM(GEN x, GEN pol, GEN p)4376{4377pari_sp av = avma;4378GEN r, T = RgX_to_FpX(pol, p);4379if (signe(T) == 0) pari_err_OP("indexrank",x,pol);4380r = FqM_indexrank(RgM_to_FqM(x, T, p), T, p);4381return gerepileupto(av, r);4382}43834384#define code(t1,t2) ((t1 << 6) | t2)4385static GEN4386RgM_indexrank_fast(GEN x)4387{4388GEN p, pol;4389long pa;4390long t = RgM_type(x,&p,&pol,&pa);4391switch(t)4392{4393case t_INT: return ZM_indexrank(x);4394case t_FRAC: return QM_indexrank(x);4395case t_INTMOD: return RgM_indexrank_FpM(x, p);4396case t_FFELT: return FFM_indexrank(x, pol);4397case code(t_POLMOD, t_INTMOD):4398return RgM_indexrank_FqM(x, pol, p);4399default: return NULL;4400}4401}4402#undef code44034404GEN4405indexrank(GEN x)4406{4407pari_sp av;4408long r;4409GEN d;4410if (typ(x)!=t_MAT) pari_err_TYPE("indexrank",x);4411d = RgM_indexrank_fast(x);4412if (d) return d;4413av = avma;4414init_indexrank(x);4415d = gauss_pivot(x, &r);4416set_avma(av); return indexrank0(lg(x)-1, r, d);4417}44184419GEN4420ZM_indeximage(GEN x) {4421pari_sp av = avma;4422long r;4423GEN d;4424init_indexrank(x);4425d = ZM_pivots(x,&r);4426set_avma(av); return indeximage0(lg(x)-1, r, d);4427}4428long4429ZM_rank(GEN x) {4430pari_sp av = avma;4431long r;4432(void)ZM_pivots(x,&r);4433return gc_long(av, lg(x)-1-r);4434}4435GEN4436ZM_indexrank(GEN x) {4437pari_sp av = avma;4438long r;4439GEN d;4440init_indexrank(x);4441d = ZM_pivots(x,&r);4442set_avma(av); return indexrank0(lg(x)-1, r, d);4443}44444445long4446QM_rank(GEN x)4447{4448pari_sp av = avma;4449long r = ZM_rank(Q_primpart(x));4450set_avma(av);4451return r;4452}44534454GEN4455QM_indexrank(GEN x)4456{4457pari_sp av = avma;4458GEN r = ZM_indexrank(Q_primpart(x));4459return gerepileupto(av, r);4460}44614462/*******************************************************************/4463/* */4464/* ZabM */4465/* */4466/*******************************************************************/44674468static GEN4469FpXM_ratlift(GEN a, GEN q)4470{4471GEN B, y;4472long i, j, l = lg(a), n;4473B = sqrti(shifti(q,-1));4474y = cgetg(l, t_MAT);4475if (l==1) return y;4476n = lgcols(a);4477for (i=1; i<l; i++)4478{4479GEN yi = cgetg(n, t_COL);4480for (j=1; j<n; j++)4481{4482GEN v = FpX_ratlift(gmael(a,i,j), q, B, B, NULL);4483if (!v) return NULL;4484gel(yi, j) = RgX_renormalize(v);4485}4486gel(y,i) = yi;4487}4488return y;4489}44904491static GEN4492FlmV_recover_pre(GEN a, GEN M, ulong p, ulong pi, long sv)4493{4494GEN a1 = gel(a,1);4495long i, j, k, l = lg(a1), n, lM = lg(M);4496GEN v = cgetg(lM, t_VECSMALL);4497GEN y = cgetg(l, t_MAT);4498if (l==1) return y;4499n = lgcols(a1);4500for (i=1; i<l; i++)4501{4502GEN yi = cgetg(n, t_COL);4503for (j=1; j<n; j++)4504{4505for (k=1; k<lM; k++) uel(v,k) = umael(gel(a,k),i,j);4506gel(yi, j) = Flm_Flc_mul_pre_Flx(M, v, p, pi, sv);4507}4508gel(y,i) = yi;4509}4510return y;4511}45124513static GEN4514FlkM_inv(GEN M, GEN P, ulong p)4515{4516ulong pi = get_Fl_red(p);4517GEN R = Flx_roots(P, p);4518long l = lg(R), i;4519GEN W = Flv_invVandermonde(R, 1UL, p);4520GEN V = cgetg(l, t_VEC);4521for(i=1; i<l; i++)4522{4523GEN pows = Fl_powers_pre(uel(R,i), degpol(P), p, pi);4524GEN H = Flm_inv_sp(FlxM_eval_powers_pre(M, pows, p, pi), NULL, p);4525if (!H) return NULL;4526gel(V, i) = H;4527}4528return FlmV_recover_pre(V, W, p, pi, P[1]);4529}45304531static GEN4532FlkM_adjoint(GEN M, GEN P, ulong p)4533{4534ulong pi = get_Fl_red(p);4535GEN R = Flx_roots(P, p);4536long l = lg(R), i;4537GEN W = Flv_invVandermonde(R, 1UL, p);4538GEN V = cgetg(l, t_VEC);4539for(i=1; i<l; i++)4540{4541GEN pows = Fl_powers_pre(uel(R,i), degpol(P), p, pi);4542gel(V, i) = Flm_adjoint(FlxM_eval_powers_pre(M, pows, p, pi), p);4543}4544return FlmV_recover_pre(V, W, p, pi, P[1]);4545}45464547static GEN4548ZabM_inv_slice(GEN A, GEN Q, GEN P, GEN *mod)4549{4550pari_sp av = avma;4551long i, n = lg(P)-1, w = varn(Q);4552GEN H, T;4553if (n == 1)4554{4555ulong p = uel(P,1);4556GEN Qp = ZX_to_Flx(Q, p);4557GEN Ap = ZXM_to_FlxM(A, p, get_Flx_var(Qp));4558GEN Hp = FlkM_adjoint(Ap, Qp, p);4559Hp = gerepileupto(av, FlxM_to_ZXM(Hp));4560*mod = utoipos(p); return Hp;4561}4562T = ZV_producttree(P);4563A = ZXM_nv_mod_tree(A, P, T, w);4564Q = ZX_nv_mod_tree(Q, P, T);4565H = cgetg(n+1, t_VEC);4566for(i=1; i <= n; i++)4567{4568ulong p = P[i];4569GEN a = gel(A,i), q = gel(Q, i);4570gel(H,i) = FlkM_adjoint(a, q, p);4571}4572H = nxMV_chinese_center_tree_seq(H, P, T, ZV_chinesetree(P,T));4573*mod = gmael(T, lg(T)-1, 1);4574gerepileall(av, 2, &H, mod);4575return H;4576}45774578GEN4579ZabM_inv_worker(GEN P, GEN A, GEN Q)4580{4581GEN V = cgetg(3, t_VEC);4582gel(V,1) = ZabM_inv_slice(A, Q, P, &gel(V,2));4583return V;4584}45854586static GEN4587vecnorml1(GEN a)4588{4589long i, l;4590GEN g = cgetg_copy(a, &l);4591for (i=1; i<l; i++)4592gel(g, i) = gnorml1_fake(gel(a,i));4593return g;4594}45954596static GEN4597ZabM_true_Hadamard(GEN a)4598{4599pari_sp av = avma;4600long n = lg(a)-1, i;4601GEN B;4602if (n == 0) return gen_1;4603if (n == 1) return gnorml1_fake(gcoeff(a,1,1));4604B = gen_1;4605for (i = 1; i <= n; i++)4606B = gmul(B, gnorml2(RgC_gtofp(vecnorml1(gel(a,i)),DEFAULTPREC)));4607return gerepileuptoint(av, ceil_safe(sqrtr_abs(B)));4608}46094610GEN4611ZabM_inv(GEN A, GEN Q, long n, GEN *pt_den)4612{4613pari_sp av = avma;4614forprime_t S;4615GEN bnd, H, D, d, mod, worker;4616if (lg(A) == 1)4617{4618if (pt_den) *pt_den = gen_1;4619return cgetg(1, t_MAT);4620}4621bnd = ZabM_true_Hadamard(A);4622worker = snm_closure(is_entry("_ZabM_inv_worker"), mkvec2(A, Q));4623u_forprime_arith_init(&S, HIGHBIT+1, ULONG_MAX, 1, n);4624H = gen_crt("ZabM_inv", worker, &S, NULL, expi(bnd), 0, &mod,4625nxMV_chinese_center, FpXM_center);4626D = RgMrow_RgC_mul(H, gel(A,1), 1);4627D = ZX_rem(D, Q);4628d = Z_content(mkvec2(H, D));4629if (d)4630{4631D = ZX_Z_divexact(D, d);4632H = Q_div_to_int(H, d);4633}4634if (pt_den)4635{4636gerepileall(av, 2, &H, &D);4637*pt_den = D; return H;4638}4639return gerepileupto(av, H);4640}46414642GEN4643ZabM_inv_ratlift(GEN M, GEN P, long n, GEN *pden)4644{4645pari_sp av2, av = avma;4646GEN q, H;4647ulong m = LONG_MAX>>1;4648ulong p= 1 + m - (m % n);4649long lM = lg(M);4650if (lM == 1) { *pden = gen_1; return cgetg(1,t_MAT); }46514652av2 = avma;4653H = NULL;4654for(;;)4655{4656GEN Hp, Pp, Mp, Hr;4657do p += n; while(!uisprime(p));4658Pp = ZX_to_Flx(P, p);4659Mp = ZXM_to_FlxM(M, p, get_Flx_var(Pp));4660Hp = FlkM_inv(Mp, Pp, p);4661if (!Hp) continue;4662if (!H)4663{4664H = ZXM_init_CRT(Hp, degpol(P)-1, p);4665q = utoipos(p);4666}4667else4668ZXM_incremental_CRT(&H, Hp, &q, p);4669Hr = FpXM_ratlift(H, q);4670if (DEBUGLEVEL>5) err_printf("ZabM_inv mod %ld (ratlift=%ld)\n", p,!!Hr);4671if (Hr) {/* DONE ? */4672GEN Hl = Q_remove_denom(Hr, pden);4673GEN MH = ZXQM_mul(Hl, M, P);4674if (*pden)4675{ if (RgM_isscalar(MH, *pden)) { H = Hl; break; }}4676else4677{ if (RgM_isidentity(MH)) { H = Hl; *pden = gen_1; break; } }4678}46794680if (gc_needed(av,2))4681{4682if (DEBUGMEM>1) pari_warn(warnmem,"ZabM_inv");4683gerepileall(av2, 2, &H, &q);4684}4685}4686gerepileall(av, 2, &H, pden);4687return H;4688}46894690static GEN4691FlkM_ker(GEN M, GEN P, ulong p)4692{4693ulong pi = get_Fl_red(p);4694GEN R = Flx_roots(P, p);4695long l = lg(R), i, dP = degpol(P), r;4696GEN M1, K, D;4697GEN W = Flv_invVandermonde(R, 1UL, p);4698GEN V = cgetg(l, t_VEC);4699M1 = FlxM_eval_powers_pre(M, Fl_powers_pre(uel(R,1), dP, p, pi), p, pi);4700K = Flm_ker_sp(M1, p, 2);4701r = lg(gel(K,1)); D = gel(K,2);4702gel(V, 1) = gel(K,1);4703for(i=2; i<l; i++)4704{4705GEN Mi = FlxM_eval_powers_pre(M, Fl_powers_pre(uel(R,i), dP, p, pi), p, pi);4706GEN K = Flm_ker_sp(Mi, p, 2);4707if (lg(gel(K,1)) != r || !zv_equal(D, gel(K,2))) return NULL;4708gel(V, i) = gel(K,1);4709}4710return mkvec2(FlmV_recover_pre(V, W, p, pi, P[1]), D);4711}47124713static int4714ZabM_ker_check(GEN M, GEN H, ulong p, GEN P, long n)4715{4716GEN pow;4717long j, l = lg(H);4718ulong pi, r;4719do p += n; while(!uisprime(p));4720pi = get_Fl_red(p);4721P = ZX_to_Flx(P, p);4722r = Flx_oneroot(P, p);4723pow = Fl_powers_pre(r, degpol(P),p,pi);4724M = ZXM_to_FlxM(M, p, P[1]); M = FlxM_eval_powers_pre(M, pow, p, pi);4725H = ZXM_to_FlxM(H, p, P[1]); H = FlxM_eval_powers_pre(H, pow, p, pi);4726for (j = 1; j < l; j++)4727if (!zv_equal0(Flm_Flc_mul_pre(M, gel(H,j), p, pi))) return 0;4728return 1;4729}47304731GEN4732ZabM_ker(GEN M, GEN P, long n)4733{4734pari_sp av = avma;4735pari_timer ti;4736GEN q, H = NULL, D = NULL;4737ulong m = LONG_MAX>>1;4738ulong p = 1 + m - (m % n);47394740if (DEBUGLEVEL>5) timer_start(&ti);4741for(;;)4742{4743GEN Kp, Hp, Dp, Pp, Mp, Hr;4744do p += n; while(!uisprime(p));4745Pp = ZX_to_Flx(P, p);4746Mp = ZXM_to_FlxM(M, p, get_Flx_var(Pp));4747Kp = FlkM_ker(Mp, Pp, p);4748if (!Kp) continue;4749Hp = gel(Kp,1); Dp = gel(Kp,2);4750if (H && (lg(Hp)>lg(H) || (lg(Hp)==lg(H) && vecsmall_lexcmp(Dp,D)>0))) continue;4751if (!H || (lg(Hp)<lg(H) || vecsmall_lexcmp(Dp,D)<0))4752{4753H = ZXM_init_CRT(Hp, degpol(P)-1, p); D = Dp;4754q = utoipos(p);4755}4756else4757ZXM_incremental_CRT(&H, Hp, &q, p);4758Hr = FpXM_ratlift(H, q);4759if (DEBUGLEVEL>5) timer_printf(&ti,"ZabM_ker mod %ld (ratlift=%ld)", p,!!Hr);4760if (Hr) {/* DONE ? */4761GEN Hl = vec_Q_primpart(Hr);4762if (ZabM_ker_check(M, Hl, p, P, n)) { H = Hl; break; }4763}47644765if (gc_needed(av,2))4766{4767if (DEBUGMEM>1) pari_warn(warnmem,"ZabM_ker");4768gerepileall(av, 3, &H, &D, &q);4769}4770}4771return gerepilecopy(av, H);4772}47734774GEN4775ZabM_indexrank(GEN M, GEN P, long n)4776{4777pari_sp av = avma;4778ulong m = LONG_MAX>>1;4779ulong p = 1+m-(m%n), D = degpol(P);4780long lM = lg(M), lmax = 0, c = 0;4781GEN v;4782for(;;)4783{4784GEN R, Pp, Mp, K;4785ulong pi;4786long l;4787do p += n; while (!uisprime(p));4788pi = get_Fl_red(p);4789Pp = ZX_to_Flx(P, p);4790R = Flx_roots(Pp, p);4791Mp = ZXM_to_FlxM(M, p, get_Flx_var(Pp));4792K = FlxM_eval_powers_pre(Mp, Fl_powers_pre(uel(R,1), D,p,pi), p,pi);4793v = Flm_indexrank(K, p);4794l = lg(gel(v,2));4795if (l == lM) break;4796if (lmax >= 0 && l > lmax) { lmax = l; c = 0; } else c++;4797if (c > 2)4798{ /* probably not maximal rank, expensive check */4799lM -= lg(ZabM_ker(M, P, n))-1; /* actual rank (+1) */4800if (lmax == lM) break;4801lmax = -1; /* disable check */4802}4803}4804return gerepileupto(av, v);4805}48064807#if 04808GEN4809ZabM_gauss(GEN M, GEN P, long n, GEN *den)4810{4811pari_sp av = avma;4812GEN v, S, W;4813v = ZabM_indexrank(M, P, n);4814S = shallowmatextract(M,gel(v,1),gel(v,2));4815W = ZabM_inv(S, P, n, den);4816gerepileall(av,2,&W,den);4817return W;4818}4819#endif48204821GEN4822ZabM_pseudoinv(GEN M, GEN P, long n, GEN *pv, GEN *den)4823{4824GEN v = ZabM_indexrank(M, P, n);4825if (pv) *pv = v;4826M = shallowmatextract(M,gel(v,1),gel(v,2));4827return ZabM_inv(M, P, n, den);4828}4829GEN4830ZM_pseudoinv(GEN M, GEN *pv, GEN *den)4831{4832GEN v = ZM_indexrank(M);4833if (pv) *pv = v;4834M = shallowmatextract(M,gel(v,1),gel(v,2));4835return ZM_inv(M, den);4836}48374838/*******************************************************************/4839/* */4840/* Structured Elimination */4841/* */4842/*******************************************************************/48434844static void4845rem_col(GEN c, long i, GEN iscol, GEN Wrow, long *rcol, long *rrow)4846{4847long lc = lg(c), k;4848iscol[i] = 0; (*rcol)--;4849for (k = 1; k < lc; ++k)4850{4851Wrow[c[k]]--;4852if (Wrow[c[k]]==0) (*rrow)--;4853}4854}48554856static void4857rem_singleton(GEN M, GEN iscol, GEN Wrow, long idx, long *rcol, long *rrow)4858{4859long i, j;4860long nbcol = lg(iscol)-1, last;4861do4862{4863last = 0;4864for (i = 1; i <= nbcol; ++i)4865if (iscol[i])4866{4867GEN c = idx ? gmael(M, i, idx): gel(M,i);4868long lc = lg(c);4869for (j = 1; j < lc; ++j)4870if (Wrow[c[j]] == 1)4871{4872rem_col(c, i, iscol, Wrow, rcol, rrow);4873last=1; break;4874}4875}4876} while (last);4877}48784879static GEN4880fill_wcol(GEN M, GEN iscol, GEN Wrow, long *w, GEN wcol)4881{4882long nbcol = lg(iscol)-1;4883long i, j, m, last;4884GEN per;4885for (m = 2, last=0; !last ; m++)4886{4887for (i = 1; i <= nbcol; ++i)4888{4889wcol[i] = 0;4890if (iscol[i])4891{4892GEN c = gmael(M, i, 1);4893long lc = lg(c);4894for (j = 1; j < lc; ++j)4895if (Wrow[c[j]] == m) { wcol[i]++; last = 1; }4896}4897}4898}4899per = vecsmall_indexsort(wcol);4900*w = wcol[per[nbcol]];4901return per;4902}49034904/* M is a RgMs with nbrow rows, A a list of row indices.4905Eliminate rows of M with a single entry that do not belong to A,4906and the corresponding columns. Also eliminate columns until #colums=#rows.4907Return pcol and prow:4908pcol is a map from the new columns indices to the old one.4909prow is a map from the old rows indices to the new one (0 if removed).4910*/49114912void4913RgMs_structelim_col(GEN M, long nbcol, long nbrow, GEN A, GEN *p_col, GEN *p_row)4914{4915long i,j,k;4916long lA = lg(A);4917GEN prow = cgetg(nbrow+1, t_VECSMALL);4918GEN pcol = zero_zv(nbcol);4919pari_sp av = avma;4920long rcol = nbcol, rrow = 0, imin = nbcol - usqrt(nbcol);4921GEN iscol = const_vecsmall(nbcol, 1);4922GEN Wrow = zero_zv(nbrow);4923GEN wcol = cgetg(nbcol+1, t_VECSMALL);4924pari_sp av2=avma;4925for (i = 1; i <= nbcol; ++i)4926{4927GEN F = gmael(M, i, 1);4928long l = lg(F)-1;4929for (j = 1; j <= l; ++j)4930Wrow[F[j]]++;4931}4932for (j = 1; j < lA; ++j)4933{4934if (Wrow[A[j]] == 0) { *p_col=NULL; return; }4935Wrow[A[j]] = -1;4936}4937for (i = 1; i <= nbrow; ++i)4938if (Wrow[i])4939rrow++;4940rem_singleton(M, iscol, Wrow, 1, &rcol, &rrow);4941if (rcol<rrow) pari_err_BUG("RgMs_structelim, rcol<rrow");4942for (; rcol>rrow;)4943{4944long w;4945GEN per = fill_wcol(M, iscol, Wrow, &w, wcol);4946for (i = nbcol; i>=imin && wcol[per[i]]>=w && rcol>rrow; i--)4947rem_col(gmael(M, per[i], 1), per[i], iscol, Wrow, &rcol, &rrow);4948rem_singleton(M, iscol, Wrow, 1, &rcol, &rrow);4949set_avma(av2);4950}4951for (j = 1, i = 1; i <= nbcol; ++i)4952if (iscol[i])4953pcol[j++] = i;4954setlg(pcol,j);4955for (k = 1, i = 1; i <= nbrow; ++i)4956prow[i] = Wrow[i] ? k++: 0;4957set_avma(av);4958*p_col = pcol; *p_row = prow;4959}49604961void4962RgMs_structelim(GEN M, long nbrow, GEN A, GEN *p_col, GEN *p_row)4963{4964RgMs_structelim_col(M, lg(M)-1, nbrow, A, p_col, p_row);4965}49664967GEN4968F2Ms_colelim(GEN M, long nbrow)4969{4970long i,j;4971long nbcol = lg(M)-1;4972GEN pcol = zero_zv(nbcol);4973pari_sp av = avma;4974long rcol = nbcol, rrow = 0;4975GEN iscol = const_vecsmall(nbcol, 1);4976GEN Wrow = zero_zv(nbrow);4977for (i = 1; i <= nbcol; ++i)4978{4979GEN F = gel(M, i);4980long l = lg(F)-1;4981for (j = 1; j <= l; ++j)4982Wrow[F[j]]++;4983}4984rem_singleton(M, iscol, Wrow, 0, &rcol, &rrow);4985for (j = 1, i = 1; i <= nbcol; ++i)4986if (iscol[i])4987pcol[j++] = i;4988fixlg(pcol,j);4989set_avma(av);4990return pcol;4991}49924993/*******************************************************************/4994/* */4995/* EIGENVECTORS */4996/* (independent eigenvectors, sorted by increasing eigenvalue) */4997/* */4998/*******************************************************************/4999/* assume x is square of dimension > 0 */5000static int5001RgM_is_symmetric_cx(GEN x, long bit)5002{5003pari_sp av = avma;5004long i, j, l = lg(x);5005for (i = 1; i < l; i++)5006for (j = 1; j < i; j++)5007{5008GEN a = gcoeff(x,i,j), b = gcoeff(x,j,i), c = gsub(a,b);5009if (!gequal0(c) && gexpo(c) - gexpo(a) > -bit) return gc_long(av,0);5010}5011return gc_long(av,1);5012}5013static GEN5014eigen_err(int exact, GEN x, long flag, long prec)5015{5016pari_sp av = avma;5017if (RgM_is_symmetric_cx(x, prec2nbits(prec) - 10))5018{ /* approximately symmetric: recover */5019x = jacobi(x, prec); if (flag) return x;5020return gerepilecopy(av, gel(x,2));5021}5022if (exact)5023{5024GEN y = mateigen(x, flag, precdbl(prec));5025return gerepilecopy(av, gprec_wtrunc(y, prec));5026}5027pari_err_PREC("mateigen");5028return NULL; /* LCOV_EXCL_LINE */5029}5030GEN5031mateigen(GEN x, long flag, long prec)5032{5033GEN y, R, T;5034long k, l, ex, n = lg(x);5035int exact;5036pari_sp av = avma;50375038if (typ(x)!=t_MAT) pari_err_TYPE("eigen",x);5039if (n != 1 && n != lgcols(x)) pari_err_DIM("eigen");5040if (flag < 0 || flag > 1) pari_err_FLAG("mateigen");5041if (n == 1)5042{5043if (flag) retmkvec2(cgetg(1,t_VEC), cgetg(1,t_MAT));5044return cgetg(1,t_VEC);5045}5046if (n == 2)5047{5048if (flag) retmkvec2(mkveccopy(gcoeff(x,1,1)), matid(1));5049return matid(1);5050}50515052ex = 16 - prec2nbits(prec);5053T = charpoly(x,0);5054exact = RgX_is_QX(T);5055if (exact)5056{5057T = ZX_radical( Q_primpart(T) );5058R = nfrootsQ(T);5059if (lg(R)-1 < degpol(T))5060{ /* add missing complex roots */5061GEN r = cleanroots(RgX_div(T, roots_to_pol(R, 0)), prec);5062settyp(r, t_VEC);5063R = shallowconcat(R, r);5064}5065}5066else5067{5068GEN r1, v = vectrunc_init(lg(T));5069long e;5070R = cleanroots(T,prec);5071r1 = NULL;5072for (k = 1; k < lg(R); k++)5073{5074GEN r2 = gel(R,k), r = grndtoi(r2, &e);5075if (e < ex) r2 = r;5076if (r1)5077{5078r = gsub(r1,r2);5079if (gequal0(r) || gexpo(r) < ex) continue;5080}5081vectrunc_append(v, r2);5082r1 = r2;5083}5084R = v;5085}5086/* R = distinct complex roots of charpoly(x) */5087l = lg(R); y = cgetg(l, t_VEC);5088for (k = 1; k < l; k++)5089{5090GEN F = ker_aux(RgM_Rg_sub_shallow(x, gel(R,k)), x);5091long d = lg(F)-1;5092if (!d) { set_avma(av); return eigen_err(exact, x, flag, prec); }5093gel(y,k) = F;5094if (flag) gel(R,k) = const_vec(d, gel(R,k));5095}5096y = shallowconcat1(y);5097if (lg(y) > n) { set_avma(av); return eigen_err(exact, x, flag, prec); }5098/* lg(y) < n if x is not diagonalizable */5099if (flag) y = mkvec2(shallowconcat1(R), y);5100return gerepilecopy(av,y);5101}5102GEN5103eigen(GEN x, long prec) { return mateigen(x, 0, prec); }51045105/*******************************************************************/5106/* */5107/* DETERMINANT */5108/* */5109/*******************************************************************/51105111GEN5112det0(GEN a,long flag)5113{5114switch(flag)5115{5116case 0: return det(a);5117case 1: return det2(a);5118default: pari_err_FLAG("matdet");5119}5120return NULL; /* LCOV_EXCL_LINE */5121}51225123/* M a 2x2 matrix, returns det(M) */5124static GEN5125RgM_det2(GEN M)5126{5127pari_sp av = avma;5128GEN a = gcoeff(M,1,1), b = gcoeff(M,1,2);5129GEN c = gcoeff(M,2,1), d = gcoeff(M,2,2);5130return gerepileupto(av, gsub(gmul(a,d), gmul(b,c)));5131}5132/* M a 2x2 ZM, returns det(M) */5133static GEN5134ZM_det2(GEN M)5135{5136pari_sp av = avma;5137GEN a = gcoeff(M,1,1), b = gcoeff(M,1,2);5138GEN c = gcoeff(M,2,1), d = gcoeff(M,2,2);5139return gerepileuptoint(av, subii(mulii(a,d), mulii(b, c)));5140}5141/* M a 3x3 ZM, return det(M) */5142static GEN5143ZM_det3(GEN M)5144{5145pari_sp av = avma;5146GEN a = gcoeff(M,1,1), b = gcoeff(M,1,2), c = gcoeff(M,1,3);5147GEN d = gcoeff(M,2,1), e = gcoeff(M,2,2), f = gcoeff(M,2,3);5148GEN g = gcoeff(M,3,1), h = gcoeff(M,3,2), i = gcoeff(M,3,3);5149GEN t, D = signe(i)? mulii(subii(mulii(a,e), mulii(b,d)), i): gen_0;5150if (signe(g))5151{5152t = mulii(subii(mulii(b,f), mulii(c,e)), g);5153D = addii(D, t);5154}5155if (signe(h))5156{5157t = mulii(subii(mulii(c,d), mulii(a,f)), h);5158D = addii(D, t);5159}5160return gerepileuptoint(av, D);5161}51625163static GEN5164det_simple_gauss(GEN a, GEN data, pivot_fun pivot)5165{5166pari_sp av = avma;5167long i,j,k, s = 1, nbco = lg(a)-1;5168GEN p, x = gen_1;51695170a = RgM_shallowcopy(a);5171for (i=1; i<nbco; i++)5172{5173k = pivot(a, data, i, NULL);5174if (k > nbco) return gerepilecopy(av, gcoeff(a,i,i));5175if (k != i)5176{ /* exchange the lines s.t. k = i */5177for (j=i; j<=nbco; j++) swap(gcoeff(a,i,j), gcoeff(a,k,j));5178s = -s;5179}5180p = gcoeff(a,i,i);51815182x = gmul(x,p);5183for (k=i+1; k<=nbco; k++)5184{5185GEN m = gcoeff(a,i,k);5186if (gequal0(m)) continue;51875188m = gdiv(m,p);5189for (j=i+1; j<=nbco; j++)5190gcoeff(a,j,k) = gsub(gcoeff(a,j,k), gmul(m,gcoeff(a,j,i)));5191}5192if (gc_needed(av,2))5193{5194if(DEBUGMEM>1) pari_warn(warnmem,"det. col = %ld",i);5195gerepileall(av,2, &a,&x);5196}5197}5198if (s < 0) x = gneg_i(x);5199return gerepileupto(av, gmul(x, gcoeff(a,nbco,nbco)));5200}52015202GEN5203det2(GEN a)5204{5205GEN data;5206pivot_fun pivot;5207long n = lg(a)-1;5208if (typ(a)!=t_MAT) pari_err_TYPE("det2",a);5209if (!n) return gen_1;5210if (n != nbrows(a)) pari_err_DIM("det2");5211if (n == 1) return gcopy(gcoeff(a,1,1));5212if (n == 2) return RgM_det2(a);5213pivot = get_pivot_fun(a, a, &data);5214return det_simple_gauss(a, data, pivot);5215}52165217/* Assumes a a square t_MAT of dimension n > 0. Returns det(a) using5218* Gauss-Bareiss. */5219static GEN5220det_bareiss(GEN a)5221{5222pari_sp av = avma;5223long nbco = lg(a)-1,i,j,k,s = 1;5224GEN p, pprec;52255226a = RgM_shallowcopy(a);5227for (pprec=gen_1,i=1; i<nbco; i++,pprec=p)5228{5229int diveuc = (gequal1(pprec)==0);5230GEN ci;52315232p = gcoeff(a,i,i);5233if (gequal0(p))5234{5235k=i+1; while (k<=nbco && gequal0(gcoeff(a,i,k))) k++;5236if (k>nbco) return gerepilecopy(av, p);5237swap(gel(a,k), gel(a,i)); s = -s;5238p = gcoeff(a,i,i);5239}5240ci = gel(a,i);5241for (k=i+1; k<=nbco; k++)5242{5243GEN ck = gel(a,k), m = gel(ck,i);5244if (gequal0(m))5245{5246if (gequal1(p))5247{5248if (diveuc)5249gel(a,k) = gdiv(gel(a,k), pprec);5250}5251else5252for (j=i+1; j<=nbco; j++)5253{5254GEN p1 = gmul(p, gel(ck,j));5255if (diveuc) p1 = gdiv(p1,pprec);5256gel(ck,j) = p1;5257}5258}5259else5260for (j=i+1; j<=nbco; j++)5261{5262pari_sp av2 = avma;5263GEN p1 = gsub(gmul(p,gel(ck,j)), gmul(m,gel(ci,j)));5264if (diveuc) p1 = gdiv(p1,pprec);5265gel(ck,j) = gerepileupto(av2, p1);5266}5267if (gc_needed(av,2))5268{5269if(DEBUGMEM>1) pari_warn(warnmem,"det. col = %ld",i);5270gerepileall(av,2, &a,&pprec);5271ci = gel(a,i);5272p = gcoeff(a,i,i);5273}5274}5275}5276p = gcoeff(a,nbco,nbco);5277p = (s < 0)? gneg(p): gcopy(p);5278return gerepileupto(av, p);5279}52805281/* count nonzero entries in col j, at most 'max' of them.5282* Return their indices */5283static GEN5284col_count_non_zero(GEN a, long j, long max)5285{5286GEN v = cgetg(max+1, t_VECSMALL);5287GEN c = gel(a,j);5288long i, l = lg(a), k = 1;5289for (i = 1; i < l; i++)5290if (!gequal0(gel(c,i)))5291{5292if (k > max) return NULL; /* fail */5293v[k++] = i;5294}5295setlg(v, k); return v;5296}5297/* count nonzero entries in row i, at most 'max' of them.5298* Return their indices */5299static GEN5300row_count_non_zero(GEN a, long i, long max)5301{5302GEN v = cgetg(max+1, t_VECSMALL);5303long j, l = lg(a), k = 1;5304for (j = 1; j < l; j++)5305if (!gequal0(gcoeff(a,i,j)))5306{5307if (k > max) return NULL; /* fail */5308v[k++] = j;5309}5310setlg(v, k); return v;5311}53125313static GEN det_develop(GEN a, long max, double bound);5314/* (-1)^(i+j) a[i,j] * det RgM_minor(a,i,j) */5315static GEN5316coeff_det(GEN a, long i, long j, long max, double bound)5317{5318GEN c = gcoeff(a, i, j);5319c = gmul(c, det_develop(RgM_minor(a, i,j), max, bound));5320if (odd(i+j)) c = gneg(c);5321return c;5322}5323/* a square t_MAT, 'bound' a rough upper bound for the number of5324* multiplications we are willing to pay while developing rows/columns before5325* switching to Gaussian elimination */5326static GEN5327det_develop(GEN M, long max, double bound)5328{5329pari_sp av = avma;5330long i,j, n = lg(M)-1, lbest = max+2, best_col = 0, best_row = 0;5331GEN best = NULL;53325333if (bound < 1.) return det_bareiss(M); /* too costly now */53345335switch(n)5336{5337case 0: return gen_1;5338case 1: return gcopy(gcoeff(M,1,1));5339case 2: return RgM_det2(M);5340}5341if (max > ((n+2)>>1)) max = (n+2)>>1;5342for (j = 1; j <= n; j++)5343{5344pari_sp av2 = avma;5345GEN v = col_count_non_zero(M, j, max);5346long lv;5347if (!v || (lv = lg(v)) >= lbest) { set_avma(av2); continue; }5348if (lv == 1) { set_avma(av); return gen_0; }5349if (lv == 2) {5350set_avma(av);5351return gerepileupto(av, coeff_det(M,v[1],j,max,bound));5352}5353best = v; lbest = lv; best_col = j;5354}5355for (i = 1; i <= n; i++)5356{5357pari_sp av2 = avma;5358GEN v = row_count_non_zero(M, i, max);5359long lv;5360if (!v || (lv = lg(v)) >= lbest) { set_avma(av2); continue; }5361if (lv == 1) { set_avma(av); return gen_0; }5362if (lv == 2) {5363set_avma(av);5364return gerepileupto(av, coeff_det(M,i,v[1],max,bound));5365}5366best = v; lbest = lv; best_row = i;5367}5368if (best_row)5369{5370double d = lbest-1;5371GEN s = NULL;5372long k;5373bound /= d*d*d;5374for (k = 1; k < lbest; k++)5375{5376GEN c = coeff_det(M, best_row, best[k], max, bound);5377s = s? gadd(s, c): c;5378}5379return gerepileupto(av, s);5380}5381if (best_col)5382{5383double d = lbest-1;5384GEN s = NULL;5385long k;5386bound /= d*d*d;5387for (k = 1; k < lbest; k++)5388{5389GEN c = coeff_det(M, best[k], best_col, max, bound);5390s = s? gadd(s, c): c;5391}5392return gerepileupto(av, s);5393}5394return det_bareiss(M);5395}53965397/* area of parallelogram bounded by (v1,v2) */5398static GEN5399parallelogramarea(GEN v1, GEN v2)5400{ return gsub(gmul(gnorml2(v1), gnorml2(v2)), gsqr(RgV_dotproduct(v1, v2))); }54015402/* Square of Hadamard bound for det(a), a square matrix.5403* Slight improvement: instead of using the column norms, use the area of5404* the parallelogram formed by pairs of consecutive vectors */5405GEN5406RgM_Hadamard(GEN a)5407{5408pari_sp av = avma;5409long n = lg(a)-1, i;5410GEN B;5411if (n == 0) return gen_1;5412if (n == 1) return gsqr(gcoeff(a,1,1));5413a = RgM_gtofp(a, LOWDEFAULTPREC);5414B = gen_1;5415for (i = 1; i <= n/2; i++)5416B = gmul(B, parallelogramarea(gel(a,2*i-1), gel(a,2*i)));5417if (odd(n)) B = gmul(B, gnorml2(gel(a, n)));5418return gerepileuptoint(av, ceil_safe(B));5419}54205421/* If B=NULL, assume B=A' */5422static GEN5423ZM_det_slice(GEN A, GEN P, GEN *mod)5424{5425pari_sp av = avma;5426long i, n = lg(P)-1;5427GEN H, T;5428if (n == 1)5429{5430ulong Hp, p = uel(P,1);5431GEN a = ZM_to_Flm(A, p);5432Hp = Flm_det_sp(a, p);5433set_avma(av); *mod = utoipos(p); return utoi(Hp);5434}5435T = ZV_producttree(P);5436A = ZM_nv_mod_tree(A, P, T);5437H = cgetg(n+1, t_VECSMALL);5438for(i=1; i <= n; i++)5439{5440ulong p = P[i];5441GEN a = gel(A,i);5442H[i] = Flm_det_sp(a, p);5443}5444H = ZV_chinese_tree(H, P, T, ZV_chinesetree(P,T));5445*mod = gmael(T, lg(T)-1, 1);5446gerepileall(av, 2, &H, mod); return H;5447}54485449GEN5450ZM_det_worker(GEN P, GEN A)5451{5452GEN V = cgetg(3, t_VEC);5453gel(V,1) = ZM_det_slice(A, P, &gel(V,2));5454return V;5455}54565457GEN5458ZM_det(GEN M)5459{5460const long DIXON_THRESHOLD = 40;5461pari_sp av, av2;5462long i, n = lg(M)-1;5463ulong p, Dp;5464forprime_t S;5465pari_timer ti;5466GEN H, D, mod, h, q, v, worker;5467#ifdef LONG_IS_64BIT5468const ulong PMAX = 18446744073709551557UL;5469#else5470const ulong PMAX = 4294967291UL;5471#endif54725473switch(n)5474{5475case 0: return gen_1;5476case 1: return icopy(gcoeff(M,1,1));5477case 2: return ZM_det2(M);5478case 3: return ZM_det3(M);5479}5480if (DEBUGLEVEL>=4) timer_start(&ti);5481av = avma; h = RgM_Hadamard(M); /* |D| <= sqrt(h) */5482if (!signe(h)) { set_avma(av); return gen_0; }5483h = sqrti(h);5484if (lgefint(h) == 3 && (ulong)h[2] <= (PMAX >> 1))5485{ /* h < p/2 => direct result */5486p = PMAX;5487Dp = Flm_det_sp(ZM_to_Flm(M, p), p);5488set_avma(av);5489if (!Dp) return gen_0;5490return (Dp <= (p>>1))? utoipos(Dp): utoineg(p - Dp);5491}5492q = gen_1; Dp = 1;5493init_modular_big(&S);5494p = 0; /* -Wall */5495while (cmpii(q, h) <= 0 && (p = u_forprime_next(&S)))5496{5497av2 = avma; Dp = Flm_det_sp(ZM_to_Flm(M, p), p);5498set_avma(av2);5499if (Dp) break;5500q = muliu(q, p);5501}5502if (!p) pari_err_OVERFLOW("ZM_det [ran out of primes]");5503if (!Dp) { set_avma(av); return gen_0; }5504if (mt_nbthreads() > 1 || n <= DIXON_THRESHOLD)5505D = q; /* never competitive when bound is sharp even with 2 threads */5506else5507{5508av2 = avma;5509v = cgetg(n+1, t_COL);5510gel(v, 1) = gen_1; /* ensure content(v) = 1 */5511for (i = 2; i <= n; i++) gel(v, i) = stoi(random_Fl(15) - 7);5512D = Q_denom(ZM_gauss(M, v));5513if (expi(D) < expi(h) >> 1)5514{ /* First try unlucky, try once more */5515for (i = 2; i <= n; i++) gel(v, i) = stoi(random_Fl(15) - 7);5516D = lcmii(D, Q_denom(ZM_gauss(M, v)));5517}5518D = gerepileuptoint(av2, D);5519if (q != gen_1) D = lcmii(D, q);5520}5521if (DEBUGLEVEL >=4)5522timer_printf(&ti,"ZM_det: Dixon %ld/%ld bits",expi(D),expi(h));5523/* determinant is a multiple of D */5524if (is_pm1(D)) D = NULL;5525if (D) h = diviiexact(h, D);5526worker = snm_closure(is_entry("_ZM_det_worker"), mkvec(M));5527H = gen_crt("ZM_det", worker, &S, D, expi(h)+1, 0, &mod,5528ZV_chinese, NULL);5529if (D) H = Fp_div(H, D, mod);5530H = Fp_center(H, mod, shifti(mod,-1));5531if (D) H = mulii(H, D);5532return gerepileuptoint(av, H);5533}55345535static GEN5536RgM_det_FpM(GEN a, GEN p)5537{5538pari_sp av = avma;5539ulong pp, d;5540a = RgM_Fp_init(a,p,&pp);5541switch(pp)5542{5543case 0: return gerepileupto(av, Fp_to_mod(FpM_det(a,p),p)); break;5544case 2: d = F2m_det_sp(a); break;5545default:d = Flm_det_sp(a, pp); break;5546}5547set_avma(av); return mkintmodu(d, pp);5548}55495550static GEN5551RgM_det_FqM(GEN x, GEN pol, GEN p)5552{5553pari_sp av = avma;5554GEN b, T = RgX_to_FpX(pol, p);5555if (signe(T) == 0) pari_err_OP("%",x,pol);5556b = FqM_det(RgM_to_FqM(x, T, p), T, p);5557if (!b) return gc_NULL(av);5558return gerepilecopy(av, mkpolmod(FpX_to_mod(b, p), FpX_to_mod(T, p)));5559}55605561#define code(t1,t2) ((t1 << 6) | t2)5562static GEN5563RgM_det_fast(GEN x)5564{5565GEN p, pol;5566long pa;5567long t = RgM_type(x, &p,&pol,&pa);5568switch(t)5569{5570case t_INT: return ZM_det(x);5571case t_FRAC: return QM_det(x);5572case t_FFELT: return FFM_det(x, pol);5573case t_INTMOD: return RgM_det_FpM(x, p);5574case code(t_POLMOD, t_INTMOD):5575return RgM_det_FqM(x, pol, p);5576default: return NULL;5577}5578}5579#undef code55805581static long5582det_init_max(long n)5583{5584if (n > 100) return 0;5585if (n > 50) return 1;5586if (n > 30) return 4;5587return 7;5588}55895590GEN5591det(GEN a)5592{5593long n = lg(a)-1;5594double B;5595GEN data, b;5596pivot_fun pivot;55975598if (typ(a)!=t_MAT) pari_err_TYPE("det",a);5599if (!n) return gen_1;5600if (n != nbrows(a)) pari_err_DIM("det");5601if (n == 1) return gcopy(gcoeff(a,1,1));5602if (n == 2) return RgM_det2(a);5603b = RgM_det_fast(a);5604if (b) return b;5605pivot = get_pivot_fun(a, a, &data);5606if (pivot != gauss_get_pivot_NZ) return det_simple_gauss(a, data, pivot);5607B = (double)n;5608return det_develop(a, det_init_max(n), B*B*B);5609}56105611GEN5612QM_det(GEN M)5613{5614pari_sp av = avma;5615GEN cM, pM = Q_primitive_part(M, &cM);5616GEN b = ZM_det(pM);5617if (cM) b = gmul(b, gpowgs(cM, lg(M)-1));5618return gerepileupto(av, b);5619}562056215622