Line data Source code
1 : /* Copyright (C) 2000, 2012 The PARI group.
2 :
3 : This file is part of the PARI/GP package.
4 :
5 : PARI/GP is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU General Public License as published by the Free Software
7 : Foundation; either version 2 of the License, or (at your option) any later
8 : version. It is distributed in the hope that it will be useful, but WITHOUT
9 : ANY WARRANTY WHATSOEVER.
10 :
11 : Check the License for details. You should have received a copy of it, along
12 : with the package; see the file 'COPYING'. If not, write to the Free Software
13 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
14 :
15 : /********************************************************************/
16 : /** **/
17 : /** LINEAR ALGEBRA **/
18 : /** (first part) **/
19 : /** **/
20 : /********************************************************************/
21 : #include "pari.h"
22 : #include "paripriv.h"
23 :
24 : #define DEBUGLEVEL DEBUGLEVEL_mat
25 :
26 : /*******************************************************************/
27 : /* */
28 : /* GEREPILE */
29 : /* */
30 : /*******************************************************************/
31 :
32 : static void
33 0 : gerepile_mat(pari_sp av, pari_sp tetpil, GEN x, long k, long m, long n, long t)
34 : {
35 0 : pari_sp A, bot = pari_mainstack->bot;
36 : long u, i;
37 : size_t dec;
38 :
39 0 : (void)gerepile(av,tetpil,NULL); dec = av-tetpil;
40 :
41 0 : for (u=t+1; u<=m; u++)
42 : {
43 0 : A = (pari_sp)coeff(x,u,k);
44 0 : if (A < av && A >= bot) coeff(x,u,k) += dec;
45 : }
46 0 : for (i=k+1; i<=n; i++)
47 0 : for (u=1; u<=m; u++)
48 : {
49 0 : A = (pari_sp)coeff(x,u,i);
50 0 : if (A < av && A >= bot) coeff(x,u,i) += dec;
51 : }
52 0 : }
53 :
54 : static void
55 0 : gen_gerepile_gauss_ker(GEN x, long k, long t, pari_sp av, void *E, GEN (*copy)(void*, GEN))
56 : {
57 0 : pari_sp tetpil = avma;
58 0 : long u,i, n = lg(x)-1, m = n? nbrows(x): 0;
59 :
60 0 : if (DEBUGMEM > 1) pari_warn(warnmem,"gauss_pivot_ker. k=%ld, n=%ld",k,n);
61 0 : for (u=t+1; u<=m; u++) gcoeff(x,u,k) = copy(E,gcoeff(x,u,k));
62 0 : for (i=k+1; i<=n; i++)
63 0 : for (u=1; u<=m; u++) gcoeff(x,u,i) = copy(E,gcoeff(x,u,i));
64 0 : gerepile_mat(av,tetpil,x,k,m,n,t);
65 0 : }
66 :
67 : /* special gerepile for huge matrices */
68 :
69 : #define COPY(x) {\
70 : GEN _t = (x); if (!is_universal_constant(_t)) x = gcopy(_t); \
71 : }
72 :
73 : INLINE GEN
74 0 : _copy(void *E, GEN x)
75 : {
76 0 : (void) E; COPY(x);
77 0 : return x;
78 : }
79 :
80 : static void
81 0 : gerepile_gauss_ker(GEN x, long k, long t, pari_sp av)
82 : {
83 0 : gen_gerepile_gauss_ker(x, k, t, av, NULL, &_copy);
84 0 : }
85 :
86 : static void
87 0 : gerepile_gauss(GEN x,long k,long t,pari_sp av, long j, GEN c)
88 : {
89 0 : pari_sp tetpil = avma, A, bot;
90 0 : long u,i, n = lg(x)-1, m = n? nbrows(x): 0;
91 : size_t dec;
92 :
93 0 : if (DEBUGMEM > 1) pari_warn(warnmem,"gauss_pivot. k=%ld, n=%ld",k,n);
94 0 : for (u=t+1; u<=m; u++)
95 0 : if (u==j || !c[u]) COPY(gcoeff(x,u,k));
96 0 : for (u=1; u<=m; u++)
97 0 : if (u==j || !c[u])
98 0 : for (i=k+1; i<=n; i++) COPY(gcoeff(x,u,i));
99 :
100 0 : (void)gerepile(av,tetpil,NULL); dec = av-tetpil;
101 0 : bot = pari_mainstack->bot;
102 0 : for (u=t+1; u<=m; u++)
103 0 : if (u==j || !c[u])
104 : {
105 0 : A=(pari_sp)coeff(x,u,k);
106 0 : if (A<av && A>=bot) coeff(x,u,k)+=dec;
107 : }
108 0 : for (u=1; u<=m; u++)
109 0 : if (u==j || !c[u])
110 0 : for (i=k+1; i<=n; i++)
111 : {
112 0 : A=(pari_sp)coeff(x,u,i);
113 0 : if (A<av && A>=bot) coeff(x,u,i)+=dec;
114 : }
115 0 : }
116 :
117 : /*******************************************************************/
118 : /* */
119 : /* GENERIC */
120 : /* */
121 : /*******************************************************************/
122 : GEN
123 1906 : gen_ker(GEN x, long deplin, void *E, const struct bb_field *ff)
124 : {
125 1906 : pari_sp av0 = avma, av, tetpil;
126 : GEN y, c, d;
127 : long i, j, k, r, t, n, m;
128 :
129 1906 : n=lg(x)-1; if (!n) return cgetg(1,t_MAT);
130 1906 : m=nbrows(x); r=0;
131 1906 : x = RgM_shallowcopy(x);
132 1906 : c = zero_zv(m);
133 1906 : d=new_chunk(n+1);
134 1906 : av=avma;
135 6897 : for (k=1; k<=n; k++)
136 : {
137 15211 : for (j=1; j<=m; j++)
138 13052 : if (!c[j])
139 : {
140 9266 : gcoeff(x,j,k) = ff->red(E, gcoeff(x,j,k));
141 9266 : if (!ff->equal0(gcoeff(x,j,k))) break;
142 : }
143 5026 : if (j>m)
144 : {
145 2159 : if (deplin)
146 : {
147 35 : GEN c = cgetg(n+1, t_COL), g0 = ff->s(E,0), g1=ff->s(E,1);
148 98 : for (i=1; i<k; i++) gel(c,i) = ff->red(E, gcoeff(x,d[i],k));
149 63 : gel(c,k) = g1; for (i=k+1; i<=n; i++) gel(c,i) = g0;
150 35 : return gerepileupto(av0, c);
151 : }
152 2124 : r++; d[k]=0;
153 5101 : for(j=1; j<k; j++)
154 2977 : if (d[j]) gcoeff(x,d[j],k) = gclone(gcoeff(x,d[j],k));
155 : }
156 : else
157 : {
158 2867 : GEN piv = ff->neg(E,ff->inv(E,gcoeff(x,j,k)));
159 2867 : c[j] = k; d[k] = j;
160 2867 : gcoeff(x,j,k) = ff->s(E,-1);
161 6888 : for (i=k+1; i<=n; i++) gcoeff(x,j,i) = ff->red(E,ff->mul(E,piv,gcoeff(x,j,i)));
162 16275 : for (t=1; t<=m; t++)
163 : {
164 13408 : if (t==j) continue;
165 :
166 10541 : piv = ff->red(E,gcoeff(x,t,k));
167 10541 : if (ff->equal0(piv)) continue;
168 :
169 3105 : gcoeff(x,t,k) = ff->s(E,0);
170 7570 : for (i=k+1; i<=n; i++)
171 4465 : gcoeff(x,t,i) = ff->red(E, ff->add(E, gcoeff(x,t,i),
172 4465 : ff->mul(E,piv,gcoeff(x,j,i))));
173 3105 : if (gc_needed(av,1))
174 0 : gen_gerepile_gauss_ker(x,k,t,av,E,ff->red);
175 : }
176 : }
177 : }
178 1871 : if (deplin) return gc_NULL(av0);
179 :
180 1843 : tetpil=avma; y=cgetg(r+1,t_MAT);
181 3967 : for (j=k=1; j<=r; j++,k++)
182 : {
183 2124 : GEN C = cgetg(n+1,t_COL);
184 2124 : GEN g0 = ff->s(E,0), g1 = ff->s(E,1);
185 4092 : gel(y,j) = C; while (d[k]) k++;
186 5101 : for (i=1; i<k; i++)
187 2977 : if (d[i])
188 : {
189 2427 : GEN p1=gcoeff(x,d[i],k);
190 2427 : gel(C,i) = ff->red(E,p1); gunclone(p1);
191 : }
192 : else
193 550 : gel(C,i) = g0;
194 2969 : gel(C,k) = g1; for (i=k+1; i<=n; i++) gel(C,i) = g0;
195 : }
196 1843 : return gerepile(av0,tetpil,y);
197 : }
198 :
199 : GEN
200 1891 : gen_Gauss_pivot(GEN x, long *rr, void *E, const struct bb_field *ff)
201 : {
202 : pari_sp av;
203 : GEN c, d;
204 1891 : long i, j, k, r, t, m, n = lg(x)-1;
205 :
206 1891 : if (!n) { *rr = 0; return NULL; }
207 :
208 1891 : m=nbrows(x); r=0;
209 1891 : d = cgetg(n+1, t_VECSMALL);
210 1891 : x = RgM_shallowcopy(x);
211 1891 : c = zero_zv(m);
212 1891 : av=avma;
213 6830 : for (k=1; k<=n; k++)
214 : {
215 13696 : for (j=1; j<=m; j++)
216 13088 : if (!c[j])
217 : {
218 9200 : gcoeff(x,j,k) = ff->red(E,gcoeff(x,j,k));
219 9200 : if (!ff->equal0(gcoeff(x,j,k))) break;
220 : }
221 4939 : if (j>m) { r++; d[k]=0; }
222 : else
223 : {
224 4331 : GEN piv = ff->neg(E,ff->inv(E,gcoeff(x,j,k)));
225 4331 : GEN g0 = ff->s(E,0);
226 4331 : c[j] = k; d[k] = j;
227 9032 : for (i=k+1; i<=n; i++) gcoeff(x,j,i) = ff->red(E,ff->mul(E,piv,gcoeff(x,j,i)));
228 26263 : for (t=1; t<=m; t++)
229 : {
230 21932 : if (c[t]) continue; /* already a pivot on that line */
231 :
232 13493 : piv = ff->red(E,gcoeff(x,t,k));
233 13493 : if (ff->equal0(piv)) continue;
234 5346 : gcoeff(x,t,k) = g0;
235 9841 : for (i=k+1; i<=n; i++)
236 4495 : gcoeff(x,t,i) = ff->red(E, ff->add(E,gcoeff(x,t,i), ff->mul(E,piv,gcoeff(x,j,i))));
237 5346 : if (gc_needed(av,1))
238 0 : gerepile_gauss(x,k,t,av,j,c);
239 : }
240 13363 : for (i=k; i<=n; i++) gcoeff(x,j,i) = g0; /* dummy */
241 : }
242 : }
243 1891 : *rr = r; return gc_const((pari_sp)d, d);
244 : }
245 :
246 : GEN
247 294 : gen_det(GEN a, void *E, const struct bb_field *ff)
248 : {
249 294 : pari_sp av = avma;
250 294 : long i,j,k, s = 1, nbco = lg(a)-1;
251 294 : GEN x = ff->s(E,1);
252 294 : if (!nbco) return x;
253 287 : a = RgM_shallowcopy(a);
254 1064 : for (i=1; i<nbco; i++)
255 : {
256 : GEN q;
257 1029 : for(k=i; k<=nbco; k++)
258 : {
259 994 : gcoeff(a,k,i) = ff->red(E,gcoeff(a,k,i));
260 994 : if (!ff->equal0(gcoeff(a,k,i))) break;
261 : }
262 812 : if (k > nbco) return gerepileupto(av, gcoeff(a,i,i));
263 777 : if (k != i)
264 : { /* exchange the lines s.t. k = i */
265 413 : for (j=i; j<=nbco; j++) swap(gcoeff(a,i,j), gcoeff(a,k,j));
266 105 : s = -s;
267 : }
268 777 : q = gcoeff(a,i,i);
269 777 : x = ff->red(E,ff->mul(E,x,q));
270 777 : q = ff->inv(E,q);
271 2324 : for (k=i+1; k<=nbco; k++)
272 : {
273 1547 : GEN m = ff->red(E,gcoeff(a,i,k));
274 1547 : if (ff->equal0(m)) continue;
275 1092 : m = ff->neg(E, ff->red(E,ff->mul(E,m, q)));
276 3528 : for (j=i+1; j<=nbco; j++)
277 2436 : gcoeff(a,j,k) = ff->red(E, ff->add(E, gcoeff(a,j,k),
278 2436 : ff->mul(E, m, gcoeff(a,j,i))));
279 : }
280 777 : if (gc_needed(av,2))
281 : {
282 0 : if(DEBUGMEM>1) pari_warn(warnmem,"det. col = %ld",i);
283 0 : gerepileall(av,2, &a,&x);
284 : }
285 : }
286 252 : if (s < 0) x = ff->neg(E,x);
287 252 : return gerepileupto(av, ff->red(E,ff->mul(E, x, gcoeff(a,nbco,nbco))));
288 : }
289 :
290 : INLINE void
291 145653 : _gen_addmul(GEN b, long k, long i, GEN m, void *E, const struct bb_field *ff)
292 : {
293 145653 : gel(b,i) = ff->red(E,gel(b,i));
294 145653 : gel(b,k) = ff->add(E,gel(b,k), ff->mul(E,m, gel(b,i)));
295 145653 : }
296 :
297 : static GEN
298 61724 : _gen_get_col(GEN a, GEN b, long li, void *E, const struct bb_field *ff)
299 : {
300 61724 : GEN u = cgetg(li+1,t_COL);
301 61724 : pari_sp av = avma;
302 : long i, j;
303 :
304 61724 : gel(u,li) = gerepileupto(av, ff->red(E,ff->mul(E,gel(b,li), gcoeff(a,li,li))));
305 318729 : for (i=li-1; i>0; i--)
306 : {
307 257005 : pari_sp av = avma;
308 257005 : GEN m = gel(b,i);
309 1018258 : for (j=i+1; j<=li; j++) m = ff->add(E,m, ff->neg(E,ff->mul(E,gcoeff(a,i,j), gel(u,j))));
310 257005 : m = ff->red(E, m);
311 257005 : gel(u,i) = gerepileupto(av, ff->red(E,ff->mul(E,m, gcoeff(a,i,i))));
312 : }
313 61724 : return u;
314 : }
315 :
316 : GEN
317 13612 : gen_Gauss(GEN a, GEN b, void *E, const struct bb_field *ff)
318 : {
319 : long i, j, k, li, bco, aco;
320 13612 : GEN u, g0 = ff->s(E,0);
321 13612 : pari_sp av = avma;
322 13612 : a = RgM_shallowcopy(a);
323 13612 : b = RgM_shallowcopy(b);
324 13612 : aco = lg(a)-1; bco = lg(b)-1; li = nbrows(a);
325 60478 : for (i=1; i<=aco; i++)
326 : {
327 : GEN invpiv;
328 73118 : for (k = i; k <= li; k++)
329 : {
330 73062 : GEN piv = ff->red(E,gcoeff(a,k,i));
331 73062 : if (!ff->equal0(piv)) { gcoeff(a,k,i) = ff->inv(E,piv); break; }
332 12640 : gcoeff(a,k,i) = g0;
333 : }
334 : /* found a pivot on line k */
335 60478 : if (k > li) return NULL;
336 60422 : if (k != i)
337 : { /* swap lines so that k = i */
338 52266 : for (j=i; j<=aco; j++) swap(gcoeff(a,i,j), gcoeff(a,k,j));
339 69813 : for (j=1; j<=bco; j++) swap(gcoeff(b,i,j), gcoeff(b,k,j));
340 : }
341 60422 : if (i == aco) break;
342 :
343 46866 : invpiv = gcoeff(a,i,i); /* 1/piv mod p */
344 176184 : for (k=i+1; k<=li; k++)
345 : {
346 129318 : GEN m = ff->red(E,gcoeff(a,k,i)); gcoeff(a,k,i) = g0;
347 129318 : if (ff->equal0(m)) continue;
348 :
349 17311 : m = ff->red(E,ff->neg(E,ff->mul(E,m, invpiv)));
350 71287 : for (j=i+1; j<=aco; j++) _gen_addmul(gel(a,j),k,i,m,E,ff);
351 108988 : for (j=1 ; j<=bco; j++) _gen_addmul(gel(b,j),k,i,m,E,ff);
352 : }
353 46866 : if (gc_needed(av,1))
354 : {
355 0 : if(DEBUGMEM>1) pari_warn(warnmem,"gen_Gauss. i=%ld",i);
356 0 : gerepileall(av,2, &a,&b);
357 : }
358 : }
359 :
360 13556 : if(DEBUGLEVEL>4) err_printf("Solving the triangular system\n");
361 13556 : u = cgetg(bco+1,t_MAT);
362 75280 : for (j=1; j<=bco; j++) gel(u,j) = _gen_get_col(a, gel(b,j), aco, E, ff);
363 13556 : return u;
364 : }
365 :
366 : /* compatible t_MAT * t_COL, lgA = lg(A) = lg(B) > 1, l = lgcols(A) */
367 : static GEN
368 644421 : gen_matcolmul_i(GEN A, GEN B, ulong lgA, ulong l,
369 : void *E, const struct bb_field *ff)
370 : {
371 644421 : GEN C = cgetg(l, t_COL);
372 : ulong i;
373 4217217 : for (i = 1; i < l; i++) {
374 3572796 : pari_sp av = avma;
375 3572796 : GEN e = ff->mul(E, gcoeff(A, i, 1), gel(B, 1));
376 : ulong k;
377 15412672 : for(k = 2; k < lgA; k++)
378 11839876 : e = ff->add(E, e, ff->mul(E, gcoeff(A, i, k), gel(B, k)));
379 3572796 : gel(C, i) = gerepileupto(av, ff->red(E, e));
380 : }
381 644421 : return C;
382 : }
383 :
384 : GEN
385 206341 : gen_matcolmul(GEN A, GEN B, void *E, const struct bb_field *ff)
386 : {
387 206341 : ulong lgA = lg(A);
388 206341 : if (lgA != (ulong)lg(B))
389 0 : pari_err_OP("operation 'gen_matcolmul'", A, B);
390 206341 : if (lgA == 1)
391 0 : return cgetg(1, t_COL);
392 206341 : return gen_matcolmul_i(A, B, lgA, lgcols(A), E, ff);
393 : }
394 :
395 : static GEN
396 85117 : gen_matmul_classical(GEN A, GEN B, long l, long la, long lb,
397 : void *E, const struct bb_field *ff)
398 : {
399 : long j;
400 85117 : GEN C = cgetg(lb, t_MAT);
401 523197 : for(j = 1; j < lb; j++)
402 438080 : gel(C, j) = gen_matcolmul_i(A, gel(B, j), la, l, E, ff);
403 85117 : return C;
404 : }
405 :
406 : /* Strassen-Winograd algorithm */
407 :
408 : /* Return A[ma+1..ma+da, na+1..na+ea] - B[mb+1..mb+db, nb+1..nb+eb]
409 : * as an (m x n)-matrix, padding the input with zeroes as necessary. */
410 : static GEN
411 0 : add_slices(long m, long n,
412 : GEN A, long ma, long da, long na, long ea,
413 : GEN B, long mb, long db, long nb, long eb,
414 : void *E, const struct bb_field *ff)
415 : {
416 0 : long min_d = minss(da, db), min_e = minss(ea, eb), i, j;
417 0 : GEN M = cgetg(n + 1, t_MAT), C;
418 :
419 0 : for (j = 1; j <= min_e; j++) {
420 0 : gel(M, j) = C = cgetg(m + 1, t_COL);
421 0 : for (i = 1; i <= min_d; i++)
422 0 : gel(C, i) = ff->add(E, gcoeff(A, ma + i, na + j),
423 0 : gcoeff(B, mb + i, nb + j));
424 0 : for (; i <= da; i++)
425 0 : gel(C, i) = gcoeff(A, ma + i, na + j);
426 0 : for (; i <= db; i++)
427 0 : gel(C, i) = gcoeff(B, mb + i, nb + j);
428 0 : for (; i <= m; i++)
429 0 : gel(C, i) = ff->s(E, 0);
430 : }
431 0 : for (; j <= ea; j++) {
432 0 : gel(M, j) = C = cgetg(m + 1, t_COL);
433 0 : for (i = 1; i <= da; i++)
434 0 : gel(C, i) = gcoeff(A, ma + i, na + j);
435 0 : for (; i <= m; i++)
436 0 : gel(C, i) = ff->s(E, 0);
437 : }
438 0 : for (; j <= eb; j++) {
439 0 : gel(M, j) = C = cgetg(m + 1, t_COL);
440 0 : for (i = 1; i <= db; i++)
441 0 : gel(C, i) = gcoeff(B, mb + i, nb + j);
442 0 : for (; i <= m; i++)
443 0 : gel(C, i) = ff->s(E, 0);
444 : }
445 0 : for (; j <= n; j++) {
446 0 : gel(M, j) = C = cgetg(m + 1, t_COL);
447 0 : for (i = 1; i <= m; i++)
448 0 : gel(C, i) = ff->s(E, 0);
449 : }
450 0 : return M;
451 : }
452 :
453 : /* Return A[ma+1..ma+da, na+1..na+ea] - B[mb+1..mb+db, nb+1..nb+eb]
454 : * as an (m x n)-matrix, padding the input with zeroes as necessary. */
455 : static GEN
456 0 : subtract_slices(long m, long n,
457 : GEN A, long ma, long da, long na, long ea,
458 : GEN B, long mb, long db, long nb, long eb,
459 : void *E, const struct bb_field *ff)
460 : {
461 0 : long min_d = minss(da, db), min_e = minss(ea, eb), i, j;
462 0 : GEN M = cgetg(n + 1, t_MAT), C;
463 :
464 0 : for (j = 1; j <= min_e; j++) {
465 0 : gel(M, j) = C = cgetg(m + 1, t_COL);
466 0 : for (i = 1; i <= min_d; i++)
467 0 : gel(C, i) = ff->add(E, gcoeff(A, ma + i, na + j),
468 0 : ff->neg(E, gcoeff(B, mb + i, nb + j)));
469 0 : for (; i <= da; i++)
470 0 : gel(C, i) = gcoeff(A, ma + i, na + j);
471 0 : for (; i <= db; i++)
472 0 : gel(C, i) = ff->neg(E, gcoeff(B, mb + i, nb + j));
473 0 : for (; i <= m; i++)
474 0 : gel(C, i) = ff->s(E, 0);
475 : }
476 0 : for (; j <= ea; j++) {
477 0 : gel(M, j) = C = cgetg(m + 1, t_COL);
478 0 : for (i = 1; i <= da; i++)
479 0 : gel(C, i) = gcoeff(A, ma + i, na + j);
480 0 : for (; i <= m; i++)
481 0 : gel(C, i) = ff->s(E, 0);
482 : }
483 0 : for (; j <= eb; j++) {
484 0 : gel(M, j) = C = cgetg(m + 1, t_COL);
485 0 : for (i = 1; i <= db; i++)
486 0 : gel(C, i) = ff->neg(E, gcoeff(B, mb + i, nb + j));
487 0 : for (; i <= m; i++)
488 0 : gel(C, i) = ff->s(E, 0);
489 : }
490 0 : for (; j <= n; j++) {
491 0 : gel(M, j) = C = cgetg(m + 1, t_COL);
492 0 : for (i = 1; i <= m; i++)
493 0 : gel(C, i) = ff->s(E, 0);
494 : }
495 0 : return M;
496 : }
497 :
498 : static GEN gen_matmul_i(GEN A, GEN B, long l, long la, long lb,
499 : void *E, const struct bb_field *ff);
500 :
501 : static GEN
502 0 : gen_matmul_sw(GEN A, GEN B, long m, long n, long p,
503 : void *E, const struct bb_field *ff)
504 : {
505 0 : pari_sp av = avma;
506 0 : long m1 = (m + 1)/2, m2 = m/2,
507 0 : n1 = (n + 1)/2, n2 = n/2,
508 0 : p1 = (p + 1)/2, p2 = p/2;
509 : GEN A11, A12, A22, B11, B21, B22,
510 : S1, S2, S3, S4, T1, T2, T3, T4,
511 : M1, M2, M3, M4, M5, M6, M7,
512 : V1, V2, V3, C11, C12, C21, C22, C;
513 :
514 0 : T2 = subtract_slices(n1, p2, B, 0, n1, p1, p2, B, n1, n2, p1, p2, E, ff);
515 0 : S1 = subtract_slices(m2, n1, A, m1, m2, 0, n1, A, 0, m2, 0, n1, E, ff);
516 0 : M2 = gen_matmul_i(S1, T2, m2 + 1, n1 + 1, p2 + 1, E, ff);
517 0 : if (gc_needed(av, 1))
518 0 : gerepileall(av, 2, &T2, &M2); /* destroy S1 */
519 0 : T3 = subtract_slices(n1, p1, T2, 0, n1, 0, p2, B, 0, n1, 0, p1, E, ff);
520 0 : if (gc_needed(av, 1))
521 0 : gerepileall(av, 2, &M2, &T3); /* destroy T2 */
522 0 : S2 = add_slices(m2, n1, A, m1, m2, 0, n1, A, m1, m2, n1, n2, E, ff);
523 0 : T1 = subtract_slices(n1, p1, B, 0, n1, p1, p2, B, 0, n1, 0, p2, E, ff);
524 0 : M3 = gen_matmul_i(S2, T1, m2 + 1, n1 + 1, p2 + 1, E, ff);
525 0 : if (gc_needed(av, 1))
526 0 : gerepileall(av, 4, &M2, &T3, &S2, &M3); /* destroy T1 */
527 0 : S3 = subtract_slices(m1, n1, S2, 0, m2, 0, n1, A, 0, m1, 0, n1, E, ff);
528 0 : if (gc_needed(av, 1))
529 0 : gerepileall(av, 4, &M2, &T3, &M3, &S3); /* destroy S2 */
530 0 : A11 = matslice(A, 1, m1, 1, n1);
531 0 : B11 = matslice(B, 1, n1, 1, p1);
532 0 : M1 = gen_matmul_i(A11, B11, m1 + 1, n1 + 1, p1 + 1, E, ff);
533 0 : if (gc_needed(av, 1))
534 0 : gerepileall(av, 5, &M2, &T3, &M3, &S3, &M1); /* destroy A11, B11 */
535 0 : A12 = matslice(A, 1, m1, n1 + 1, n);
536 0 : B21 = matslice(B, n1 + 1, n, 1, p1);
537 0 : M4 = gen_matmul_i(A12, B21, m1 + 1, n2 + 1, p1 + 1, E, ff);
538 0 : if (gc_needed(av, 1))
539 0 : gerepileall(av, 6, &M2, &T3, &M3, &S3, &M1, &M4); /* destroy A12, B21 */
540 0 : C11 = add_slices(m1, p1, M1, 0, m1, 0, p1, M4, 0, m1, 0, p1, E, ff);
541 0 : if (gc_needed(av, 1))
542 0 : gerepileall(av, 6, &M2, &T3, &M3, &S3, &M1, &C11); /* destroy M4 */
543 0 : M5 = gen_matmul_i(S3, T3, m1 + 1, n1 + 1, p1 + 1, E, ff);
544 0 : S4 = subtract_slices(m1, n2, A, 0, m1, n1, n2, S3, 0, m1, 0, n2, E, ff);
545 0 : if (gc_needed(av, 1))
546 0 : gerepileall(av, 7, &M2, &T3, &M3, &M1, &C11, &M5, &S4); /* destroy S3 */
547 0 : T4 = add_slices(n2, p1, B, n1, n2, 0, p1, T3, 0, n2, 0, p1, E, ff);
548 0 : if (gc_needed(av, 1))
549 0 : gerepileall(av, 7, &M2, &M3, &M1, &C11, &M5, &S4, &T4); /* destroy T3 */
550 0 : V1 = subtract_slices(m1, p1, M1, 0, m1, 0, p1, M5, 0, m1, 0, p1, E, ff);
551 0 : if (gc_needed(av, 1))
552 0 : gerepileall(av, 6, &M2, &M3, &S4, &T4, &C11, &V1); /* destroy M1, M5 */
553 0 : B22 = matslice(B, n1 + 1, n, p1 + 1, p);
554 0 : M6 = gen_matmul_i(S4, B22, m1 + 1, n2 + 1, p2 + 1, E, ff);
555 0 : if (gc_needed(av, 1))
556 0 : gerepileall(av, 6, &M2, &M3, &T4, &C11, &V1, &M6); /* destroy S4, B22 */
557 0 : A22 = matslice(A, m1 + 1, m, n1 + 1, n);
558 0 : M7 = gen_matmul_i(A22, T4, m2 + 1, n2 + 1, p1 + 1, E, ff);
559 0 : if (gc_needed(av, 1))
560 0 : gerepileall(av, 6, &M2, &M3, &C11, &V1, &M6, &M7); /* destroy A22, T4 */
561 0 : V3 = add_slices(m1, p2, V1, 0, m1, 0, p2, M3, 0, m2, 0, p2, E, ff);
562 0 : C12 = add_slices(m1, p2, V3, 0, m1, 0, p2, M6, 0, m1, 0, p2, E, ff);
563 0 : if (gc_needed(av, 1))
564 0 : gerepileall(av, 6, &M2, &M3, &C11, &V1, &M7, &C12); /* destroy V3, M6 */
565 0 : V2 = add_slices(m2, p1, V1, 0, m2, 0, p1, M2, 0, m2, 0, p2, E, ff);
566 0 : if (gc_needed(av, 1))
567 0 : gerepileall(av, 5, &M3, &C11, &M7, &C12, &V2); /* destroy V1, M2 */
568 0 : C21 = add_slices(m2, p1, V2, 0, m2, 0, p1, M7, 0, m2, 0, p1, E, ff);
569 0 : if (gc_needed(av, 1))
570 0 : gerepileall(av, 5, &M3, &C11, &C12, &V2, &C21); /* destroy M7 */
571 0 : C22 = add_slices(m2, p2, V2, 0, m2, 0, p2, M3, 0, m2, 0, p2, E, ff);
572 0 : if (gc_needed(av, 1))
573 0 : gerepileall(av, 4, &C11, &C12, &C21, &C22); /* destroy V2, M3 */
574 0 : C = mkmat2(mkcol2(C11, C21), mkcol2(C12, C22));
575 0 : return gerepileupto(av, matconcat(C));
576 : }
577 :
578 : /* Strassen-Winograd used for dim >= gen_matmul_sw_bound */
579 : static const long gen_matmul_sw_bound = 24;
580 :
581 : static GEN
582 85117 : gen_matmul_i(GEN A, GEN B, long l, long la, long lb,
583 : void *E, const struct bb_field *ff)
584 : {
585 85117 : if (l <= gen_matmul_sw_bound
586 7 : || la <= gen_matmul_sw_bound
587 0 : || lb <= gen_matmul_sw_bound)
588 85117 : return gen_matmul_classical(A, B, l, la, lb, E, ff);
589 : else
590 0 : return gen_matmul_sw(A, B, l - 1, la - 1, lb - 1, E, ff);
591 : }
592 :
593 : GEN
594 85117 : gen_matmul(GEN A, GEN B, void *E, const struct bb_field *ff)
595 : {
596 85117 : ulong lgA, lgB = lg(B);
597 85117 : if (lgB == 1)
598 0 : return cgetg(1, t_MAT);
599 85117 : lgA = lg(A);
600 85117 : if (lgA != (ulong)lgcols(B))
601 0 : pari_err_OP("operation 'gen_matmul'", A, B);
602 85117 : if (lgA == 1)
603 0 : return zeromat(0, lgB - 1);
604 85117 : return gen_matmul_i(A, B, lgcols(A), lgA, lgB, E, ff);
605 : }
606 :
607 : static GEN
608 19326 : gen_colneg(GEN A, void *E, const struct bb_field *ff)
609 : {
610 : long i, l;
611 19326 : GEN B = cgetg_copy(A, &l);
612 74127 : for (i = 1; i < l; i++)
613 54801 : gel(B, i) = ff->neg(E, gel(A, i));
614 19326 : return B;
615 : }
616 :
617 : static GEN
618 4015 : gen_matneg(GEN A, void *E, const struct bb_field *ff)
619 : {
620 : long i, l;
621 4015 : GEN B = cgetg_copy(A, &l);
622 23271 : for (i = 1; i < l; i++)
623 19256 : gel(B, i) = gen_colneg(gel(A, i), E, ff);
624 4015 : return B;
625 : }
626 :
627 : static GEN
628 354675 : gen_colscalmul(GEN A, GEN b, void *E, const struct bb_field *ff)
629 : {
630 : long i, l;
631 354675 : GEN B = cgetg_copy(A, &l);
632 826358 : for (i = 1; i < l; i++)
633 471683 : gel(B, i) = ff->red(E, ff->mul(E, gel(A, i), b));
634 354675 : return B;
635 : }
636 :
637 : static GEN
638 54434 : gen_matscalmul(GEN A, GEN b, void *E, const struct bb_field *ff)
639 : {
640 : long i, l;
641 54434 : GEN B = cgetg_copy(A, &l);
642 409109 : for (i = 1; i < l; i++)
643 354675 : gel(B, i) = gen_colscalmul(gel(A, i), b, E, ff);
644 54434 : return B;
645 : }
646 :
647 : static GEN
648 681846 : gen_colsub(GEN A, GEN C, void *E, const struct bb_field *ff)
649 : {
650 : long i, l;
651 681846 : GEN B = cgetg_copy(A, &l);
652 2432956 : for (i = 1; i < l; i++)
653 1751110 : gel(B, i) = ff->add(E, gel(A, i), ff->neg(E, gel(C, i)));
654 681846 : return B;
655 : }
656 :
657 : static GEN
658 78576 : gen_matsub(GEN A, GEN C, void *E, const struct bb_field *ff)
659 : {
660 : long i, l;
661 78576 : GEN B = cgetg_copy(A, &l);
662 760422 : for (i = 1; i < l; i++)
663 681846 : gel(B, i) = gen_colsub(gel(A, i), gel(C, i), E, ff);
664 78576 : return B;
665 : }
666 :
667 : static GEN
668 46734 : gen_zerocol(long n, void* data, const struct bb_field *R)
669 : {
670 46734 : GEN C = cgetg(n+1,t_COL), zero = R->s(data, 0);
671 : long i;
672 282161 : for (i=1; i<=n; i++) gel(C,i) = zero;
673 46734 : return C;
674 : }
675 :
676 : static GEN
677 14885 : gen_zeromat(long m, long n, void* data, const struct bb_field *R)
678 : {
679 14885 : GEN M = cgetg(n+1,t_MAT);
680 : long i;
681 61619 : for (i=1; i<=n; i++) gel(M,i) = gen_zerocol(m, data, R);
682 14885 : return M;
683 : }
684 :
685 : static GEN
686 154 : gen_colei(long n, long i, void *E, const struct bb_field *S)
687 : {
688 154 : GEN y = cgetg(n+1,t_COL), _0, _1;
689 : long j;
690 154 : if (n < 0) pari_err_DOMAIN("gen_colei", "dimension","<",gen_0,stoi(n));
691 154 : _0 = S->s(E,0);
692 154 : _1 = S->s(E,1);
693 2422 : for (j=1; j<=n; j++)
694 2268 : gel(y, j) = i==j ? _1: _0;
695 154 : return y;
696 : }
697 :
698 : /* assume dim A >= 1, A invertible + upper triangular */
699 : static GEN
700 77 : gen_matinv_upper_ind(GEN A, long index, void *E, const struct bb_field *ff)
701 : {
702 77 : long n = lg(A) - 1, i, j;
703 77 : GEN u = cgetg(n + 1, t_COL);
704 147 : for (i = n; i > index; i--)
705 70 : gel(u, i) = ff->s(E, 0);
706 77 : gel(u, i) = ff->inv(E, gcoeff(A, i, i));
707 147 : for (i--; i > 0; i--) {
708 70 : pari_sp av = avma;
709 70 : GEN m = ff->neg(E, ff->mul(E, gcoeff(A, i, i + 1), gel(u, i + 1)));
710 112 : for (j = i + 2; j <= n; j++)
711 42 : m = ff->add(E, m, ff->neg(E, ff->mul(E, gcoeff(A, i, j), gel(u, j))));
712 70 : gel(u, i) = gerepileupto(av, ff->red(E, ff->mul(E, m, ff->inv(E, gcoeff(A, i, i)))));
713 : }
714 77 : return u;
715 : }
716 :
717 : static GEN
718 28 : gen_matinv_upper(GEN A, void *E, const struct bb_field *ff)
719 : {
720 : long i, l;
721 28 : GEN B = cgetg_copy(A, &l);
722 105 : for (i = 1; i < l; i++)
723 77 : gel(B,i) = gen_matinv_upper_ind(A, i, E, ff);
724 28 : return B;
725 : }
726 :
727 : /* find z such that A z = y. Return NULL if no solution */
728 : GEN
729 0 : gen_matcolinvimage(GEN A, GEN y, void *E, const struct bb_field *ff)
730 : {
731 0 : pari_sp av = avma;
732 0 : long i, l = lg(A);
733 : GEN M, x, t;
734 :
735 0 : M = gen_ker(shallowconcat(A, y), 0, E, ff);
736 0 : i = lg(M) - 1;
737 0 : if (!i) return gc_NULL(av);
738 :
739 0 : x = gel(M, i);
740 0 : t = gel(x, l);
741 0 : if (ff->equal0(t)) return gc_NULL(av);
742 :
743 0 : t = ff->neg(E, ff->inv(E, t));
744 0 : setlg(x, l);
745 0 : for (i = 1; i < l; i++)
746 0 : gel(x, i) = ff->red(E, ff->mul(E, t, gel(x, i)));
747 0 : return gerepilecopy(av, x);
748 : }
749 :
750 : /* find Z such that A Z = B. Return NULL if no solution */
751 : GEN
752 77 : gen_matinvimage(GEN A, GEN B, void *E, const struct bb_field *ff)
753 : {
754 77 : pari_sp av = avma;
755 : GEN d, x, X, Y;
756 : long i, j, nY, nA, nB;
757 77 : x = gen_ker(shallowconcat(gen_matneg(A, E, ff), B), 0, E, ff);
758 : /* AX = BY, Y in strict upper echelon form with pivots = 1.
759 : * We must find T such that Y T = Id_nB then X T = Z. This exists
760 : * iff Y has at least nB columns and full rank. */
761 77 : nY = lg(x) - 1;
762 77 : nB = lg(B) - 1;
763 77 : if (nY < nB) return gc_NULL(av);
764 77 : nA = lg(A) - 1;
765 77 : Y = rowslice(x, nA + 1, nA + nB); /* nB rows */
766 77 : d = cgetg(nB + 1, t_VECSMALL);
767 182 : for (i = nB, j = nY; i >= 1; i--, j--) {
768 224 : for (; j >= 1; j--)
769 175 : if (!ff->equal0(gcoeff(Y, i, j))) { d[i] = j; break; }
770 154 : if (!j) return gc_NULL(av);
771 : }
772 : /* reduce to the case Y square, upper triangular with 1s on diagonal */
773 28 : Y = vecpermute(Y, d);
774 28 : x = vecpermute(x, d);
775 28 : X = rowslice(x, 1, nA);
776 28 : return gerepileupto(av, gen_matmul(X, gen_matinv_upper(Y, E, ff), E, ff));
777 : }
778 :
779 : static GEN
780 364891 : image_from_pivot(GEN x, GEN d, long r)
781 : {
782 : GEN y;
783 : long j, k;
784 :
785 364891 : if (!d) return gcopy(x);
786 : /* d left on stack for efficiency */
787 360169 : r = lg(x)-1 - r; /* = dim Im(x) */
788 360169 : y = cgetg(r+1,t_MAT);
789 2070166 : for (j=k=1; j<=r; k++)
790 1709995 : if (d[k]) gel(y,j++) = gcopy(gel(x,k));
791 360171 : return y;
792 : }
793 :
794 : /* r = dim Ker x, n = nbrows(x) */
795 : static GEN
796 269589 : get_suppl(GEN x, GEN d, long n, long r, GEN(*ei)(long,long))
797 : {
798 : pari_sp av;
799 : GEN y, c;
800 269589 : long j, k, rx = lg(x)-1; /* != 0 due to init_suppl() */
801 :
802 269589 : if (rx == n && r == 0) return gcopy(x);
803 199237 : y = cgetg(n+1, t_MAT);
804 199238 : av = avma; c = zero_zv(n);
805 : /* c = lines containing pivots (could get it from gauss_pivot, but cheap)
806 : * In theory r = 0 and d[j] > 0 for all j, but why take chances? */
807 840743 : for (k = j = 1; j<=rx; j++)
808 641505 : if (d[j]) { c[ d[j] ] = 1; gel(y,k++) = gel(x,j); }
809 1202668 : for (j=1; j<=n; j++)
810 1003430 : if (!c[j]) gel(y,k++) = (GEN)j; /* HACK */
811 199238 : set_avma(av);
812 :
813 199238 : rx -= r;
814 840674 : for (j=1; j<=rx; j++) gel(y,j) = gcopy(gel(y,j));
815 561234 : for ( ; j<=n; j++) gel(y,j) = ei(n, y[j]);
816 199238 : return y;
817 : }
818 :
819 : /* n = dim x, r = dim Ker(x), d from gauss_pivot */
820 : static GEN
821 1966603 : indexrank0(long n, long r, GEN d)
822 : {
823 1966603 : GEN p1, p2, res = cgetg(3,t_VEC);
824 : long i, j;
825 :
826 1966602 : r = n - r; /* now r = dim Im(x) */
827 1966602 : p1 = cgetg(r+1,t_VECSMALL); gel(res,1) = p1;
828 1966602 : p2 = cgetg(r+1,t_VECSMALL); gel(res,2) = p2;
829 1966603 : if (d)
830 : {
831 7895332 : for (i=0,j=1; j<=n; j++)
832 5932236 : if (d[j]) { i++; p1[i] = d[j]; p2[i] = j; }
833 1963096 : vecsmall_sort(p1);
834 : }
835 1966610 : return res;
836 : }
837 :
838 : /*******************************************************************/
839 : /* */
840 : /* Echelon form and CUP decomposition */
841 : /* */
842 : /*******************************************************************/
843 :
844 : /* By Peter Bruin, based on
845 : C.-P. Jeannerod, C. Pernet and A. Storjohann, Rank-profile revealing
846 : Gaussian elimination and the CUP matrix decomposition. J. Symbolic
847 : Comput. 56 (2013), 46-68.
848 :
849 : Decompose an m x n-matrix A of rank r as C*U*P, with
850 : - C: m x r-matrix in column echelon form (not necessarily reduced)
851 : with all pivots equal to 1
852 : - U: upper-triangular r x n-matrix
853 : - P: permutation matrix
854 : The pivots of C and the known zeroes in C and U are not necessarily
855 : filled in; instead, we also return the vector R of pivot rows.
856 : Instead of the matrix P, we return the permutation p of [1..n]
857 : (t_VECSMALL) such that P[i,j] = 1 if and only if j = p[i].
858 : */
859 :
860 : /* complement of a strictly increasing subsequence of (1, 2, ..., n) */
861 : static GEN
862 17592 : indexcompl(GEN v, long n)
863 : {
864 17592 : long i, j, k, m = lg(v) - 1;
865 17592 : GEN w = cgetg(n - m + 1, t_VECSMALL);
866 165740 : for (i = j = k = 1; i <= n; i++)
867 148148 : if (j <= m && v[j] == i) j++; else w[k++] = i;
868 17592 : return w;
869 : }
870 :
871 : static GEN
872 4085 : gen_solve_upper_1(GEN U, GEN B, void *E, const struct bb_field *ff)
873 4085 : { return gen_matscalmul(B, ff->inv(E, gcoeff(U, 1, 1)), E, ff); }
874 :
875 : static GEN
876 2256 : gen_rsolve_upper_2(GEN U, GEN B, void *E, const struct bb_field *ff)
877 : {
878 2256 : GEN a = gcoeff(U, 1, 1), b = gcoeff(U, 1, 2), d = gcoeff(U, 2, 2);
879 2256 : GEN D = ff->red(E, ff->mul(E, a, d)), Dinv = ff->inv(E, D);
880 2256 : GEN ainv = ff->red(E, ff->mul(E, d, Dinv));
881 2256 : GEN dinv = ff->red(E, ff->mul(E, a, Dinv));
882 2256 : GEN B1 = rowslice(B, 1, 1);
883 2256 : GEN B2 = rowslice(B, 2, 2);
884 2256 : GEN X2 = gen_matscalmul(B2, dinv, E, ff);
885 2256 : GEN X1 = gen_matscalmul(gen_matsub(B1, gen_matscalmul(X2, b, E, ff), E, ff),
886 : ainv, E, ff);
887 2256 : return vconcat(X1, X2);
888 : }
889 :
890 : /* solve U*X = B, U upper triangular and invertible */
891 : static GEN
892 5840 : gen_rsolve_upper(GEN U, GEN B, void *E, const struct bb_field *ff,
893 : GEN (*mul)(void *E, GEN a, GEN))
894 : {
895 5840 : long n = lg(U) - 1, n1;
896 : GEN U2, U11, U12, U22, B1, B2, X1, X2, X;
897 5840 : pari_sp av = avma;
898 :
899 5840 : if (n == 0) return B;
900 5840 : if (n == 1) return gen_solve_upper_1(U, B, E, ff);
901 4914 : if (n == 2) return gen_rsolve_upper_2(U, B, E, ff);
902 2658 : n1 = (n + 1)/2;
903 2658 : U2 = vecslice(U, n1 + 1, n);
904 2658 : U11 = matslice(U, 1,n1, 1,n1);
905 2658 : U12 = rowslice(U2, 1, n1);
906 2658 : U22 = rowslice(U2, n1 + 1, n);
907 2658 : B1 = rowslice(B, 1, n1);
908 2658 : B2 = rowslice(B, n1 + 1, n);
909 2658 : X2 = gen_rsolve_upper(U22, B2, E, ff, mul);
910 2658 : B1 = gen_matsub(B1, mul(E, U12, X2), E, ff);
911 2658 : if (gc_needed(av, 1)) gerepileall(av, 3, &B1, &U11, &X2);
912 2658 : X1 = gen_rsolve_upper(U11, B1, E, ff, mul);
913 2658 : X = vconcat(X1, X2);
914 2658 : if (gc_needed(av, 1)) X = gerepilecopy(av, X);
915 2658 : return X;
916 : }
917 :
918 : static GEN
919 6180 : gen_lsolve_upper_2(GEN U, GEN B, void *E, const struct bb_field *ff)
920 : {
921 6180 : GEN a = gcoeff(U, 1, 1), b = gcoeff(U, 1, 2), d = gcoeff(U, 2, 2);
922 6180 : GEN D = ff->red(E, ff->mul(E, a, d)), Dinv = ff->inv(E, D);
923 6180 : GEN ainv = ff->red(E, ff->mul(E, d, Dinv)), dinv = ff->red(E, ff->mul(E, a, Dinv));
924 6180 : GEN B1 = vecslice(B, 1, 1);
925 6180 : GEN B2 = vecslice(B, 2, 2);
926 6180 : GEN X1 = gen_matscalmul(B1, ainv, E, ff);
927 6180 : GEN X2 = gen_matscalmul(gen_matsub(B2, gen_matscalmul(X1, b, E, ff), E, ff), dinv, E, ff);
928 6180 : return shallowconcat(X1, X2);
929 : }
930 :
931 : /* solve X*U = B, U upper triangular and invertible */
932 : static GEN
933 14256 : gen_lsolve_upper(GEN U, GEN B, void *E, const struct bb_field *ff,
934 : GEN (*mul)(void *E, GEN a, GEN))
935 : {
936 14256 : long n = lg(U) - 1, n1;
937 : GEN U2, U11, U12, U22, B1, B2, X1, X2, X;
938 14256 : pari_sp av = avma;
939 :
940 14256 : if (n == 0) return B;
941 14256 : if (n == 1) return gen_solve_upper_1(U, B, E, ff);
942 11097 : if (n == 2) return gen_lsolve_upper_2(U, B, E, ff);
943 4917 : n1 = (n + 1)/2;
944 4917 : U2 = vecslice(U, n1 + 1, n);
945 4917 : U11 = matslice(U, 1,n1, 1,n1);
946 4917 : U12 = rowslice(U2, 1, n1);
947 4917 : U22 = rowslice(U2, n1 + 1, n);
948 4917 : B1 = vecslice(B, 1, n1);
949 4917 : B2 = vecslice(B, n1 + 1, n);
950 4917 : X1 = gen_lsolve_upper(U11, B1, E, ff, mul);
951 4917 : B2 = gen_matsub(B2, mul(E, X1, U12), E, ff);
952 4917 : if (gc_needed(av, 1)) gerepileall(av, 3, &B2, &U22, &X1);
953 4917 : X2 = gen_lsolve_upper(U22, B2, E, ff, mul);
954 4917 : X = shallowconcat(X1, X2);
955 4917 : if (gc_needed(av, 1)) X = gerepilecopy(av, X);
956 4917 : return X;
957 : }
958 :
959 : static GEN
960 17183 : gen_rsolve_lower_unit_2(GEN L, GEN A, void *E, const struct bb_field *ff)
961 : {
962 17183 : GEN X1 = rowslice(A, 1, 1);
963 17183 : GEN X2 = gen_matsub(rowslice(A, 2, 2), gen_matscalmul(X1, gcoeff(L, 2, 1), E, ff), E, ff);
964 17183 : return vconcat(X1, X2);
965 : }
966 :
967 : /* solve L*X = A, L lower triangular with ones on the diagonal
968 : * (at least as many rows as columns) */
969 : static GEN
970 40198 : gen_rsolve_lower_unit(GEN L, GEN A, void *E, const struct bb_field *ff,
971 : GEN (*mul)(void *E, GEN a, GEN))
972 : {
973 40198 : long m = lg(L) - 1, m1, n;
974 : GEN L1, L11, L21, L22, A1, A2, X1, X2, X;
975 40198 : pari_sp av = avma;
976 :
977 40198 : if (m == 0) return zeromat(0, lg(A) - 1);
978 40198 : if (m == 1) return rowslice(A, 1, 1);
979 31768 : if (m == 2) return gen_rsolve_lower_unit_2(L, A, E, ff);
980 14585 : m1 = (m + 1)/2;
981 14585 : n = nbrows(L);
982 14585 : L1 = vecslice(L, 1, m1);
983 14585 : L11 = rowslice(L1, 1, m1);
984 14585 : L21 = rowslice(L1, m1 + 1, n);
985 14585 : A1 = rowslice(A, 1, m1);
986 14585 : X1 = gen_rsolve_lower_unit(L11, A1, E, ff, mul);
987 14585 : A2 = rowslice(A, m1 + 1, n);
988 14585 : A2 = gen_matsub(A2, mul(E, L21, X1), E, ff);
989 14585 : if (gc_needed(av, 1)) gerepileall(av, 2, &A2, &X1);
990 14585 : L22 = matslice(L, m1+1,n, m1+1,m);
991 14585 : X2 = gen_rsolve_lower_unit(L22, A2, E, ff, mul);
992 14585 : X = vconcat(X1, X2);
993 14585 : if (gc_needed(av, 1)) X = gerepilecopy(av, X);
994 14585 : return X;
995 : }
996 :
997 : static GEN
998 7858 : gen_lsolve_lower_unit_2(GEN L, GEN A, void *E, const struct bb_field *ff)
999 : {
1000 7858 : GEN X2 = vecslice(A, 2, 2);
1001 7858 : GEN X1 = gen_matsub(vecslice(A, 1, 1),
1002 7858 : gen_matscalmul(X2, gcoeff(L, 2, 1), E, ff), E, ff);
1003 7858 : return shallowconcat(X1, X2);
1004 : }
1005 :
1006 : /* solve L*X = A, L lower triangular with ones on the diagonal
1007 : * (at least as many rows as columns) */
1008 : static GEN
1009 20118 : gen_lsolve_lower_unit(GEN L, GEN A, void *E, const struct bb_field *ff,
1010 : GEN (*mul)(void *E, GEN a, GEN))
1011 : {
1012 20118 : long m = lg(L) - 1, m1;
1013 : GEN L1, L2, L11, L21, L22, A1, A2, X1, X2, X;
1014 20118 : pari_sp av = avma;
1015 :
1016 20118 : if (m <= 1) return A;
1017 15913 : if (m == 2) return gen_lsolve_lower_unit_2(L, A, E, ff);
1018 8055 : m1 = (m + 1)/2;
1019 8055 : L2 = vecslice(L, m1 + 1, m);
1020 8055 : L22 = rowslice(L2, m1 + 1, m);
1021 8055 : A2 = vecslice(A, m1 + 1, m);
1022 8055 : X2 = gen_lsolve_lower_unit(L22, A2, E, ff, mul);
1023 8055 : if (gc_needed(av, 1)) X2 = gerepilecopy(av, X2);
1024 8055 : L1 = vecslice(L, 1, m1);
1025 8055 : L21 = rowslice(L1, m1 + 1, m);
1026 8055 : A1 = vecslice(A, 1, m1);
1027 8055 : A1 = gen_matsub(A1, mul(E, X2, L21), E, ff);
1028 8055 : L11 = rowslice(L1, 1, m1);
1029 8055 : if (gc_needed(av, 1)) gerepileall(av, 3, &A1, &L11, &X2);
1030 8055 : X1 = gen_lsolve_lower_unit(L11, A1, E, ff, mul);
1031 8055 : X = shallowconcat(X1, X2);
1032 8055 : if (gc_needed(av, 1)) X = gerepilecopy(av, X);
1033 8055 : return X;
1034 : }
1035 :
1036 : /* destroy A */
1037 : static long
1038 22429 : gen_CUP_basecase(GEN A, GEN *R, GEN *C, GEN *U, GEN *P, void *E, const struct bb_field *ff)
1039 : {
1040 22429 : long i, j, k, m = nbrows(A), n = lg(A) - 1, pr, pc;
1041 : pari_sp av;
1042 : GEN u, v;
1043 :
1044 22429 : if (P) *P = identity_perm(n);
1045 22429 : *R = cgetg(m + 1, t_VECSMALL);
1046 22429 : av = avma;
1047 58432 : for (j = 1, pr = 0; j <= n; j++)
1048 : {
1049 134204 : for (pr++, pc = 0; pr <= m; pr++)
1050 : {
1051 657259 : for (k = j; k <= n; k++)
1052 : {
1053 540534 : v = ff->red(E, gcoeff(A, pr, k));
1054 540534 : gcoeff(A, pr, k) = v;
1055 540534 : if (!pc && !ff->equal0(v)) pc = k;
1056 : }
1057 116725 : if (pc) break;
1058 : }
1059 53482 : if (!pc) break;
1060 36003 : (*R)[j] = pr;
1061 36003 : if (pc != j)
1062 : {
1063 5073 : swap(gel(A, j), gel(A, pc));
1064 5073 : if (P) lswap((*P)[j], (*P)[pc]);
1065 : }
1066 36003 : u = ff->inv(E, gcoeff(A, pr, j));
1067 179286 : for (i = pr + 1; i <= m; i++)
1068 : {
1069 143283 : v = ff->red(E, ff->mul(E, gcoeff(A, i, j), u));
1070 143283 : gcoeff(A, i, j) = v;
1071 143283 : v = ff->neg(E, v);
1072 462790 : for (k = j + 1; k <= n; k++)
1073 319507 : gcoeff(A, i, k) = ff->add(E, gcoeff(A, i, k),
1074 319507 : ff->red(E, ff->mul(E, gcoeff(A, pr, k), v)));
1075 : }
1076 36003 : if (gc_needed(av, 2)) A = gerepilecopy(av, A);
1077 : }
1078 22429 : setlg(*R, j);
1079 22429 : *C = vecslice(A, 1, j - 1);
1080 22429 : if (U) *U = rowpermute(A, *R);
1081 22429 : return j - 1;
1082 : }
1083 :
1084 : static const long gen_CUP_LIMIT = 5;
1085 :
1086 : static long
1087 11480 : gen_CUP(GEN A, GEN *R, GEN *C, GEN *U, GEN *P, void *E, const struct bb_field *ff,
1088 : GEN (*mul)(void *E, GEN a, GEN))
1089 : {
1090 11480 : long m = nbrows(A), m1, n = lg(A) - 1, i, r1, r2, r;
1091 : GEN R1, C1, U1, P1, R2, C2, U2, P2;
1092 : GEN A1, A2, B2, C21, U11, U12, T21, T22;
1093 11480 : pari_sp av = avma;
1094 :
1095 11480 : if (m < gen_CUP_LIMIT || n < gen_CUP_LIMIT)
1096 : /* destroy A; not called at the outermost recursion level */
1097 6573 : return gen_CUP_basecase(A, R, C, U, P, E, ff);
1098 4907 : m1 = (minss(m, n) + 1)/2;
1099 4907 : A1 = rowslice(A, 1, m1);
1100 4907 : A2 = rowslice(A, m1 + 1, m);
1101 4907 : r1 = gen_CUP(A1, &R1, &C1, &U1, &P1, E, ff, mul);
1102 4907 : if (r1 == 0)
1103 : {
1104 485 : r2 = gen_CUP(A2, &R2, &C2, &U2, &P2, E, ff, mul);
1105 485 : *R = cgetg(r2 + 1, t_VECSMALL);
1106 790 : for (i = 1; i <= r2; i++) (*R)[i] = R2[i] + m1;
1107 485 : *C = vconcat(gen_zeromat(m1, r2, E, ff), C2);
1108 485 : *U = U2;
1109 485 : *P = P2;
1110 485 : r = r2;
1111 : }
1112 : else
1113 : {
1114 4422 : U11 = vecslice(U1, 1, r1);
1115 4422 : U12 = vecslice(U1, r1 + 1, n);
1116 4422 : T21 = vecslicepermute(A2, P1, 1, r1);
1117 4422 : T22 = vecslicepermute(A2, P1, r1 + 1, n);
1118 4422 : C21 = gen_lsolve_upper(U11, T21, E, ff, mul);
1119 4422 : if (gc_needed(av, 1))
1120 0 : gerepileall(av, 7, &R1, &C1, &P1, &U11, &U12, &T22, &C21);
1121 4422 : B2 = gen_matsub(T22, mul(E, C21, U12), E, ff);
1122 4422 : r2 = gen_CUP(B2, &R2, &C2, &U2, &P2, E, ff, mul);
1123 4422 : r = r1 + r2;
1124 4422 : *R = cgetg(r + 1, t_VECSMALL);
1125 19941 : for (i = 1; i <= r1; i++) (*R)[i] = R1[i];
1126 21029 : for ( ; i <= r; i++) (*R)[i] = R2[i - r1] + m1;
1127 4422 : *C = shallowconcat(vconcat(C1, C21),
1128 : vconcat(gen_zeromat(m1, r2, E, ff), C2));
1129 4422 : *U = shallowconcat(vconcat(U11, gen_zeromat(r2, r1, E, ff)),
1130 : vconcat(vecpermute(U12, P2), U2));
1131 :
1132 4422 : *P = cgetg(n + 1, t_VECSMALL);
1133 19941 : for (i = 1; i <= r1; i++) (*P)[i] = P1[i];
1134 50825 : for ( ; i <= n; i++) (*P)[i] = P1[P2[i - r1] + r1];
1135 : }
1136 4907 : if (gc_needed(av, 1)) gerepileall(av, 4, R, C, U, P);
1137 4907 : return r;
1138 : }
1139 :
1140 : /* column echelon form */
1141 : static long
1142 27879 : gen_echelon(GEN A, GEN *R, GEN *C, void *E, const struct bb_field *ff,
1143 : GEN (*mul)(void*, GEN, GEN))
1144 : {
1145 27879 : long j, j1, j2, m = nbrows(A), n = lg(A) - 1, n1, r, r1, r2;
1146 : GEN A1, A2, R1, R1c, C1, R2, C2;
1147 : GEN A12, A22, B2, C11, C21, M12;
1148 27879 : pari_sp av = avma;
1149 :
1150 27879 : if (m < gen_CUP_LIMIT || n < gen_CUP_LIMIT)
1151 15856 : return gen_CUP_basecase(shallowcopy(A), R, C, NULL, NULL, E, ff);
1152 :
1153 12023 : n1 = (n + 1)/2;
1154 12023 : A1 = vecslice(A, 1, n1);
1155 12023 : A2 = vecslice(A, n1 + 1, n);
1156 12023 : r1 = gen_echelon(A1, &R1, &C1, E, ff, mul);
1157 12023 : if (!r1) return gen_echelon(A2, R, C, E, ff, mul);
1158 10700 : if (r1 == m) { *R = R1; *C = C1; return r1; }
1159 10462 : R1c = indexcompl(R1, m);
1160 10462 : C11 = rowpermute(C1, R1);
1161 10462 : C21 = rowpermute(C1, R1c);
1162 10462 : A12 = rowpermute(A2, R1);
1163 10462 : A22 = rowpermute(A2, R1c);
1164 10462 : M12 = gen_rsolve_lower_unit(C11, A12, E, ff, mul);
1165 10462 : B2 = gen_matsub(A22, mul(E, C21, M12), E, ff);
1166 10462 : r2 = gen_echelon(B2, &R2, &C2, E, ff, mul);
1167 10462 : if (!r2) { *R = R1; *C = C1; r = r1; }
1168 : else
1169 : {
1170 5535 : R2 = perm_mul(R1c, R2);
1171 5535 : C2 = rowpermute(vconcat(gen_zeromat(r1, r2, E, ff), C2),
1172 : perm_inv(vecsmall_concat(R1, R1c)));
1173 5535 : r = r1 + r2;
1174 5535 : *R = cgetg(r + 1, t_VECSMALL);
1175 5535 : *C = cgetg(r + 1, t_MAT);
1176 39631 : for (j = j1 = j2 = 1; j <= r; j++)
1177 34096 : if (j2 > r2 || (j1 <= r1 && R1[j1] < R2[j2]))
1178 : {
1179 20045 : gel(*C, j) = gel(C1, j1);
1180 20045 : (*R)[j] = R1[j1++];
1181 : }
1182 : else
1183 : {
1184 14051 : gel(*C, j) = gel(C2, j2);
1185 14051 : (*R)[j] = R2[j2++];
1186 : }
1187 : }
1188 10462 : if (gc_needed(av, 1)) gerepileall(av, 2, R, C);
1189 10462 : return r;
1190 : }
1191 :
1192 : static GEN
1193 904 : gen_pivots_CUP(GEN x, long *rr, void *E, const struct bb_field *ff,
1194 : GEN (*mul)(void*, GEN, GEN))
1195 : {
1196 : pari_sp av;
1197 904 : long i, n = lg(x) - 1, r;
1198 904 : GEN R, C, U, P, d = zero_zv(n);
1199 904 : av = avma;
1200 904 : r = gen_CUP(x, &R, &C, &U, &P, E, ff, mul);
1201 6921 : for(i = 1; i <= r; i++)
1202 6017 : d[P[i]] = R[i];
1203 904 : set_avma(av);
1204 904 : *rr = n - r;
1205 904 : return d;
1206 : }
1207 :
1208 : static GEN
1209 140 : gen_det_CUP(GEN a, void *E, const struct bb_field *ff,
1210 : GEN (*mul)(void*, GEN, GEN))
1211 : {
1212 140 : pari_sp av = avma;
1213 : GEN R, C, U, P, d;
1214 140 : long i, n = lg(a) - 1, r;
1215 140 : r = gen_CUP(a, &R, &C, &U, &P, E, ff, mul);
1216 140 : if (r < n)
1217 0 : d = ff->s(E, 0);
1218 : else {
1219 140 : d = ff->s(E, perm_sign(P) == 1 ? 1: - 1);
1220 2730 : for (i = 1; i <= n; i++)
1221 2590 : d = ff->red(E, ff->mul(E, d, gcoeff(U, i, i)));
1222 : }
1223 140 : return gerepileupto(av, d);
1224 : }
1225 :
1226 : static long
1227 35 : gen_matrank(GEN x, void *E, const struct bb_field *ff,
1228 : GEN (*mul)(void*, GEN, GEN))
1229 : {
1230 35 : pari_sp av = avma;
1231 : long r;
1232 35 : if (lg(x) - 1 >= gen_CUP_LIMIT && nbrows(x) >= gen_CUP_LIMIT)
1233 : {
1234 : GEN R, C;
1235 28 : return gc_long(av, gen_echelon(x, &R, &C, E, ff, mul));
1236 : }
1237 7 : (void) gen_Gauss_pivot(x, &r, E, ff);
1238 7 : return gc_long(av, lg(x)-1 - r);
1239 : }
1240 :
1241 : static GEN
1242 63 : gen_invimage_CUP(GEN A, GEN B, void *E, const struct bb_field *ff,
1243 : GEN (*mul)(void*, GEN, GEN))
1244 : {
1245 63 : pari_sp av = avma;
1246 : GEN R, Rc, C, U, P, B1, B2, C1, C2, X, Y, Z;
1247 63 : long r = gen_CUP(A, &R, &C, &U, &P, E, ff, mul);
1248 63 : Rc = indexcompl(R, nbrows(B));
1249 63 : C1 = rowpermute(C, R);
1250 63 : C2 = rowpermute(C, Rc);
1251 63 : B1 = rowpermute(B, R);
1252 63 : B2 = rowpermute(B, Rc);
1253 63 : Z = gen_rsolve_lower_unit(C1, B1, E, ff, mul);
1254 63 : if (!gequal(mul(E, C2, Z), B2))
1255 42 : return NULL;
1256 21 : Y = vconcat(gen_rsolve_upper(vecslice(U, 1, r), Z, E, ff, mul),
1257 21 : gen_zeromat(lg(A) - 1 - r, lg(B) - 1, E, ff));
1258 21 : X = rowpermute(Y, perm_inv(P));
1259 21 : return gerepilecopy(av, X);
1260 : }
1261 :
1262 : static GEN
1263 3938 : gen_ker_echelon(GEN x, void *E, const struct bb_field *ff,
1264 : GEN (*mul)(void*, GEN, GEN))
1265 : {
1266 3938 : pari_sp av = avma;
1267 : GEN R, Rc, C, C1, C2, S, K;
1268 3938 : long n = lg(x) - 1, r;
1269 3938 : r = gen_echelon(shallowtrans(x), &R, &C, E, ff, mul);
1270 3938 : Rc = indexcompl(R, n);
1271 3938 : C1 = rowpermute(C, R);
1272 3938 : C2 = rowpermute(C, Rc);
1273 3938 : S = gen_lsolve_lower_unit(C1, C2, E, ff, mul);
1274 3938 : K = vecpermute(shallowconcat(gen_matneg(S, E, ff), gen_matid(n - r, E, ff)),
1275 : perm_inv(vecsmall_concat(R, Rc)));
1276 3938 : K = shallowtrans(K);
1277 3938 : return gerepilecopy(av, K);
1278 : }
1279 :
1280 : static GEN
1281 105 : gen_deplin_echelon(GEN x, void *E, const struct bb_field *ff,
1282 : GEN (*mul)(void*, GEN, GEN))
1283 : {
1284 105 : pari_sp av = avma;
1285 : GEN R, Rc, C, C1, C2, s, v;
1286 105 : long i, n = lg(x) - 1, r;
1287 105 : r = gen_echelon(shallowtrans(x), &R, &C, E, ff, mul);
1288 105 : if (r == n) return gc_NULL(av);
1289 70 : Rc = indexcompl(R, n);
1290 70 : i = Rc[1];
1291 70 : C1 = rowpermute(C, R);
1292 70 : C2 = rowslice(C, i, i);
1293 70 : s = row(gen_lsolve_lower_unit(C1, C2, E, ff, mul), 1);
1294 70 : settyp(s, t_COL);
1295 70 : v = vecpermute(shallowconcat(gen_colneg(s, E, ff), gen_colei(n - r, 1, E, ff)),
1296 : perm_inv(vecsmall_concat(R, Rc)));
1297 70 : return gerepilecopy(av, v);
1298 : }
1299 :
1300 : static GEN
1301 559 : gen_gauss_CUP(GEN a, GEN b, void *E, const struct bb_field *ff,
1302 : GEN (*mul)(void*, GEN, GEN))
1303 : {
1304 : GEN R, C, U, P, Y;
1305 559 : long n = lg(a) - 1, r;
1306 559 : if (nbrows(a) < n || (r = gen_CUP(a, &R, &C, &U, &P, E, ff, mul)) < n)
1307 56 : return NULL;
1308 503 : Y = gen_rsolve_lower_unit(rowpermute(C, R), rowpermute(b, R), E, ff, mul);
1309 503 : return rowpermute(gen_rsolve_upper(U, Y, E, ff, mul), perm_inv(P));
1310 : }
1311 :
1312 : static GEN
1313 3057 : gen_gauss(GEN a, GEN b, void *E, const struct bb_field *ff,
1314 : GEN (*mul)(void*, GEN, GEN))
1315 : {
1316 3057 : if (lg(a) - 1 >= gen_CUP_LIMIT)
1317 559 : return gen_gauss_CUP(a, b, E, ff, mul);
1318 2498 : return gen_Gauss(a, b, E, ff);
1319 : }
1320 :
1321 : static GEN
1322 5872 : gen_ker_i(GEN x, long deplin, void *E, const struct bb_field *ff,
1323 : GEN (*mul)(void*, GEN, GEN)) {
1324 5872 : if (lg(x) - 1 >= gen_CUP_LIMIT && nbrows(x) >= gen_CUP_LIMIT)
1325 4043 : return deplin? gen_deplin_echelon(x, E, ff, mul): gen_ker_echelon(x, E, ff, mul);
1326 1829 : return gen_ker(x, deplin, E, ff);
1327 : }
1328 :
1329 : static GEN
1330 140 : gen_invimage(GEN A, GEN B, void *E, const struct bb_field *ff,
1331 : GEN (*mul)(void*, GEN, GEN))
1332 : {
1333 140 : long nA = lg(A)-1, nB = lg(B)-1;
1334 :
1335 140 : if (!nB) return cgetg(1, t_MAT);
1336 140 : if (nA + nB >= gen_CUP_LIMIT && nbrows(B) >= gen_CUP_LIMIT)
1337 63 : return gen_invimage_CUP(A, B, E, ff, mul);
1338 77 : return gen_matinvimage(A, B, E, ff);
1339 : }
1340 :
1341 : /* find z such that A z = y. Return NULL if no solution */
1342 : static GEN
1343 71 : gen_matcolinvimage_i(GEN A, GEN y, void *E, const struct bb_field *ff,
1344 : GEN (*mul)(void*, GEN, GEN))
1345 : {
1346 71 : pari_sp av = avma;
1347 71 : long i, l = lg(A);
1348 : GEN M, x, t;
1349 :
1350 71 : M = gen_ker_i(shallowconcat(A, y), 0, E, ff, mul);
1351 71 : i = lg(M) - 1;
1352 71 : if (!i) return gc_NULL(av);
1353 :
1354 71 : x = gel(M, i);
1355 71 : t = gel(x, l);
1356 71 : if (ff->equal0(t)) return gc_NULL(av);
1357 :
1358 50 : t = ff->neg(E, ff->inv(E, t));
1359 50 : setlg(x, l);
1360 178 : for (i = 1; i < l; i++)
1361 128 : gel(x, i) = ff->red(E, ff->mul(E, t, gel(x, i)));
1362 50 : return gerepilecopy(av, x);
1363 : }
1364 :
1365 : static GEN
1366 420 : gen_det_i(GEN a, void *E, const struct bb_field *ff,
1367 : GEN (*mul)(void*, GEN, GEN))
1368 : {
1369 420 : if (lg(a) - 1 >= gen_CUP_LIMIT)
1370 140 : return gen_det_CUP(a, E, ff, mul);
1371 : else
1372 280 : return gen_det(a, E, ff);
1373 : }
1374 :
1375 : static GEN
1376 2788 : gen_pivots(GEN x, long *rr, void *E, const struct bb_field *ff,
1377 : GEN (*mul)(void*, GEN, GEN))
1378 : {
1379 2788 : if (lg(x) - 1 >= gen_CUP_LIMIT && nbrows(x) >= gen_CUP_LIMIT)
1380 904 : return gen_pivots_CUP(x, rr, E, ff, mul);
1381 1884 : return gen_Gauss_pivot(x, rr, E, ff);
1382 : }
1383 :
1384 : /* r = dim Ker x, n = nbrows(x) */
1385 : static GEN
1386 21 : gen_get_suppl(GEN x, GEN d, long n, long r, void *E, const struct bb_field *ff)
1387 : {
1388 : GEN y, c;
1389 21 : long j, k, rx = lg(x)-1; /* != 0 due to init_suppl() */
1390 :
1391 21 : if (rx == n && r == 0) return gcopy(x);
1392 21 : c = zero_zv(n);
1393 21 : y = cgetg(n+1, t_MAT);
1394 : /* c = lines containing pivots (could get it from gauss_pivot, but cheap)
1395 : * In theory r = 0 and d[j] > 0 for all j, but why take chances? */
1396 119 : for (k = j = 1; j<=rx; j++)
1397 98 : if (d[j]) { c[ d[j] ] = 1; gel(y,k++) = gcopy(gel(x,j)); }
1398 203 : for (j=1; j<=n; j++)
1399 182 : if (!c[j]) gel(y,k++) = gen_colei(n, j, E, ff);
1400 21 : return y;
1401 : }
1402 :
1403 : static GEN
1404 21 : gen_suppl(GEN x, void *E, const struct bb_field *ff,
1405 : GEN (*mul)(void*, GEN, GEN))
1406 : {
1407 : GEN d;
1408 21 : long n = nbrows(x), r;
1409 :
1410 21 : if (lg(x) == 1) pari_err_IMPL("suppl [empty matrix]");
1411 21 : d = gen_pivots(x, &r, E, ff, mul);
1412 21 : return gen_get_suppl(x, d, n, r, E, ff);
1413 : }
1414 :
1415 : /*******************************************************************/
1416 : /* */
1417 : /* MATRIX MULTIPLICATION MODULO P */
1418 : /* */
1419 : /*******************************************************************/
1420 :
1421 : GEN
1422 21 : F2xqM_F2xqC_mul(GEN A, GEN B, GEN T) {
1423 : void *E;
1424 21 : const struct bb_field *ff = get_F2xq_field(&E, T);
1425 21 : return gen_matcolmul(A, B, E, ff);
1426 : }
1427 :
1428 : GEN
1429 35 : FlxqM_FlxqC_mul(GEN A, GEN B, GEN T, ulong p) {
1430 : void *E;
1431 35 : const struct bb_field *ff = get_Flxq_field(&E, T, p);
1432 35 : return gen_matcolmul(A, B, E, ff);
1433 : }
1434 :
1435 : GEN
1436 63 : FqM_FqC_mul(GEN A, GEN B, GEN T, GEN p) {
1437 : void *E;
1438 63 : const struct bb_field *ff = get_Fq_field(&E, T, p);
1439 63 : return gen_matcolmul(A, B, E, ff);
1440 : }
1441 :
1442 : GEN
1443 1449 : F2xqM_mul(GEN A, GEN B, GEN T) {
1444 : void *E;
1445 1449 : const struct bb_field *ff = get_F2xq_field(&E, T);
1446 1449 : return gen_matmul(A, B, E, ff);
1447 : }
1448 :
1449 : GEN
1450 158058 : FlxqM_mul(GEN A, GEN B, GEN T, ulong p) {
1451 : void *E;
1452 : const struct bb_field *ff;
1453 158058 : long n = lg(A) - 1;
1454 :
1455 158058 : if (n == 0)
1456 0 : return cgetg(1, t_MAT);
1457 158058 : if (n > 1)
1458 89193 : return FlxqM_mul_Kronecker(A, B, T, p);
1459 68865 : ff = get_Flxq_field(&E, T, p);
1460 68865 : return gen_matmul(A, B, E, ff);
1461 : }
1462 :
1463 : GEN
1464 86037 : FqM_mul(GEN A, GEN B, GEN T, GEN p) {
1465 : void *E;
1466 86037 : long n = lg(A) - 1;
1467 : const struct bb_field *ff;
1468 86037 : if (n == 0)
1469 0 : return cgetg(1, t_MAT);
1470 86037 : if (n > 1)
1471 81872 : return FqM_mul_Kronecker(A, B, T, p);
1472 4165 : ff = get_Fq_field(&E, T, p);
1473 4165 : return gen_matmul(A, B, E, ff);
1474 : }
1475 :
1476 : /*******************************************************************/
1477 : /* */
1478 : /* LINEAR ALGEBRA MODULO P */
1479 : /* */
1480 : /*******************************************************************/
1481 :
1482 : static GEN
1483 0 : _F2xqM_mul(void *E, GEN A, GEN B)
1484 0 : { return F2xqM_mul(A, B, (GEN) E); }
1485 :
1486 : struct _Flxq {
1487 : GEN aut;
1488 : GEN T;
1489 : ulong p;
1490 : };
1491 :
1492 : static GEN
1493 16072 : _FlxqM_mul(void *E, GEN A, GEN B)
1494 : {
1495 16072 : struct _Flxq *D = (struct _Flxq*)E;
1496 16072 : return FlxqM_mul(A, B, D->T, D->p);
1497 : }
1498 :
1499 : static GEN
1500 22741 : _FpM_mul(void *E, GEN A, GEN B)
1501 22741 : { return FpM_mul(A, B, (GEN) E); }
1502 :
1503 : struct _Fq_field
1504 : {
1505 : GEN T, p;
1506 : };
1507 :
1508 : static GEN
1509 6349 : _FqM_mul(void *E, GEN A, GEN B)
1510 : {
1511 6349 : struct _Fq_field *D = (struct _Fq_field*) E;
1512 6349 : return FqM_mul(A, B, D->T, D->p);
1513 : }
1514 :
1515 : static GEN
1516 1276339 : FpM_init(GEN a, GEN p, ulong *pp)
1517 : {
1518 1276339 : if (lgefint(p) == 3)
1519 : {
1520 1272053 : *pp = uel(p,2);
1521 1272053 : return (*pp==2)? ZM_to_F2m(a): ZM_to_Flm(a, *pp);
1522 : }
1523 4286 : *pp = 0; return a;
1524 : }
1525 : static GEN
1526 1304793 : FpM_init3(GEN a, GEN p, ulong *pp)
1527 : {
1528 1304793 : if (lgefint(p) == 3)
1529 : {
1530 1302218 : *pp = uel(p,2);
1531 1302218 : switch(*pp)
1532 : {
1533 705801 : case 2: return ZM_to_F2m(a);
1534 156274 : case 3: return ZM_to_F3m(a);
1535 440143 : default:return ZM_to_Flm(a, *pp);
1536 : }
1537 : }
1538 2575 : *pp = 0; return a;
1539 : }
1540 : GEN
1541 4578 : RgM_Fp_init(GEN a, GEN p, ulong *pp)
1542 : {
1543 4578 : if (lgefint(p) == 3)
1544 : {
1545 4298 : *pp = uel(p,2);
1546 4298 : return (*pp==2)? RgM_to_F2m(a): RgM_to_Flm(a, *pp);
1547 : }
1548 280 : *pp = 0; return RgM_to_FpM(a,p);
1549 : }
1550 : static GEN
1551 644 : RgM_Fp_init3(GEN a, GEN p, ulong *pp)
1552 : {
1553 644 : if (lgefint(p) == 3)
1554 : {
1555 574 : *pp = uel(p,2);
1556 574 : switch(*pp)
1557 : {
1558 21 : case 2: return RgM_to_F2m(a);
1559 77 : case 3: return RgM_to_F3m(a);
1560 476 : default:return RgM_to_Flm(a, *pp);
1561 : }
1562 : }
1563 70 : *pp = 0; return RgM_to_FpM(a,p);
1564 : }
1565 :
1566 : static GEN
1567 315 : FpM_det_gen(GEN a, GEN p)
1568 : {
1569 : void *E;
1570 315 : const struct bb_field *S = get_Fp_field(&E,p);
1571 315 : return gen_det_i(a, E, S, _FpM_mul);
1572 : }
1573 : GEN
1574 4676 : FpM_det(GEN a, GEN p)
1575 : {
1576 4676 : pari_sp av = avma;
1577 : ulong pp, d;
1578 4676 : a = FpM_init(a, p, &pp);
1579 4676 : switch(pp)
1580 : {
1581 315 : case 0: return FpM_det_gen(a, p);
1582 1750 : case 2: d = F2m_det_sp(a); break;
1583 2611 : default:d = Flm_det_sp(a,pp); break;
1584 : }
1585 4361 : return gc_utoi(av, d);
1586 : }
1587 :
1588 : GEN
1589 7 : F2xqM_det(GEN a, GEN T)
1590 : {
1591 : void *E;
1592 7 : const struct bb_field *S = get_F2xq_field(&E, T);
1593 7 : return gen_det_i(a, E, S, _F2xqM_mul);
1594 : }
1595 :
1596 : GEN
1597 28 : FlxqM_det(GEN a, GEN T, ulong p) {
1598 : void *E;
1599 28 : const struct bb_field *S = get_Flxq_field(&E, T, p);
1600 28 : return gen_det_i(a, E, S, _FlxqM_mul);
1601 : }
1602 :
1603 : GEN
1604 70 : FqM_det(GEN x, GEN T, GEN p)
1605 : {
1606 : void *E;
1607 70 : const struct bb_field *S = get_Fq_field(&E,T,p);
1608 70 : return gen_det_i(x, E, S, _FqM_mul);
1609 : }
1610 :
1611 : static GEN
1612 1214 : FpM_gauss_pivot_gen(GEN x, GEN p, long *rr)
1613 : {
1614 : void *E;
1615 1214 : const struct bb_field *S = get_Fp_field(&E,p);
1616 1214 : return gen_pivots(x, rr, E, S, _FpM_mul);
1617 : }
1618 :
1619 : static GEN
1620 631282 : FpM_gauss_pivot(GEN x, GEN p, long *rr)
1621 : {
1622 : ulong pp;
1623 631282 : if (lg(x)==1) { *rr = 0; return NULL; }
1624 627211 : x = FpM_init(x, p, &pp);
1625 627212 : switch(pp)
1626 : {
1627 1214 : case 0: return FpM_gauss_pivot_gen(x, p, rr);
1628 350031 : case 2: return F2m_gauss_pivot(x, rr);
1629 275967 : default:return Flm_pivots(x, pp, rr, 1);
1630 : }
1631 : }
1632 :
1633 : static GEN
1634 21 : F2xqM_gauss_pivot(GEN x, GEN T, long *rr)
1635 : {
1636 : void *E;
1637 21 : const struct bb_field *S = get_F2xq_field(&E,T);
1638 21 : return gen_pivots(x, rr, E, S, _F2xqM_mul);
1639 : }
1640 :
1641 : static GEN
1642 1427 : FlxqM_gauss_pivot(GEN x, GEN T, ulong p, long *rr) {
1643 : void *E;
1644 1427 : const struct bb_field *S = get_Flxq_field(&E, T, p);
1645 1427 : return gen_pivots(x, rr, E, S, _FlxqM_mul);
1646 : }
1647 :
1648 : static GEN
1649 105 : FqM_gauss_pivot_gen(GEN x, GEN T, GEN p, long *rr)
1650 : {
1651 : void *E;
1652 105 : const struct bb_field *S = get_Fq_field(&E,T,p);
1653 105 : return gen_pivots(x, rr, E, S, _FqM_mul);
1654 : }
1655 : static GEN
1656 1504 : FqM_gauss_pivot(GEN x, GEN T, GEN p, long *rr)
1657 : {
1658 1504 : if (lg(x)==1) { *rr = 0; return NULL; }
1659 1504 : if (!T) return FpM_gauss_pivot(x, p, rr);
1660 1504 : if (lgefint(p) == 3)
1661 : {
1662 1399 : pari_sp av = avma;
1663 1399 : ulong pp = uel(p,2);
1664 1399 : GEN Tp = ZXT_to_FlxT(T, pp);
1665 1399 : GEN d = FlxqM_gauss_pivot(ZXM_to_FlxM(x, pp, get_Flx_var(Tp)), Tp, pp, rr);
1666 1399 : return d ? gerepileuptoleaf(av, d): d;
1667 : }
1668 105 : return FqM_gauss_pivot_gen(x, T, p, rr);
1669 : }
1670 :
1671 : GEN
1672 323935 : FpM_image(GEN x, GEN p)
1673 : {
1674 : long r;
1675 323935 : GEN d = FpM_gauss_pivot(x,p,&r); /* d left on stack for efficiency */
1676 323934 : return image_from_pivot(x,d,r);
1677 : }
1678 :
1679 : GEN
1680 40859 : Flm_image(GEN x, ulong p)
1681 : {
1682 : long r;
1683 40859 : GEN d = Flm_pivots(x, p, &r, 0); /* d left on stack for efficiency */
1684 40859 : return image_from_pivot(x,d,r);
1685 : }
1686 :
1687 : GEN
1688 7 : F2m_image(GEN x)
1689 : {
1690 : long r;
1691 7 : GEN d = F2m_gauss_pivot(F2m_copy(x),&r); /* d left on stack for efficiency */
1692 7 : return image_from_pivot(x,d,r);
1693 : }
1694 :
1695 : GEN
1696 7 : F2xqM_image(GEN x, GEN T)
1697 : {
1698 : long r;
1699 7 : GEN d = F2xqM_gauss_pivot(x,T,&r); /* d left on stack for efficiency */
1700 7 : return image_from_pivot(x,d,r);
1701 : }
1702 :
1703 : GEN
1704 21 : FlxqM_image(GEN x, GEN T, ulong p)
1705 : {
1706 : long r;
1707 21 : GEN d = FlxqM_gauss_pivot(x, T, p, &r); /* d left on stack for efficiency */
1708 21 : return image_from_pivot(x,d,r);
1709 : }
1710 :
1711 : GEN
1712 49 : FqM_image(GEN x, GEN T, GEN p)
1713 : {
1714 : long r;
1715 49 : GEN d = FqM_gauss_pivot(x,T,p,&r); /* d left on stack for efficiency */
1716 49 : return image_from_pivot(x,d,r);
1717 : }
1718 :
1719 : long
1720 56 : FpM_rank(GEN x, GEN p)
1721 : {
1722 56 : pari_sp av = avma;
1723 : long r;
1724 56 : (void)FpM_gauss_pivot(x,p,&r);
1725 56 : return gc_long(av, lg(x)-1 - r);
1726 : }
1727 :
1728 : long
1729 7 : F2xqM_rank(GEN x, GEN T)
1730 : {
1731 7 : pari_sp av = avma;
1732 : long r;
1733 7 : (void)F2xqM_gauss_pivot(x,T,&r);
1734 7 : return gc_long(av, lg(x)-1 - r);
1735 : }
1736 :
1737 : long
1738 35 : FlxqM_rank(GEN x, GEN T, ulong p)
1739 : {
1740 : void *E;
1741 35 : const struct bb_field *S = get_Flxq_field(&E, T, p);
1742 35 : return gen_matrank(x, E, S, _FlxqM_mul);
1743 : }
1744 :
1745 : long
1746 70 : FqM_rank(GEN x, GEN T, GEN p)
1747 : {
1748 70 : pari_sp av = avma;
1749 : long r;
1750 70 : (void)FqM_gauss_pivot(x,T,p,&r);
1751 70 : return gc_long(av, lg(x)-1 - r);
1752 : }
1753 :
1754 : static GEN
1755 35 : FpM_invimage_gen(GEN A, GEN B, GEN p)
1756 : {
1757 : void *E;
1758 35 : const struct bb_field *ff = get_Fp_field(&E, p);
1759 35 : return gen_invimage(A, B, E, ff, _FpM_mul);
1760 : }
1761 :
1762 : GEN
1763 0 : FpM_invimage(GEN A, GEN B, GEN p)
1764 : {
1765 0 : pari_sp av = avma;
1766 : ulong pp;
1767 : GEN y;
1768 :
1769 0 : A = FpM_init(A, p, &pp);
1770 0 : switch(pp)
1771 : {
1772 0 : case 0: return FpM_invimage_gen(A, B, p);
1773 0 : case 2:
1774 0 : y = F2m_invimage(A, ZM_to_F2m(B));
1775 0 : if (!y) return gc_NULL(av);
1776 0 : y = F2m_to_ZM(y);
1777 0 : return gerepileupto(av, y);
1778 0 : default:
1779 0 : y = Flm_invimage_i(A, ZM_to_Flm(B, pp), pp);
1780 0 : if (!y) return gc_NULL(av);
1781 0 : y = Flm_to_ZM(y);
1782 0 : return gerepileupto(av, y);
1783 : }
1784 : }
1785 :
1786 : GEN
1787 21 : F2xqM_invimage(GEN A, GEN B, GEN T) {
1788 : void *E;
1789 21 : const struct bb_field *ff = get_F2xq_field(&E, T);
1790 21 : return gen_invimage(A, B, E, ff, _F2xqM_mul);
1791 : }
1792 :
1793 : GEN
1794 42 : FlxqM_invimage(GEN A, GEN B, GEN T, ulong p) {
1795 : void *E;
1796 42 : const struct bb_field *ff = get_Flxq_field(&E, T, p);
1797 42 : return gen_invimage(A, B, E, ff, _FlxqM_mul);
1798 : }
1799 :
1800 : GEN
1801 42 : FqM_invimage(GEN A, GEN B, GEN T, GEN p) {
1802 : void *E;
1803 42 : const struct bb_field *ff = get_Fq_field(&E, T, p);
1804 42 : return gen_invimage(A, B, E, ff, _FqM_mul);
1805 : }
1806 :
1807 : static GEN
1808 8 : FpM_FpC_invimage_gen(GEN A, GEN y, GEN p)
1809 : {
1810 : void *E;
1811 8 : const struct bb_field *ff = get_Fp_field(&E, p);
1812 8 : return gen_matcolinvimage_i(A, y, E, ff, _FpM_mul);
1813 : }
1814 :
1815 : GEN
1816 296901 : FpM_FpC_invimage(GEN A, GEN x, GEN p)
1817 : {
1818 296901 : pari_sp av = avma;
1819 : ulong pp;
1820 : GEN y;
1821 :
1822 296901 : A = FpM_init(A, p, &pp);
1823 296910 : switch(pp)
1824 : {
1825 8 : case 0: return FpM_FpC_invimage_gen(A, x, p);
1826 192971 : case 2:
1827 192971 : y = F2m_F2c_invimage(A, ZV_to_F2v(x));
1828 192976 : if (!y) return y;
1829 192976 : y = F2c_to_ZC(y);
1830 192975 : return gerepileupto(av, y);
1831 103931 : default:
1832 103931 : y = Flm_Flc_invimage(A, ZV_to_Flv(x, pp), pp);
1833 103930 : if (!y) return y;
1834 103930 : y = Flc_to_ZC(y);
1835 103930 : return gerepileupto(av, y);
1836 : }
1837 : }
1838 :
1839 : GEN
1840 21 : F2xqM_F2xqC_invimage(GEN A, GEN B, GEN T) {
1841 : void *E;
1842 21 : const struct bb_field *ff = get_F2xq_field(&E, T);
1843 21 : return gen_matcolinvimage_i(A, B, E, ff, _F2xqM_mul);
1844 : }
1845 :
1846 : GEN
1847 21 : FlxqM_FlxqC_invimage(GEN A, GEN B, GEN T, ulong p) {
1848 : void *E;
1849 21 : const struct bb_field *ff = get_Flxq_field(&E, T, p);
1850 21 : return gen_matcolinvimage_i(A, B, E, ff, _FlxqM_mul);
1851 : }
1852 :
1853 : GEN
1854 21 : FqM_FqC_invimage(GEN A, GEN B, GEN T, GEN p) {
1855 : void *E;
1856 21 : const struct bb_field *ff = get_Fq_field(&E, T, p);
1857 21 : return gen_matcolinvimage_i(A, B, E, ff, _FqM_mul);
1858 : }
1859 :
1860 : static GEN
1861 2646 : FpM_ker_gen(GEN x, GEN p, long deplin)
1862 : {
1863 : void *E;
1864 2646 : const struct bb_field *S = get_Fp_field(&E,p);
1865 2646 : return gen_ker_i(x, deplin, E, S, _FpM_mul);
1866 : }
1867 : static GEN
1868 1304792 : FpM_ker_i(GEN x, GEN p, long deplin)
1869 : {
1870 1304792 : pari_sp av = avma;
1871 : ulong pp;
1872 : GEN y;
1873 :
1874 1304792 : if (lg(x)==1) return cgetg(1,t_MAT);
1875 1304792 : x = FpM_init3(x, p, &pp);
1876 1304824 : switch(pp)
1877 : {
1878 2576 : case 0: return FpM_ker_gen(x,p,deplin);
1879 705822 : case 2:
1880 705822 : y = F2m_ker_sp(x, deplin);
1881 705829 : if (!y) return gc_NULL(av);
1882 705839 : y = deplin? F2c_to_ZC(y): F2m_to_ZM(y);
1883 705833 : return gerepileupto(av, y);
1884 156277 : case 3:
1885 156277 : y = F3m_ker_sp(x, deplin);
1886 156277 : if (!y) return gc_NULL(av);
1887 156277 : y = deplin? F3c_to_ZC(y): F3m_to_ZM(y);
1888 156277 : return gerepileupto(av, y);
1889 440149 : default:
1890 440149 : y = Flm_ker_sp(x, pp, deplin);
1891 440150 : if (!y) return gc_NULL(av);
1892 440150 : y = deplin? Flc_to_ZC(y): Flm_to_ZM(y);
1893 440150 : return gerepileupto(av, y);
1894 : }
1895 : }
1896 :
1897 : GEN
1898 841724 : FpM_ker(GEN x, GEN p) { return FpM_ker_i(x,p,0); }
1899 :
1900 : static GEN
1901 35 : F2xqM_ker_i(GEN x, GEN T, long deplin)
1902 : {
1903 : const struct bb_field *ff;
1904 : void *E;
1905 :
1906 35 : if (lg(x)==1) return cgetg(1,t_MAT);
1907 35 : ff = get_F2xq_field(&E,T);
1908 35 : return gen_ker_i(x,deplin, E, ff, _F2xqM_mul);
1909 : }
1910 :
1911 : GEN
1912 21 : F2xqM_ker(GEN x, GEN T)
1913 : {
1914 21 : return F2xqM_ker_i(x, T, 0);
1915 : }
1916 :
1917 : static GEN
1918 2994 : FlxqM_ker_i(GEN x, GEN T, ulong p, long deplin) {
1919 : void *E;
1920 2994 : const struct bb_field *S = get_Flxq_field(&E, T, p);
1921 2994 : return gen_ker_i(x, deplin, E, S, _FlxqM_mul);
1922 : }
1923 :
1924 : GEN
1925 28 : FlxqM_ker(GEN x, GEN T, ulong p)
1926 : {
1927 28 : return FlxqM_ker_i(x, T, p, 0);
1928 : }
1929 :
1930 : static GEN
1931 126 : FqM_ker_gen(GEN x, GEN T, GEN p, long deplin)
1932 : {
1933 : void *E;
1934 126 : const struct bb_field *S = get_Fq_field(&E,T,p);
1935 126 : return gen_ker_i(x,deplin,E,S,_FqM_mul);
1936 : }
1937 : static GEN
1938 11310 : FqM_ker_i(GEN x, GEN T, GEN p, long deplin)
1939 : {
1940 11310 : if (!T) return FpM_ker_i(x,p,deplin);
1941 3057 : if (lg(x)==1) return cgetg(1,t_MAT);
1942 :
1943 3057 : if (lgefint(p)==3)
1944 : {
1945 2931 : pari_sp av = avma;
1946 2931 : ulong l = p[2];
1947 2931 : GEN Tl = ZXT_to_FlxT(T,l);
1948 2931 : GEN Ml = ZXM_to_FlxM(x, l, get_Flx_var(Tl));
1949 2931 : GEN K = FlxqM_ker_i(Ml, Tl, l, deplin);
1950 2931 : if (!deplin) K = FlxM_to_ZXM(K);
1951 28 : else if (!K) return gc_NULL(av);
1952 21 : else K = FlxC_to_ZXC(K);
1953 2924 : return gerepileupto(av, K);
1954 : }
1955 126 : return FqM_ker_gen(x, T, p, deplin);
1956 : }
1957 :
1958 : GEN
1959 11226 : FqM_ker(GEN x, GEN T, GEN p) { return FqM_ker_i(x,T,p,0); }
1960 :
1961 : GEN
1962 454837 : FpM_deplin(GEN x, GEN p) { return FpM_ker_i(x,p,1); }
1963 :
1964 : GEN
1965 14 : F2xqM_deplin(GEN x, GEN T)
1966 : {
1967 14 : return F2xqM_ker_i(x, T, 1);
1968 : }
1969 :
1970 : GEN
1971 35 : FlxqM_deplin(GEN x, GEN T, ulong p)
1972 : {
1973 35 : return FlxqM_ker_i(x, T, p, 1);
1974 : }
1975 :
1976 : GEN
1977 84 : FqM_deplin(GEN x, GEN T, GEN p) { return FqM_ker_i(x,T,p,1); }
1978 :
1979 : static GEN
1980 2749 : FpM_gauss_gen(GEN a, GEN b, GEN p)
1981 : {
1982 : void *E;
1983 2749 : const struct bb_field *S = get_Fp_field(&E,p);
1984 2749 : return gen_gauss(a,b, E, S, _FpM_mul);
1985 : }
1986 : /* a an FpM, lg(a)>1; b an FpM or NULL (replace by identity) */
1987 : static GEN
1988 347584 : FpM_gauss_i(GEN a, GEN b, GEN p, ulong *pp)
1989 : {
1990 347584 : long n = nbrows(a);
1991 347583 : a = FpM_init(a,p,pp);
1992 347580 : switch(*pp)
1993 : {
1994 2749 : case 0:
1995 2749 : if (!b) b = matid(n);
1996 2749 : return FpM_gauss_gen(a,b,p);
1997 226948 : case 2:
1998 226948 : if (b) b = ZM_to_F2m(b); else b = matid_F2m(n);
1999 226953 : return F2m_gauss_sp(a,b);
2000 117883 : default:
2001 117883 : if (b) b = ZM_to_Flm(b, *pp); else b = matid_Flm(n);
2002 117883 : return Flm_gauss_sp(a,b, NULL, *pp);
2003 : }
2004 : }
2005 : GEN
2006 35 : FpM_gauss(GEN a, GEN b, GEN p)
2007 : {
2008 35 : pari_sp av = avma;
2009 : ulong pp;
2010 : GEN u;
2011 35 : if (lg(a) == 1 || lg(b)==1) return cgetg(1, t_MAT);
2012 35 : u = FpM_gauss_i(a, b, p, &pp);
2013 35 : if (!u) return gc_NULL(av);
2014 28 : switch(pp)
2015 : {
2016 28 : case 0: return gerepilecopy(av, u);
2017 0 : case 2: u = F2m_to_ZM(u); break;
2018 0 : default: u = Flm_to_ZM(u); break;
2019 : }
2020 0 : return gerepileupto(av, u);
2021 : }
2022 :
2023 : static GEN
2024 84 : F2xqM_gauss_gen(GEN a, GEN b, GEN T)
2025 : {
2026 : void *E;
2027 84 : const struct bb_field *S = get_F2xq_field(&E, T);
2028 84 : return gen_gauss(a, b, E, S, _F2xqM_mul);
2029 : }
2030 :
2031 : GEN
2032 21 : F2xqM_gauss(GEN a, GEN b, GEN T)
2033 : {
2034 21 : pari_sp av = avma;
2035 21 : long n = lg(a)-1;
2036 : GEN u;
2037 21 : if (!n || lg(b)==1) { set_avma(av); return cgetg(1, t_MAT); }
2038 21 : u = F2xqM_gauss_gen(a, b, T);
2039 21 : if (!u) return gc_NULL(av);
2040 14 : return gerepilecopy(av, u);
2041 : }
2042 :
2043 : static GEN
2044 91 : FlxqM_gauss_i(GEN a, GEN b, GEN T, ulong p) {
2045 : void *E;
2046 91 : const struct bb_field *S = get_Flxq_field(&E, T, p);
2047 91 : return gen_gauss(a, b, E, S, _FlxqM_mul);
2048 : }
2049 :
2050 : GEN
2051 21 : FlxqM_gauss(GEN a, GEN b, GEN T, ulong p)
2052 : {
2053 21 : pari_sp av = avma;
2054 21 : long n = lg(a)-1;
2055 : GEN u;
2056 21 : if (!n || lg(b)==1) { set_avma(av); return cgetg(1, t_MAT); }
2057 21 : u = FlxqM_gauss_i(a, b, T, p);
2058 21 : if (!u) return gc_NULL(av);
2059 14 : return gerepilecopy(av, u);
2060 : }
2061 :
2062 : static GEN
2063 133 : FqM_gauss_gen(GEN a, GEN b, GEN T, GEN p)
2064 : {
2065 : void *E;
2066 133 : const struct bb_field *S = get_Fq_field(&E,T,p);
2067 133 : return gen_gauss(a,b,E,S,_FqM_mul);
2068 : }
2069 : GEN
2070 21 : FqM_gauss(GEN a, GEN b, GEN T, GEN p)
2071 : {
2072 21 : pari_sp av = avma;
2073 : GEN u;
2074 : long n;
2075 21 : if (!T) return FpM_gauss(a,b,p);
2076 21 : n = lg(a)-1; if (!n || lg(b)==1) return cgetg(1, t_MAT);
2077 21 : u = FqM_gauss_gen(a,b,T,p);
2078 21 : if (!u) return gc_NULL(av);
2079 14 : return gerepilecopy(av, u);
2080 : }
2081 :
2082 : GEN
2083 14 : FpM_FpC_gauss(GEN a, GEN b, GEN p)
2084 : {
2085 14 : pari_sp av = avma;
2086 : ulong pp;
2087 : GEN u;
2088 14 : if (lg(a) == 1) return cgetg(1, t_COL);
2089 14 : u = FpM_gauss_i(a, mkmat(b), p, &pp);
2090 14 : if (!u) return gc_NULL(av);
2091 14 : switch(pp)
2092 : {
2093 14 : case 0: return gerepilecopy(av, gel(u,1));
2094 0 : case 2: u = F2c_to_ZC(gel(u,1)); break;
2095 0 : default: u = Flc_to_ZC(gel(u,1)); break;
2096 : }
2097 0 : return gerepileupto(av, u);
2098 : }
2099 :
2100 : GEN
2101 28 : F2xqM_F2xqC_gauss(GEN a, GEN b, GEN T)
2102 : {
2103 28 : pari_sp av = avma;
2104 : GEN u;
2105 28 : if (lg(a) == 1) return cgetg(1, t_COL);
2106 28 : u = F2xqM_gauss_gen(a, mkmat(b), T);
2107 28 : if (!u) return gc_NULL(av);
2108 14 : return gerepilecopy(av, gel(u,1));
2109 : }
2110 :
2111 : GEN
2112 14 : FlxqM_FlxqC_gauss(GEN a, GEN b, GEN T, ulong p)
2113 : {
2114 14 : pari_sp av = avma;
2115 : GEN u;
2116 14 : if (lg(a) == 1) return cgetg(1, t_COL);
2117 14 : u = FlxqM_gauss_i(a, mkmat(b), T, p);
2118 14 : if (!u) return gc_NULL(av);
2119 7 : return gerepilecopy(av, gel(u,1));
2120 : }
2121 :
2122 : GEN
2123 14 : FqM_FqC_gauss(GEN a, GEN b, GEN T, GEN p)
2124 : {
2125 14 : pari_sp av = avma;
2126 : GEN u;
2127 14 : if (!T) return FpM_FpC_gauss(a,b,p);
2128 14 : if (lg(a) == 1) return cgetg(1, t_COL);
2129 14 : u = FqM_gauss_gen(a,mkmat(b),T,p);
2130 14 : if (!u) return gc_NULL(av);
2131 7 : return gerepilecopy(av, gel(u,1));
2132 : }
2133 :
2134 : GEN
2135 347534 : FpM_inv(GEN a, GEN p)
2136 : {
2137 347534 : pari_sp av = avma;
2138 : ulong pp;
2139 : GEN u;
2140 347534 : if (lg(a) == 1) return cgetg(1, t_MAT);
2141 347534 : u = FpM_gauss_i(a, NULL, p, &pp);
2142 347534 : if (!u) return gc_NULL(av);
2143 347520 : switch(pp)
2144 : {
2145 2693 : case 0: return gerepilecopy(av, u);
2146 226944 : case 2: u = F2m_to_ZM(u); break;
2147 117883 : default: u = Flm_to_ZM(u); break;
2148 : }
2149 344824 : return gerepileupto(av, u);
2150 : }
2151 :
2152 : GEN
2153 35 : F2xqM_inv(GEN a, GEN T)
2154 : {
2155 35 : pari_sp av = avma;
2156 : GEN u;
2157 35 : if (lg(a) == 1) { set_avma(av); return cgetg(1, t_MAT); }
2158 35 : u = F2xqM_gauss_gen(a, matid_F2xqM(nbrows(a),T), T);
2159 35 : if (!u) return gc_NULL(av);
2160 28 : return gerepilecopy(av, u);
2161 : }
2162 :
2163 : GEN
2164 56 : FlxqM_inv(GEN a, GEN T, ulong p)
2165 : {
2166 56 : pari_sp av = avma;
2167 : GEN u;
2168 56 : if (lg(a) == 1) { set_avma(av); return cgetg(1, t_MAT); }
2169 56 : u = FlxqM_gauss_i(a, matid_FlxqM(nbrows(a),T,p), T,p);
2170 56 : if (!u) return gc_NULL(av);
2171 42 : return gerepilecopy(av, u);
2172 : }
2173 :
2174 : GEN
2175 98 : FqM_inv(GEN a, GEN T, GEN p)
2176 : {
2177 98 : pari_sp av = avma;
2178 : GEN u;
2179 98 : if (!T) return FpM_inv(a,p);
2180 98 : if (lg(a) == 1) return cgetg(1, t_MAT);
2181 98 : u = FqM_gauss_gen(a,matid(nbrows(a)),T,p);
2182 98 : if (!u) return gc_NULL(av);
2183 70 : return gerepilecopy(av, u);
2184 : }
2185 :
2186 : GEN
2187 263070 : FpM_intersect_i(GEN x, GEN y, GEN p)
2188 : {
2189 263070 : long j, lx = lg(x);
2190 : GEN z;
2191 :
2192 263070 : if (lx == 1 || lg(y) == 1) return cgetg(1,t_MAT);
2193 263070 : if (lgefint(p) == 3)
2194 : {
2195 263070 : ulong pp = p[2];
2196 263070 : return Flm_to_ZM(Flm_intersect_i(ZM_to_Flm(x,pp), ZM_to_Flm(y,pp), pp));
2197 : }
2198 0 : z = FpM_ker(shallowconcat(x,y), p);
2199 0 : for (j=lg(z)-1; j; j--) setlg(gel(z,j),lx);
2200 0 : return FpM_mul(x,z,p);
2201 : }
2202 : GEN
2203 0 : FpM_intersect(GEN x, GEN y, GEN p)
2204 : {
2205 0 : pari_sp av = avma;
2206 : GEN z;
2207 0 : if (lgefint(p) == 3)
2208 : {
2209 0 : ulong pp = p[2];
2210 0 : z = Flm_to_ZM(Flm_image(Flm_intersect_i(ZM_to_Flm(x,pp), ZM_to_Flm(y,pp), pp), pp));
2211 : }
2212 : else
2213 0 : z = FpM_image(FpM_intersect_i(x,y,p), p);
2214 0 : return gerepileupto(av, z);
2215 : }
2216 :
2217 : static void
2218 269590 : init_suppl(GEN x)
2219 : {
2220 269590 : if (lg(x) == 1) pari_err_IMPL("suppl [empty matrix]");
2221 : /* HACK: avoid overwriting d from gauss_pivot() after set_avma(av) */
2222 269590 : (void)new_chunk(lgcols(x) * 2);
2223 269589 : }
2224 :
2225 : GEN
2226 268023 : FpM_suppl(GEN x, GEN p)
2227 : {
2228 : GEN d;
2229 : long r;
2230 268023 : init_suppl(x); d = FpM_gauss_pivot(x,p, &r);
2231 268022 : return get_suppl(x,d,nbrows(x),r,&col_ei);
2232 : }
2233 :
2234 : GEN
2235 14 : F2m_suppl(GEN x)
2236 : {
2237 : GEN d;
2238 : long r;
2239 14 : init_suppl(x); d = F2m_gauss_pivot(F2m_copy(x), &r);
2240 14 : return get_suppl(x,d,mael(x,1,1),r,&F2v_ei);
2241 : }
2242 :
2243 : GEN
2244 105 : Flm_suppl(GEN x, ulong p)
2245 : {
2246 : GEN d;
2247 : long r;
2248 105 : init_suppl(x); d = Flm_pivots(x, p, &r, 0);
2249 105 : return get_suppl(x,d,nbrows(x),r,&vecsmall_ei);
2250 : }
2251 :
2252 : GEN
2253 7 : F2xqM_suppl(GEN x, GEN T)
2254 : {
2255 : void *E;
2256 7 : const struct bb_field *S = get_F2xq_field(&E, T);
2257 7 : return gen_suppl(x, E, S, _F2xqM_mul);
2258 : }
2259 :
2260 : GEN
2261 14 : FlxqM_suppl(GEN x, GEN T, ulong p)
2262 : {
2263 : void *E;
2264 14 : const struct bb_field *S = get_Flxq_field(&E, T, p);
2265 14 : return gen_suppl(x, E, S, _FlxqM_mul);
2266 : }
2267 :
2268 : GEN
2269 5319 : FqM_suppl(GEN x, GEN T, GEN p)
2270 : {
2271 5319 : pari_sp av = avma;
2272 : GEN d;
2273 : long r;
2274 :
2275 5319 : if (!T) return FpM_suppl(x,p);
2276 1378 : init_suppl(x);
2277 1378 : d = FqM_gauss_pivot(x,T,p,&r);
2278 1378 : set_avma(av); return get_suppl(x,d,nbrows(x),r,&col_ei);
2279 : }
2280 :
2281 : static void
2282 1951009 : init_indexrank(GEN x) {
2283 1951009 : (void)new_chunk(3 + 2*lg(x)); /* HACK */
2284 1951007 : }
2285 :
2286 : GEN
2287 39275 : FpM_indexrank(GEN x, GEN p) {
2288 39275 : pari_sp av = avma;
2289 : long r;
2290 : GEN d;
2291 39275 : init_indexrank(x);
2292 39275 : d = FpM_gauss_pivot(x,p,&r);
2293 39275 : set_avma(av); return indexrank0(lg(x)-1, r, d);
2294 : }
2295 :
2296 : GEN
2297 56447 : Flm_indexrank(GEN x, ulong p) {
2298 56447 : pari_sp av = avma;
2299 : long r;
2300 : GEN d;
2301 56447 : init_indexrank(x);
2302 56447 : d = Flm_pivots(x, p, &r, 0);
2303 56448 : set_avma(av); return indexrank0(lg(x)-1, r, d);
2304 : }
2305 :
2306 : GEN
2307 53 : F2m_indexrank(GEN x) {
2308 53 : pari_sp av = avma;
2309 : long r;
2310 : GEN d;
2311 53 : init_indexrank(x);
2312 53 : d = F2m_gauss_pivot(F2m_copy(x),&r);
2313 53 : set_avma(av); return indexrank0(lg(x)-1, r, d);
2314 : }
2315 :
2316 : GEN
2317 7 : F2xqM_indexrank(GEN x, GEN T) {
2318 7 : pari_sp av = avma;
2319 : long r;
2320 : GEN d;
2321 7 : init_indexrank(x);
2322 7 : d = F2xqM_gauss_pivot(x, T, &r);
2323 7 : set_avma(av); return indexrank0(lg(x) - 1, r, d);
2324 : }
2325 :
2326 : GEN
2327 7 : FlxqM_indexrank(GEN x, GEN T, ulong p) {
2328 7 : pari_sp av = avma;
2329 : long r;
2330 : GEN d;
2331 7 : init_indexrank(x);
2332 7 : d = FlxqM_gauss_pivot(x, T, p, &r);
2333 7 : set_avma(av); return indexrank0(lg(x) - 1, r, d);
2334 : }
2335 :
2336 : GEN
2337 7 : FqM_indexrank(GEN x, GEN T, GEN p) {
2338 7 : pari_sp av = avma;
2339 : long r;
2340 : GEN d;
2341 7 : init_indexrank(x);
2342 7 : d = FqM_gauss_pivot(x, T, p, &r);
2343 7 : set_avma(av); return indexrank0(lg(x) - 1, r, d);
2344 : }
2345 :
2346 : /*******************************************************************/
2347 : /* */
2348 : /* Solve A*X=B (Gauss pivot) */
2349 : /* */
2350 : /*******************************************************************/
2351 : /* x a column, x0 same column in the original input matrix (for reference),
2352 : * c list of pivots so far */
2353 : static long
2354 2592640 : gauss_get_pivot_max(GEN X, GEN X0, long ix, GEN c)
2355 : {
2356 2592640 : GEN p, r, x = gel(X,ix), x0 = gel(X0,ix);
2357 2592640 : long i, k = 0, ex = - (long)HIGHEXPOBIT, lx = lg(x);
2358 2592640 : if (c)
2359 : {
2360 580232 : for (i=1; i<lx; i++)
2361 361106 : if (!c[i])
2362 : {
2363 146272 : long e = gexpo(gel(x,i));
2364 146272 : if (e > ex) { ex = e; k = i; }
2365 : }
2366 : }
2367 : else
2368 : {
2369 8419098 : for (i=ix; i<lx; i++)
2370 : {
2371 6045568 : long e = gexpo(gel(x,i));
2372 6045584 : if (e > ex) { ex = e; k = i; }
2373 : }
2374 : }
2375 2592656 : if (!k) return lx;
2376 2477673 : p = gel(x,k);
2377 2477673 : r = gel(x0,k); if (isrationalzero(r)) r = x0;
2378 2477678 : return cx_approx0(p, r)? lx: k;
2379 : }
2380 : static long
2381 201792 : gauss_get_pivot_padic(GEN X, GEN p, long ix, GEN c)
2382 : {
2383 201792 : GEN x = gel(X, ix);
2384 201792 : long i, k = 0, ex = (long)HIGHVALPBIT, lx = lg(x);
2385 201792 : if (c)
2386 : {
2387 504 : for (i=1; i<lx; i++)
2388 378 : if (!c[i] && !gequal0(gel(x,i)))
2389 : {
2390 245 : long e = gvaluation(gel(x,i), p);
2391 245 : if (e < ex) { ex = e; k = i; }
2392 : }
2393 : }
2394 : else
2395 : {
2396 1721226 : for (i=ix; i<lx; i++)
2397 1519560 : if (!gequal0(gel(x,i)))
2398 : {
2399 1146977 : long e = gvaluation(gel(x,i), p);
2400 1146977 : if (e < ex) { ex = e; k = i; }
2401 : }
2402 : }
2403 201792 : return k? k: lx;
2404 : }
2405 : static long
2406 4501 : gauss_get_pivot_NZ(GEN X, GEN x0/*unused*/, long ix, GEN c)
2407 : {
2408 4501 : GEN x = gel(X, ix);
2409 4501 : long i, lx = lg(x);
2410 : (void)x0;
2411 4501 : if (c)
2412 : {
2413 12775 : for (i=1; i<lx; i++)
2414 11795 : if (!c[i] && !gequal0(gel(x,i))) return i;
2415 : }
2416 : else
2417 : {
2418 2380 : for (i=ix; i<lx; i++)
2419 2366 : if (!gequal0(gel(x,i))) return i;
2420 : }
2421 994 : return lx;
2422 : }
2423 :
2424 : /* Return pivot seeking function appropriate for the domain of the RgM x
2425 : * (first non zero pivot, maximal pivot...)
2426 : * x0 is a reference point used when guessing whether x[i,j] ~ 0
2427 : * (iff x[i,j] << x0[i,j]); typical case: mateigen, Gauss pivot on x - vp.Id,
2428 : * but use original x when deciding whether a prospective pivot is nonzero */
2429 : static pivot_fun
2430 801818 : get_pivot_fun(GEN x, GEN x0, GEN *data)
2431 : {
2432 801818 : long i, j, hx, lx = lg(x);
2433 801818 : int res = t_INT;
2434 801818 : GEN p = NULL;
2435 :
2436 801818 : *data = NULL;
2437 801818 : if (lx == 1) return &gauss_get_pivot_NZ;
2438 801783 : hx = lgcols(x);
2439 3660109 : for (j=1; j<lx; j++)
2440 : {
2441 2858368 : GEN xj = gel(x,j);
2442 15867415 : for (i=1; i<hx; i++)
2443 : {
2444 13009089 : GEN c = gel(xj,i);
2445 13009089 : switch(typ(c))
2446 : {
2447 7424351 : case t_REAL:
2448 7424351 : res = t_REAL;
2449 7424351 : break;
2450 3640 : case t_COMPLEX:
2451 3640 : if (typ(gel(c,1)) == t_REAL || typ(gel(c,2)) == t_REAL) res = t_REAL;
2452 3640 : break;
2453 4399198 : case t_INT: case t_INTMOD: case t_FRAC: case t_FFELT: case t_QUAD:
2454 : case t_POLMOD: /* exact types */
2455 4399198 : break;
2456 1181858 : case t_PADIC:
2457 1181858 : p = gel(c,2);
2458 1181858 : res = t_PADIC;
2459 1181858 : break;
2460 42 : default: return &gauss_get_pivot_NZ;
2461 : }
2462 : }
2463 : }
2464 801741 : switch(res)
2465 : {
2466 773406 : case t_REAL: *data = x0; return &gauss_get_pivot_max;
2467 26991 : case t_PADIC: *data = p; return &gauss_get_pivot_padic;
2468 1344 : default: return &gauss_get_pivot_NZ;
2469 : }
2470 : }
2471 :
2472 : static GEN
2473 1265628 : get_col(GEN a, GEN b, GEN p, long li)
2474 : {
2475 1265628 : GEN u = cgetg(li+1,t_COL);
2476 : long i, j;
2477 :
2478 1265626 : gel(u,li) = gdiv(gel(b,li), p);
2479 5149549 : for (i=li-1; i>0; i--)
2480 : {
2481 3883924 : pari_sp av = avma;
2482 3883924 : GEN m = gel(b,i);
2483 17086239 : for (j=i+1; j<=li; j++) m = gsub(m, gmul(gcoeff(a,i,j), gel(u,j)));
2484 3883883 : gel(u,i) = gerepileupto(av, gdiv(m, gcoeff(a,i,i)));
2485 : }
2486 1265625 : return u;
2487 : }
2488 :
2489 : /* bk -= m * bi */
2490 : static void
2491 18289404 : _submul(GEN b, long k, long i, GEN m)
2492 : {
2493 18289404 : gel(b,k) = gsub(gel(b,k), gmul(m, gel(b,i)));
2494 18289268 : }
2495 : static int
2496 2408445 : init_gauss(GEN a, GEN *b, long *aco, long *li, int *iscol)
2497 : {
2498 2408445 : *iscol = *b ? (typ(*b) == t_COL): 0;
2499 2408445 : *aco = lg(a) - 1;
2500 2408445 : if (!*aco) /* a empty */
2501 : {
2502 70 : if (*b && lg(*b) != 1) pari_err_DIM("gauss");
2503 70 : *li = 0; return 0;
2504 : }
2505 2408375 : *li = nbrows(a);
2506 2408376 : if (*li < *aco) pari_err_INV("gauss [no left inverse]", a);
2507 2408377 : if (*b)
2508 : {
2509 2144089 : switch(typ(*b))
2510 : {
2511 121599 : case t_MAT:
2512 121599 : if (lg(*b) == 1) return 0;
2513 121599 : *b = RgM_shallowcopy(*b);
2514 121599 : break;
2515 2022493 : case t_COL:
2516 2022493 : *b = mkmat( leafcopy(*b) );
2517 2022494 : break;
2518 0 : default: pari_err_TYPE("gauss",*b);
2519 : }
2520 2144093 : if (nbrows(*b) != *li) pari_err_DIM("gauss");
2521 : }
2522 : else
2523 264288 : *b = matid(*li);
2524 2408377 : return 1;
2525 : }
2526 :
2527 : static GEN
2528 2051 : RgM_inv_FpM(GEN a, GEN p)
2529 : {
2530 : ulong pp;
2531 2051 : a = RgM_Fp_init(a, p, &pp);
2532 2051 : switch(pp)
2533 : {
2534 35 : case 0:
2535 35 : a = FpM_inv(a,p);
2536 35 : if (a) a = FpM_to_mod(a, p);
2537 35 : break;
2538 189 : case 2:
2539 189 : a = F2m_inv(a);
2540 189 : if (a) a = F2m_to_mod(a);
2541 189 : break;
2542 1827 : default:
2543 1827 : a = Flm_inv_sp(a, NULL, pp);
2544 1827 : if (a) a = Flm_to_mod(a, pp);
2545 : }
2546 2051 : return a;
2547 : }
2548 :
2549 : static GEN
2550 42 : RgM_inv_FqM(GEN x, GEN pol, GEN p)
2551 : {
2552 42 : pari_sp av = avma;
2553 42 : GEN b, T = RgX_to_FpX(pol, p);
2554 42 : if (signe(T) == 0) pari_err_OP("^",x,gen_m1);
2555 42 : b = FqM_inv(RgM_to_FqM(x, T, p), T, p);
2556 42 : if (!b) return gc_NULL(av);
2557 28 : return gerepileupto(av, FqM_to_mod(b, T, p));
2558 : }
2559 :
2560 : #define code(t1,t2) ((t1 << 6) | t2)
2561 : static GEN
2562 527195 : RgM_inv_fast(GEN x)
2563 : {
2564 : GEN p, pol;
2565 : long pa;
2566 527195 : long t = RgM_type(x, &p,&pol,&pa);
2567 527200 : switch(t)
2568 : {
2569 48314 : case t_INT: /* Fall back */
2570 48314 : case t_FRAC: return QM_inv(x);
2571 147 : case t_FFELT: return FFM_inv(x, pol);
2572 2051 : case t_INTMOD: return RgM_inv_FpM(x, p);
2573 42 : case code(t_POLMOD, t_INTMOD):
2574 42 : return RgM_inv_FqM(x, pol, p);
2575 476646 : default: return gen_0;
2576 : }
2577 : }
2578 : #undef code
2579 :
2580 : static GEN
2581 49 : RgM_RgC_solve_FpC(GEN a, GEN b, GEN p)
2582 : {
2583 49 : pari_sp av = avma;
2584 : ulong pp;
2585 49 : a = RgM_Fp_init(a, p, &pp);
2586 49 : switch(pp)
2587 : {
2588 14 : case 0:
2589 14 : b = RgC_to_FpC(b, p);
2590 14 : a = FpM_FpC_gauss(a,b,p);
2591 14 : return a ? gerepileupto(av, FpC_to_mod(a, p)): NULL;
2592 14 : case 2:
2593 14 : b = RgV_to_F2v(b);
2594 14 : a = F2m_F2c_gauss(a,b);
2595 14 : return a ? gerepileupto(av, F2c_to_mod(a)): NULL;
2596 21 : default:
2597 21 : b = RgV_to_Flv(b, pp);
2598 21 : a = Flm_Flc_gauss(a, b, pp);
2599 21 : return a ? gerepileupto(av, Flc_to_mod(a, pp)): NULL;
2600 : }
2601 : }
2602 :
2603 : static GEN
2604 98 : RgM_solve_FpM(GEN a, GEN b, GEN p)
2605 : {
2606 98 : pari_sp av = avma;
2607 : ulong pp;
2608 98 : a = RgM_Fp_init(a, p, &pp);
2609 98 : switch(pp)
2610 : {
2611 35 : case 0:
2612 35 : b = RgM_to_FpM(b, p);
2613 35 : a = FpM_gauss(a,b,p);
2614 35 : return a ? gerepileupto(av, FpM_to_mod(a, p)): NULL;
2615 21 : case 2:
2616 21 : b = RgM_to_F2m(b);
2617 21 : a = F2m_gauss(a,b);
2618 21 : return a ? gerepileupto(av, F2m_to_mod(a)): NULL;
2619 42 : default:
2620 42 : b = RgM_to_Flm(b, pp);
2621 42 : a = Flm_gauss(a,b,pp);
2622 42 : return a ? gerepileupto(av, Flm_to_mod(a, pp)): NULL;
2623 : }
2624 : }
2625 :
2626 : /* Gaussan Elimination. If a is square, return a^(-1)*b;
2627 : * if a has more rows than columns and b is NULL, return c such that c a = Id.
2628 : * a is a (not necessarily square) matrix
2629 : * b is a matrix or column vector, NULL meaning: take the identity matrix,
2630 : * effectively returning the inverse of a
2631 : * If a and b are empty, the result is the empty matrix.
2632 : *
2633 : * li: number of rows of a and b
2634 : * aco: number of columns of a
2635 : * bco: number of columns of b (if matrix)
2636 : */
2637 : static GEN
2638 1693398 : RgM_solve_basecase(GEN a, GEN b)
2639 : {
2640 1693398 : pari_sp av = avma;
2641 : long i, j, k, li, bco, aco;
2642 : int iscol;
2643 : pivot_fun pivot;
2644 : GEN p, u, data;
2645 :
2646 1693398 : set_avma(av);
2647 :
2648 1693398 : if (lg(a)-1 == 2 && nbrows(a) == 2) {
2649 : /* 2x2 matrix, start by inverting a */
2650 1027276 : GEN u = gcoeff(a,1,1), v = gcoeff(a,1,2);
2651 1027276 : GEN w = gcoeff(a,2,1), x = gcoeff(a,2,2);
2652 1027276 : GEN D = gsub(gmul(u,x), gmul(v,w)), ainv;
2653 1027264 : if (gequal0(D)) return NULL;
2654 1027263 : ainv = mkmat2(mkcol2(x, gneg(w)), mkcol2(gneg(v), u));
2655 1027264 : ainv = gmul(ainv, ginv(D));
2656 1027257 : if (b) ainv = gmul(ainv, b);
2657 1027258 : return gerepileupto(av, ainv);
2658 : }
2659 :
2660 666121 : if (!init_gauss(a, &b, &aco, &li, &iscol)) return cgetg(1, iscol?t_COL:t_MAT);
2661 666121 : pivot = get_pivot_fun(a, a, &data);
2662 666121 : a = RgM_shallowcopy(a);
2663 666122 : bco = lg(b)-1;
2664 666122 : if(DEBUGLEVEL>4) err_printf("Entering gauss\n");
2665 :
2666 666122 : p = NULL; /* gcc -Wall */
2667 2292237 : for (i=1; i<=aco; i++)
2668 : {
2669 : /* k is the line where we find the pivot */
2670 2292230 : k = pivot(a, data, i, NULL);
2671 2292243 : if (k > li) return NULL;
2672 2292228 : if (k != i)
2673 : { /* exchange the lines s.t. k = i */
2674 1794940 : for (j=i; j<=aco; j++) swap(gcoeff(a,i,j), gcoeff(a,k,j));
2675 1738815 : for (j=1; j<=bco; j++) swap(gcoeff(b,i,j), gcoeff(b,k,j));
2676 : }
2677 2292228 : p = gcoeff(a,i,i);
2678 2292228 : if (i == aco) break;
2679 :
2680 5118246 : for (k=i+1; k<=li; k++)
2681 : {
2682 3492149 : GEN m = gcoeff(a,k,i);
2683 3492149 : if (!gequal0(m))
2684 : {
2685 2837121 : m = gdiv(m,p);
2686 12111440 : for (j=i+1; j<=aco; j++) _submul(gel(a,j),k,i,m);
2687 11852391 : for (j=1; j<=bco; j++) _submul(gel(b,j),k,i,m);
2688 : }
2689 : }
2690 1626097 : if (gc_needed(av,1))
2691 : {
2692 12 : if(DEBUGMEM>1) pari_warn(warnmem,"gauss. i=%ld",i);
2693 12 : gerepileall(av,2, &a,&b);
2694 : }
2695 : }
2696 :
2697 666112 : if(DEBUGLEVEL>4) err_printf("Solving the triangular system\n");
2698 666112 : u = cgetg(bco+1,t_MAT);
2699 1931728 : for (j=1; j<=bco; j++) gel(u,j) = get_col(a,gel(b,j),p,aco);
2700 666101 : return gerepilecopy(av, iscol? gel(u,1): u);
2701 : }
2702 :
2703 : static GEN
2704 1183430 : RgM_RgC_solve_fast(GEN x, GEN y)
2705 : {
2706 : GEN p, pol;
2707 : long pa;
2708 1183430 : long t = RgM_RgC_type(x, y, &p,&pol,&pa);
2709 1183428 : switch(t)
2710 : {
2711 14930 : case t_INT: return ZM_gauss(x, y);
2712 175 : case t_FRAC: return QM_gauss(x, y);
2713 49 : case t_INTMOD: return RgM_RgC_solve_FpC(x, y, p);
2714 56 : case t_FFELT: return FFM_FFC_gauss(x, y, pol);
2715 1168218 : default: return gen_0;
2716 : }
2717 : }
2718 :
2719 : static GEN
2720 48790 : RgM_solve_fast(GEN x, GEN y)
2721 : {
2722 : GEN p, pol;
2723 : long pa;
2724 48790 : long t = RgM_type2(x, y, &p,&pol,&pa);
2725 48790 : switch(t)
2726 : {
2727 77 : case t_INT: return ZM_gauss(x, y);
2728 14 : case t_FRAC: return QM_gauss(x, y);
2729 98 : case t_INTMOD: return RgM_solve_FpM(x, y, p);
2730 63 : case t_FFELT: return FFM_gauss(x, y, pol);
2731 48538 : default: return gen_0;
2732 : }
2733 : }
2734 :
2735 : GEN
2736 1232220 : RgM_solve(GEN a, GEN b)
2737 : {
2738 1232220 : pari_sp av = avma;
2739 : GEN u;
2740 1232220 : if (!b) return RgM_inv(a);
2741 1232220 : u = typ(b)==t_MAT ? RgM_solve_fast(a, b): RgM_RgC_solve_fast(a, b);
2742 1232218 : if (!u) return gc_NULL(av);
2743 1232113 : if (u != gen_0) return u;
2744 1216756 : return RgM_solve_basecase(a, b);
2745 : }
2746 :
2747 : GEN
2748 28 : RgM_div(GEN a, GEN b)
2749 : {
2750 28 : pari_sp av = avma;
2751 28 : GEN u = RgM_solve(shallowtrans(b), shallowtrans(a));
2752 28 : if (!u) return gc_NULL(av);
2753 21 : return gerepilecopy(av, shallowtrans(u));
2754 : }
2755 :
2756 : GEN
2757 527194 : RgM_inv(GEN a)
2758 : {
2759 527194 : GEN b = RgM_inv_fast(a);
2760 527185 : return b==gen_0? RgM_solve_basecase(a, NULL): b;
2761 : }
2762 :
2763 : /* assume dim A >= 1, A invertible + upper triangular */
2764 : static GEN
2765 3229805 : RgM_inv_upper_ind(GEN A, long index)
2766 : {
2767 3229805 : long n = lg(A)-1, i = index, j;
2768 3229805 : GEN u = zerocol(n);
2769 3229805 : gel(u,i) = ginv(gcoeff(A,i,i));
2770 6533706 : for (i--; i>0; i--)
2771 : {
2772 3303908 : pari_sp av = avma;
2773 3303908 : GEN m = gneg(gmul(gcoeff(A,i,i+1),gel(u,i+1))); /* j = i+1 */
2774 14640849 : for (j=i+2; j<=n; j++) m = gsub(m, gmul(gcoeff(A,i,j),gel(u,j)));
2775 3303870 : gel(u,i) = gerepileupto(av, gdiv(m, gcoeff(A,i,i)));
2776 : }
2777 3229798 : return u;
2778 : }
2779 : GEN
2780 1616935 : RgM_inv_upper(GEN A)
2781 : {
2782 : long i, l;
2783 1616935 : GEN B = cgetg_copy(A, &l);
2784 4846733 : for (i = 1; i < l; i++) gel(B,i) = RgM_inv_upper_ind(A, i);
2785 1616928 : return B;
2786 : }
2787 :
2788 : static GEN
2789 4517461 : split_realimag_col(GEN z, long r1, long r2)
2790 : {
2791 4517461 : long i, ru = r1+r2;
2792 4517461 : GEN x = cgetg(ru+r2+1,t_COL), y = x + r2;
2793 12540867 : for (i=1; i<=r1; i++) {
2794 8023406 : GEN a = gel(z,i);
2795 8023406 : if (typ(a) == t_COMPLEX) a = gel(a,1); /* paranoia: a should be real */
2796 8023406 : gel(x,i) = a;
2797 : }
2798 7224477 : for ( ; i<=ru; i++) {
2799 2707016 : GEN b, a = gel(z,i);
2800 2707016 : if (typ(a) == t_COMPLEX) { b = gel(a,2); a = gel(a,1); } else b = gen_0;
2801 2707016 : gel(x,i) = a;
2802 2707016 : gel(y,i) = b;
2803 : }
2804 4517461 : return x;
2805 : }
2806 : GEN
2807 2570289 : split_realimag(GEN x, long r1, long r2)
2808 : {
2809 : long i,l; GEN y;
2810 2570289 : if (typ(x) == t_COL) return split_realimag_col(x,r1,r2);
2811 1278071 : y = cgetg_copy(x, &l);
2812 4503319 : for (i=1; i<l; i++) gel(y,i) = split_realimag_col(gel(x,i), r1, r2);
2813 1278074 : return y;
2814 : }
2815 :
2816 : /* assume M = (r1+r2) x (r1+2r2) matrix and y compatible vector or matrix
2817 : * r1 first lines of M,y are real. Solve the system obtained by splitting
2818 : * real and imaginary parts. */
2819 : GEN
2820 1215622 : RgM_solve_realimag(GEN M, GEN y)
2821 : {
2822 1215622 : long l = lg(M), r2 = l - lgcols(M), r1 = l-1 - 2*r2;
2823 1215622 : return RgM_solve(split_realimag(M, r1,r2),
2824 : split_realimag(y, r1,r2));
2825 : }
2826 :
2827 : GEN
2828 434 : gauss(GEN a, GEN b)
2829 : {
2830 : GEN z;
2831 434 : long t = typ(b);
2832 434 : if (typ(a)!=t_MAT) pari_err_TYPE("gauss",a);
2833 434 : if (t!=t_COL && t!=t_MAT) pari_err_TYPE("gauss",b);
2834 434 : z = RgM_solve(a,b);
2835 434 : if (!z) pari_err_INV("gauss",a);
2836 329 : return z;
2837 : }
2838 :
2839 : /* #C = n, C[z[i]] = K[i], complete by 0s */
2840 : static GEN
2841 14 : RgC_inflate(GEN K, GEN z, long n)
2842 : {
2843 14 : GEN c = zerocol(n);
2844 14 : long j, l = lg(K);
2845 28 : for (j = 1; j < l; j++) gel(c, z[j]) = gel(K, j);
2846 14 : return c;
2847 : }
2848 : /* in place: C[i] *= cB / v[i] */
2849 : static void
2850 6482 : QC_normalize(GEN C, GEN v, GEN cB)
2851 : {
2852 6482 : long l = lg(C), i;
2853 48531 : for (i = 1; i < l; i++)
2854 : {
2855 42049 : GEN c = cB, k = gel(C,i), d = gel(v,i);
2856 42049 : if (d)
2857 : {
2858 24968 : if (isintzero(d)) { gel(C,i) = gen_0; continue; }
2859 24968 : c = div_content(c, d);
2860 : }
2861 42049 : gel(C,i) = c? gmul(k,c): k;
2862 : }
2863 6482 : }
2864 :
2865 : /* same as above, M rational; if flag = 1, call indexrank and return 1 sol */
2866 : GEN
2867 6475 : QM_gauss_i(GEN M, GEN B, long flag)
2868 : {
2869 6475 : pari_sp av = avma;
2870 : long i, l, n;
2871 6475 : int col = typ(B) == t_COL;
2872 6475 : GEN K, cB, N = cgetg_copy(M, &l), v = cgetg(l, t_VEC), z2 = NULL;
2873 :
2874 48552 : for (i = 1; i < l; i++)
2875 42077 : gel(N,i) = Q_primitive_part(gel(M,i), &gel(v,i));
2876 6475 : if (flag)
2877 : {
2878 329 : GEN z = ZM_indexrank(N), z1 = gel(z,1);
2879 329 : z2 = gel(z,2);
2880 329 : N = shallowmatextract(N, z1, z2);
2881 329 : B = col? vecpermute(B,z1): rowpermute(B,z1);
2882 329 : if (lg(z2) == l) z2 = NULL; else v = vecpermute(v, z2);
2883 : }
2884 6475 : B = Q_primitive_part(B, &cB);
2885 6475 : K = ZM_gauss(N, B); if (!K) return gc_NULL(av);
2886 6475 : n = l - 1;
2887 6475 : if (col)
2888 : {
2889 6447 : QC_normalize(K, v, cB);
2890 6447 : if (z2) K = RgC_inflate(K, z2, n);
2891 : }
2892 : else
2893 : {
2894 28 : long lK = lg(K);
2895 63 : for (i = 1; i < lK; i++)
2896 : {
2897 35 : QC_normalize(gel(K,i), v, cB);
2898 35 : if (z2) gel(K,i) = RgC_inflate(gel(K,i), z2, n);
2899 : }
2900 : }
2901 6475 : return gerepilecopy(av, K);
2902 : }
2903 : GEN
2904 6146 : QM_gauss(GEN M, GEN B) { return QM_gauss_i(M, B, 0); }
2905 :
2906 : static GEN
2907 790439 : ZM_inv_slice(GEN A, GEN P, GEN *mod)
2908 : {
2909 790439 : pari_sp av = avma;
2910 790439 : long i, n = lg(P)-1;
2911 : GEN H, T;
2912 790439 : if (n == 1)
2913 : {
2914 757972 : ulong p = uel(P,1);
2915 757972 : GEN Hp, a = ZM_to_Flm(A, p);
2916 757972 : Hp = Flm_adjoint(a, p);
2917 757972 : Hp = gerepileupto(av, Flm_to_ZM(Hp));
2918 757972 : *mod = utoipos(p); return Hp;
2919 : }
2920 32467 : T = ZV_producttree(P);
2921 32468 : A = ZM_nv_mod_tree(A, P, T);
2922 32469 : H = cgetg(n+1, t_VEC);
2923 180545 : for(i=1; i <= n; i++)
2924 148076 : gel(H,i) = Flm_adjoint(gel(A, i), uel(P,i));
2925 32469 : H = nmV_chinese_center_tree_seq(H, P, T, ZV_chinesetree(P,T));
2926 32469 : *mod = gmael(T, lg(T)-1, 1); return gc_all(av, 2, &H, mod);
2927 : }
2928 :
2929 : static GEN
2930 717575 : RgM_true_Hadamard(GEN a)
2931 : {
2932 717575 : pari_sp av = avma;
2933 717575 : long n = lg(a)-1, i;
2934 : GEN B;
2935 717575 : if (n == 0) return gen_1;
2936 717575 : a = RgM_gtofp(a, LOWDEFAULTPREC);
2937 717573 : B = gnorml2(gel(a,1));
2938 2956801 : for (i = 2; i <= n; i++) B = gmul(B, gnorml2(gel(a,i)));
2939 717573 : return gerepileuptoint(av, ceil_safe(sqrtr(B)));
2940 : }
2941 :
2942 : GEN
2943 790440 : ZM_inv_worker(GEN P, GEN A)
2944 : {
2945 790440 : GEN V = cgetg(3, t_VEC);
2946 790439 : gel(V,1) = ZM_inv_slice(A, P, &gel(V,2));
2947 790441 : return V;
2948 : }
2949 :
2950 : static GEN
2951 43505 : ZM_inv0(GEN A, GEN *pden)
2952 : {
2953 43505 : if (pden) *pden = gen_1;
2954 43505 : (void)A; return cgetg(1, t_MAT);
2955 : }
2956 : static GEN
2957 644139 : ZM_inv1(GEN A, GEN *pden)
2958 : {
2959 644139 : GEN a = gcoeff(A,1,1);
2960 644139 : long s = signe(a);
2961 644139 : if (!s) return NULL;
2962 644139 : if (pden) *pden = absi(a);
2963 644139 : retmkmat(mkcol(s == 1? gen_1: gen_m1));
2964 : }
2965 : static GEN
2966 724623 : ZM_inv2(GEN A, GEN *pden)
2967 : {
2968 : GEN a, b, c, d, D, cA;
2969 : long s;
2970 724623 : A = Q_primitive_part(A, &cA);
2971 724625 : a = gcoeff(A,1,1); b = gcoeff(A,1,2);
2972 724625 : c = gcoeff(A,2,1); d = gcoeff(A,2,2);
2973 724625 : D = subii(mulii(a,d), mulii(b,c)); /* left on stack */
2974 724620 : s = signe(D);
2975 724620 : if (!s) return NULL;
2976 724606 : if (s < 0) D = negi(D);
2977 724608 : if (pden) *pden = mul_denom(D, cA);
2978 724607 : if (s > 0)
2979 683093 : retmkmat2(mkcol2(icopy(d), negi(c)), mkcol2(negi(b), icopy(a)));
2980 : else
2981 41514 : retmkmat2(mkcol2(negi(d), icopy(c)), mkcol2(icopy(b), negi(a)));
2982 : }
2983 :
2984 : /* to be used when denom(M^(-1)) << det(M) and a sharp multiple is
2985 : * not available. Return H primitive such that M*H = den*Id */
2986 : GEN
2987 0 : ZM_inv_ratlift(GEN M, GEN *pden)
2988 : {
2989 0 : pari_sp av2, av = avma;
2990 : GEN Hp, q, H;
2991 : ulong p;
2992 0 : long m = lg(M)-1;
2993 : forprime_t S;
2994 : pari_timer ti;
2995 :
2996 0 : if (m == 0) return ZM_inv0(M,pden);
2997 0 : if (m == 1 && nbrows(M)==1) return ZM_inv1(M,pden);
2998 0 : if (m == 2 && nbrows(M)==2) return ZM_inv2(M,pden);
2999 :
3000 0 : if (DEBUGLEVEL>5) timer_start(&ti);
3001 0 : init_modular_big(&S);
3002 0 : av2 = avma;
3003 0 : H = NULL;
3004 0 : while ((p = u_forprime_next(&S)))
3005 : {
3006 : GEN Mp, B, Hr;
3007 0 : Mp = ZM_to_Flm(M,p);
3008 0 : Hp = Flm_inv_sp(Mp, NULL, p);
3009 0 : if (!Hp) continue;
3010 0 : if (!H)
3011 : {
3012 0 : H = ZM_init_CRT(Hp, p);
3013 0 : q = utoipos(p);
3014 : }
3015 : else
3016 0 : ZM_incremental_CRT(&H, Hp, &q, p);
3017 0 : B = sqrti(shifti(q,-1));
3018 0 : Hr = FpM_ratlift(H,q,B,B,NULL);
3019 0 : if (DEBUGLEVEL>5)
3020 0 : timer_printf(&ti,"ZM_inv mod %lu (ratlift=%ld)", p,!!Hr);
3021 0 : if (Hr) {/* DONE ? */
3022 0 : GEN Hl = Q_remove_denom(Hr, pden);
3023 0 : if (ZM_isscalar(ZM_mul(Hl, M), *pden)) { H = Hl; break; }
3024 : }
3025 :
3026 0 : if (gc_needed(av,2))
3027 : {
3028 0 : if (DEBUGMEM>1) pari_warn(warnmem,"ZM_inv_ratlift");
3029 0 : gerepileall(av2, 2, &H, &q);
3030 : }
3031 : }
3032 0 : if (!*pden) *pden = gen_1;
3033 0 : return gc_all(av, 2, &H, pden);
3034 : }
3035 :
3036 : GEN
3037 74445 : FpM_ratlift_worker(GEN A, GEN mod, GEN B)
3038 : {
3039 : long l, i;
3040 74445 : GEN H = cgetg_copy(A, &l);
3041 156539 : for (i = 1; i < l; i++)
3042 : {
3043 82098 : GEN c = FpC_ratlift(gel(A,i), mod, B, B, NULL);
3044 82094 : gel(H,i) = c? c: gen_0;
3045 : }
3046 74441 : return H;
3047 : }
3048 : static int
3049 762324 : can_ratlift(GEN x, GEN mod, GEN B)
3050 : {
3051 762324 : pari_sp av = avma;
3052 : GEN a, b;
3053 762324 : return gc_bool(av, Fp_ratlift(x, mod, B, B, &a,&b));
3054 : }
3055 : static GEN
3056 2739266 : FpM_ratlift_parallel(GEN A, GEN mod, GEN B)
3057 : {
3058 2739266 : pari_sp av = avma;
3059 : GEN worker;
3060 2739266 : long i, l = lg(A), m = mt_nbthreads();
3061 2739265 : int test = !!B;
3062 :
3063 2739265 : if (l == 1 || lgcols(A) == 1) return gcopy(A);
3064 2739266 : if (!B) B = sqrti(shifti(mod,-1));
3065 2739211 : if (m == 1 || l == 2 || lgcols(A) < 10)
3066 : {
3067 2731764 : A = FpM_ratlift(A, mod, B, B, NULL);
3068 2731820 : return A? A: gc_NULL(av);
3069 : }
3070 : /* test one coefficient first */
3071 7447 : if (test && !can_ratlift(gcoeff(A,1,1), mod, B)) return gc_NULL(av);
3072 7329 : worker = snm_closure(is_entry("_FpM_ratlift_worker"), mkvec2(mod,B));
3073 7329 : A = gen_parapply_slice(worker, A, m);
3074 81253 : for (i = 1; i < l; i++) if (typ(gel(A,i)) != t_COL) return gc_NULL(av);
3075 6335 : return A;
3076 : }
3077 :
3078 : static GEN
3079 755197 : ZM_adj_ratlift(GEN A, GEN H, GEN mod, GEN T)
3080 : {
3081 755197 : pari_sp av = avma;
3082 : GEN B, D, g;
3083 755197 : D = ZMrow_ZC_mul(H, gel(A,1), 1);
3084 755190 : if (T) D = mulii(T, D);
3085 755190 : g = gcdii(D, mod);
3086 755188 : if (!equali1(g))
3087 : {
3088 14 : mod = diviiexact(mod, g);
3089 14 : H = FpM_red(H, mod);
3090 : }
3091 755188 : D = Fp_inv(Fp_red(D, mod), mod);
3092 : /* test 1 coeff first */
3093 755191 : B = sqrti(shifti(mod,-1));
3094 755191 : if (!can_ratlift(Fp_mul(D, gcoeff(A,1,1), mod), mod, B)) return gc_NULL(av);
3095 734337 : H = FpM_Fp_mul(H, D, mod);
3096 734331 : H = FpM_ratlift_parallel(H, mod, B);
3097 734337 : return H? H: gc_NULL(av);
3098 : }
3099 :
3100 : /* if (T) return T A^(-1) in Mn(Q), else B in Mn(Z) such that A B = den*Id */
3101 : static GEN
3102 2129850 : ZM_inv_i(GEN A, GEN *pden, GEN T)
3103 : {
3104 2129850 : pari_sp av = avma;
3105 2129850 : long m = lg(A)-1, n, k1 = 1, k2;
3106 2129850 : GEN H = NULL, D, H1 = NULL, mod1 = NULL, worker;
3107 : ulong bnd, mask;
3108 : forprime_t S;
3109 : pari_timer ti;
3110 :
3111 2129850 : if (m == 0) return ZM_inv0(A,pden);
3112 2086345 : if (pden) *pden = gen_1;
3113 2086345 : if (nbrows(A) < m) return NULL;
3114 2086336 : if (m == 1 && nbrows(A)==1 && !T) return ZM_inv1(A,pden);
3115 1442197 : if (m == 2 && nbrows(A)==2 && !T) return ZM_inv2(A,pden);
3116 :
3117 717573 : if (DEBUGLEVEL>=5) timer_start(&ti);
3118 717573 : init_modular_big(&S);
3119 717575 : bnd = expi(RgM_true_Hadamard(A));
3120 717574 : worker = snm_closure(is_entry("_ZM_inv_worker"), mkvec(A));
3121 717577 : gen_inccrt("ZM_inv_r", worker, NULL, k1, 0, &S, &H1, &mod1, nmV_chinese_center, FpM_center);
3122 717577 : n = (bnd+1)/expu(S.p)+1;
3123 717577 : if (DEBUGLEVEL>=5) timer_printf(&ti,"inv (%ld/%ld primes)", k1, n);
3124 717577 : mask = quadratic_prec_mask(n);
3125 717577 : for (k2 = 0;;)
3126 65700 : {
3127 : GEN Hr;
3128 783277 : if (k2 > 0)
3129 : {
3130 58410 : gen_inccrt("ZM_inv_r", worker, NULL, k2, 0, &S, &H1, &mod1,nmV_chinese_center,FpM_center);
3131 58410 : k1 += k2;
3132 58410 : if (DEBUGLEVEL>=5) timer_printf(&ti,"CRT (%ld/%ld primes)", k1, n);
3133 : }
3134 783277 : if (mask == 1) break;
3135 755197 : k2 = (mask&1UL) ? k1-1: k1;
3136 755197 : mask >>= 1;
3137 :
3138 755197 : Hr = ZM_adj_ratlift(A, H1, mod1, T);
3139 755195 : if (DEBUGLEVEL>=5) timer_printf(&ti,"ratlift (%ld/%ld primes)", k1, n);
3140 755195 : if (Hr) {/* DONE ? */
3141 693342 : GEN Hl = Q_primpart(Hr), R = ZM_mul(Hl, A), d = gcoeff(R,1,1);
3142 693344 : if (gsigne(d) < 0) { d = gneg(d); Hl = ZM_neg(Hl); }
3143 693344 : if (DEBUGLEVEL>=5) timer_printf(&ti,"mult (%ld/%ld primes)", k1, n);
3144 693344 : if (equali1(d))
3145 : {
3146 595864 : if (ZM_isidentity(R)) { H = Hl; break; }
3147 : }
3148 97480 : else if (ZM_isscalar(R, d))
3149 : {
3150 93634 : if (T) T = gdiv(T,d);
3151 87335 : else if (pden) *pden = d;
3152 93634 : H = Hl; break;
3153 : }
3154 : }
3155 : }
3156 717577 : if (!H)
3157 : {
3158 : GEN d;
3159 28080 : H = H1;
3160 28080 : D = ZMrow_ZC_mul(H, gel(A,1), 1);
3161 28080 : if (signe(D)==0) pari_err_INV("ZM_inv", A);
3162 28080 : if (T) T = gdiv(T, D);
3163 : else
3164 : {
3165 27034 : d = gcdii(Q_content_safe(H), D);
3166 27034 : if (signe(D) < 0) d = negi(d);
3167 27034 : if (!equali1(d))
3168 : {
3169 15342 : H = ZM_Z_divexact(H, d);
3170 15342 : D = diviiexact(D, d);
3171 : }
3172 27034 : if (pden) *pden = D;
3173 : }
3174 : }
3175 717577 : if (T && !isint1(T)) H = ZM_Q_mul(H, T);
3176 717577 : return gc_all(av, pden? 2: 1, &H, pden);
3177 : }
3178 : GEN
3179 2065567 : ZM_inv(GEN A, GEN *pden) { return ZM_inv_i(A, pden, NULL); }
3180 :
3181 : /* same as above, M rational */
3182 : GEN
3183 64283 : QM_inv(GEN M)
3184 : {
3185 64283 : pari_sp av = avma;
3186 : GEN den, dM, K;
3187 64283 : M = Q_remove_denom(M, &dM);
3188 64283 : K = ZM_inv_i(M, &den, dM);
3189 64283 : if (!K) return gc_NULL(av);
3190 64262 : if (den && !equali1(den)) K = ZM_Q_mul(K, ginv(den));
3191 64248 : return gerepileupto(av, K);
3192 : }
3193 :
3194 : static GEN
3195 105226 : ZM_ker_filter(GEN A, GEN P)
3196 : {
3197 105226 : long i, j, l = lg(A), n = 1, d = lg(gmael(A,1,1));
3198 105226 : GEN B, Q, D = gmael(A,1,2);
3199 215193 : for (i=2; i<l; i++)
3200 : {
3201 109967 : GEN Di = gmael(A,i,2);
3202 109967 : long di = lg(gmael(A,i,1));
3203 109967 : int c = vecsmall_lexcmp(D, Di);
3204 109967 : if (di==d && c==0) n++;
3205 45588 : else if (d > di || (di==d && c>0))
3206 37680 : { n = 1; d = di; D = Di; }
3207 : }
3208 105226 : B = cgetg(n+1, t_VEC);
3209 105226 : Q = cgetg(n+1, typ(P));
3210 320418 : for (i=1, j=1; i<l; i++)
3211 : {
3212 215192 : if (lg(gmael(A,i,1))==d && vecsmall_lexcmp(D, gmael(A,i,2))==0)
3213 : {
3214 169605 : gel(B,j) = gmael(A,i,1);
3215 169605 : Q[j] = P[i];
3216 169605 : j++;
3217 : }
3218 : }
3219 105226 : return mkvec3(B,Q,D);
3220 : }
3221 :
3222 : static GEN
3223 69559 : ZM_ker_chinese(GEN A, GEN P, GEN *mod)
3224 : {
3225 69559 : GEN BQD = ZM_ker_filter(A, P);
3226 69559 : return mkvec2(nmV_chinese_center(gel(BQD,1), gel(BQD,2), mod), gel(BQD,3));
3227 : }
3228 :
3229 : static GEN
3230 131838 : ZM_ker_slice(GEN A, GEN P, GEN *mod)
3231 : {
3232 131838 : pari_sp av = avma;
3233 131838 : long i, n = lg(P)-1;
3234 : GEN BQD, B, Q, D, H, HD, T;
3235 131838 : if (n == 1)
3236 : {
3237 96171 : ulong p = uel(P,1);
3238 96171 : GEN K = Flm_ker_sp(ZM_to_Flm(A, p), p, 2);
3239 96171 : *mod = utoipos(p); return mkvec2(Flm_to_ZM(gel(K,1)), gel(K,2));
3240 : }
3241 35667 : T = ZV_producttree(P);
3242 35667 : A = ZM_nv_mod_tree(A, P, T);
3243 35667 : H = cgetg(n+1, t_VEC);
3244 111506 : for(i=1 ; i <= n; i++)
3245 75839 : gel(H,i) = Flm_ker_sp(gel(A, i), P[i], 2);
3246 35667 : BQD = ZM_ker_filter(H, P);
3247 35667 : B = gel(BQD,1); Q = gel(BQD,2); D = gel(BQD, 3);
3248 35667 : if (lg(Q) != lg(P)) T = ZV_producttree(Q);
3249 35667 : H = nmV_chinese_center_tree_seq(B, Q, T, ZV_chinesetree(Q,T));
3250 35667 : *mod = gmael(T, lg(T)-1, 1);
3251 35667 : HD = mkvec2(H, D);
3252 35667 : return gc_all(av, 2, &HD, mod);
3253 : }
3254 :
3255 : GEN
3256 131838 : ZM_ker_worker(GEN P, GEN A)
3257 : {
3258 131838 : GEN V = cgetg(3, t_VEC);
3259 131838 : gel(V,1) = ZM_ker_slice(A, P, &gel(V,2));
3260 131837 : return V;
3261 : }
3262 :
3263 : /* assume lg(A) > 1 */
3264 : static GEN
3265 65103 : ZM_ker_i(GEN A)
3266 : {
3267 : pari_sp av;
3268 65103 : long k, m = lg(A)-1;
3269 65103 : GEN HD = NULL, mod = gen_1, worker;
3270 : forprime_t S;
3271 :
3272 65103 : if (m >= 2*nbrows(A))
3273 : {
3274 3059 : GEN v = ZM_indexrank(A), y = gel(v,2), z = indexcompl(y, m);
3275 : GEN B, A1, A1i, d;
3276 3059 : A = rowpermute(A, gel(v,1)); /* same kernel */
3277 3059 : A1 = vecpermute(A, y); /* maximal rank submatrix */
3278 3059 : B = vecpermute(A, z);
3279 3059 : A1i = ZM_inv(A1, &d);
3280 3059 : if (!d) d = gen_1;
3281 3059 : B = vconcat(ZM_mul(ZM_neg(A1i), B), scalarmat_shallow(d, lg(B)-1));
3282 3059 : if (!gequal(y, identity_perm(lg(y)-1)))
3283 685 : B = rowpermute(B, perm_inv(shallowconcat(y,z)));
3284 3059 : return vec_Q_primpart(B);
3285 : }
3286 62044 : init_modular_big(&S);
3287 62044 : worker = snm_closure(is_entry("_ZM_ker_worker"), mkvec(A));
3288 62044 : av = avma;
3289 62044 : for (k = 1;; k <<= 1)
3290 65346 : {
3291 : pari_timer ti;
3292 : GEN H, Hr;
3293 127390 : gen_inccrt_i("ZM_ker", worker, NULL, (k+1)>>1, 0,
3294 : &S, &HD, &mod, ZM_ker_chinese, NULL);
3295 127390 : gerepileall(av, 2, &HD, &mod);
3296 143017 : H = gel(HD, 1); if (lg(H) == 1) return H;
3297 80973 : if (DEBUGLEVEL >= 4) timer_start(&ti);
3298 80973 : Hr = FpM_ratlift_parallel(H, mod, NULL);
3299 80973 : if (DEBUGLEVEL >= 4) timer_printf(&ti,"ZM_ker: ratlift (%ld)",!!Hr);
3300 80973 : if (Hr)
3301 : {
3302 : GEN MH;
3303 70223 : Hr = vec_Q_primpart(Hr);
3304 70223 : MH = ZM_mul(A, Hr);
3305 70223 : if (DEBUGLEVEL >= 4) timer_printf(&ti,"ZM_ker: QM_mul");
3306 70223 : if (ZM_equal0(MH)) return Hr;
3307 : }
3308 : }
3309 : }
3310 :
3311 : GEN
3312 49269 : ZM_ker(GEN M)
3313 : {
3314 49269 : pari_sp av = avma;
3315 49269 : long l = lg(M)-1;
3316 49269 : if (l==0) return cgetg(1, t_MAT);
3317 49269 : if (lgcols(M)==1) return matid(l);
3318 49269 : return gerepilecopy(av, ZM_ker_i(M));
3319 : }
3320 :
3321 : static GEN
3322 1999237 : ZM_gauss_slice(GEN A, GEN B, GEN P, GEN *mod)
3323 : {
3324 1999237 : pari_sp av = avma;
3325 1999237 : long i, n = lg(P)-1;
3326 : GEN H, T;
3327 1999237 : if (n == 1)
3328 : {
3329 1959683 : ulong p = uel(P,1);
3330 1959683 : GEN Hp = Flm_gauss(ZM_to_Flm(A, p) , ZM_to_Flm(B, p) ,p);
3331 1959687 : if (!Hp) { *mod=gen_1; return zeromat(lg(A)-1,lg(B)-1); }
3332 1959687 : Hp = gerepileupto(av, Flm_to_ZM(Hp));
3333 1959689 : *mod = utoipos(p); return Hp;
3334 : }
3335 39554 : T = ZV_producttree(P);
3336 39554 : A = ZM_nv_mod_tree(A, P, T);
3337 39554 : B = ZM_nv_mod_tree(B, P, T);
3338 39554 : H = cgetg(n+1, t_VEC);
3339 223550 : for(i=1; i <= n; i++)
3340 : {
3341 183996 : GEN Hi = Flm_gauss(gel(A, i), gel(B,i), uel(P,i));
3342 183996 : gel(H,i) = Hi ? Hi: zero_Flm(lg(A)-1,lg(B)-1);
3343 183996 : if (!Hi) uel(P,i)=1;
3344 : }
3345 39554 : H = nmV_chinese_center_tree_seq(H, P, T, ZV_chinesetree(P,T));
3346 39553 : *mod = gmael(T, lg(T)-1, 1); return gc_all(av, 2, &H, mod);
3347 : }
3348 :
3349 : GEN
3350 1999241 : ZM_gauss_worker(GEN P, GEN A, GEN B)
3351 : {
3352 1999241 : GEN V = cgetg(3, t_VEC);
3353 1999237 : gel(V,1) = ZM_gauss_slice(A, B, P, &gel(V,2));
3354 1999241 : return V;
3355 : }
3356 :
3357 : /* assume lg(A) > 1 */
3358 : static GEN
3359 1742325 : ZM_gauss_i(GEN A, GEN B)
3360 : {
3361 : pari_sp av;
3362 : long k, m, ncol;
3363 : int iscol;
3364 1742325 : GEN y, y1, y2, Hr, H = NULL, mod = gen_1, worker;
3365 : forprime_t S;
3366 1742325 : if (!init_gauss(A, &B, &m, &ncol, &iscol)) return cgetg(1, iscol?t_COL:t_MAT);
3367 1742258 : init_modular_big(&S);
3368 1742259 : y = ZM_indexrank(A); y1 = gel(y,1); y2 = gel(y,2);
3369 1742265 : if (lg(y2)-1 != m) return NULL;
3370 1742237 : A = rowpermute(A, y1);
3371 1742235 : B = rowpermute(B, y1);
3372 : /* a is square and invertible */
3373 1742236 : ncol = lg(B);
3374 1742236 : worker = snm_closure(is_entry("_ZM_gauss_worker"), mkvec2(A,B));
3375 1742240 : av = avma;
3376 1742240 : for (k = 1;; k <<= 1)
3377 181731 : {
3378 : pari_timer ti;
3379 1923971 : gen_inccrt_i("ZM_gauss", worker, NULL, (k+1)>>1 , m,
3380 : &S, &H, &mod, nmV_chinese_center, FpM_center);
3381 1923951 : gerepileall(av, 2, &H, &mod);
3382 1923971 : if (DEBUGLEVEL >= 4) timer_start(&ti);
3383 1923971 : Hr = FpM_ratlift_parallel(H, mod, NULL);
3384 1923964 : if (DEBUGLEVEL >= 4) timer_printf(&ti,"ZM_gauss: ratlift (%ld)",!!Hr);
3385 1923967 : if (Hr)
3386 : {
3387 : GEN MH, c;
3388 1787752 : MH = ZM_mul(A, Q_remove_denom(Hr, &c));
3389 1787736 : if (DEBUGLEVEL >= 4) timer_printf(&ti,"ZM_gauss: QM_mul");
3390 1787740 : if (ZM_equal(MH, c ? ZM_Z_mul(B, c): B)) break;
3391 : }
3392 : }
3393 1742228 : return iscol ? gel(Hr, 1): Hr;
3394 : }
3395 :
3396 : GEN
3397 1742326 : ZM_gauss(GEN A, GEN B)
3398 : {
3399 1742326 : pari_sp av = avma;
3400 1742326 : GEN C = ZM_gauss_i(A,B);
3401 1742324 : return C ? gerepilecopy(av, C): NULL;
3402 : }
3403 :
3404 : GEN
3405 16709 : QM_ker(GEN M)
3406 : {
3407 16709 : pari_sp av = avma;
3408 16709 : long l = lg(M)-1;
3409 16709 : if (l==0) return cgetg(1, t_MAT);
3410 16667 : if (lgcols(M)==1) return matid(l);
3411 15750 : return gerepilecopy(av, ZM_ker_i(row_Q_primpart(M)));
3412 : }
3413 :
3414 : /* x a ZM. Return a multiple of the determinant of the lattice generated by
3415 : * the columns of x. From Algorithm 2.2.6 in GTM138 */
3416 : GEN
3417 49964 : detint(GEN A)
3418 : {
3419 49964 : if (typ(A) != t_MAT) pari_err_TYPE("detint",A);
3420 49964 : RgM_check_ZM(A, "detint");
3421 49964 : return ZM_detmult(A);
3422 : }
3423 : GEN
3424 169270 : ZM_detmult(GEN A)
3425 : {
3426 169270 : pari_sp av1, av = avma;
3427 : GEN B, c, v, piv;
3428 169270 : long rg, i, j, k, m, n = lg(A) - 1;
3429 :
3430 169270 : if (!n) return gen_1;
3431 169270 : m = nbrows(A);
3432 169270 : if (n < m) return gen_0;
3433 169193 : c = zero_zv(m);
3434 169193 : av1 = avma;
3435 169193 : B = zeromatcopy(m,m);
3436 169194 : v = cgetg(m+1, t_COL);
3437 169192 : piv = gen_1; rg = 0;
3438 726437 : for (k=1; k<=n; k++)
3439 : {
3440 726423 : GEN pivprec = piv;
3441 726423 : long t = 0;
3442 5363638 : for (i=1; i<=m; i++)
3443 : {
3444 4637223 : pari_sp av2 = avma;
3445 : GEN vi;
3446 4637223 : if (c[i]) continue;
3447 :
3448 2682074 : vi = mulii(piv, gcoeff(A,i,k));
3449 28372025 : for (j=1; j<=m; j++)
3450 25689948 : if (c[j]) vi = addii(vi, mulii(gcoeff(B,j,i),gcoeff(A,j,k)));
3451 2682077 : if (!t && signe(vi)) t = i;
3452 2682077 : gel(v,i) = gerepileuptoint(av2, vi);
3453 : }
3454 726415 : if (!t) continue;
3455 : /* at this point c[t] = 0 */
3456 :
3457 726324 : if (++rg >= m) { /* full rank; mostly done */
3458 169180 : GEN det = gel(v,t); /* last on stack */
3459 169180 : if (++k > n)
3460 169048 : det = absi(det);
3461 : else
3462 : {
3463 : /* improve further; at this point c[i] is set for all i != t */
3464 132 : gcoeff(B,t,t) = piv; v = centermod(gel(B,t), det);
3465 418 : for ( ; k<=n; k++)
3466 286 : det = gcdii(det, ZV_dotproduct(v, gel(A,k)));
3467 : }
3468 169180 : return gerepileuptoint(av, det);
3469 : }
3470 :
3471 557144 : piv = gel(v,t);
3472 4467541 : for (i=1; i<=m; i++)
3473 : {
3474 : GEN mvi;
3475 3910397 : if (c[i] || i == t) continue;
3476 :
3477 1955198 : gcoeff(B,t,i) = mvi = negi(gel(v,i));
3478 23004507 : for (j=1; j<=m; j++)
3479 21049309 : if (c[j]) /* implies j != t */
3480 : {
3481 5712983 : pari_sp av2 = avma;
3482 5712983 : GEN z = addii(mulii(gcoeff(B,j,i), piv), mulii(gcoeff(B,j,t), mvi));
3483 5712983 : if (rg > 1) z = diviiexact(z, pivprec);
3484 5712983 : gcoeff(B,j,i) = gerepileuptoint(av2, z);
3485 : }
3486 : }
3487 557144 : c[t] = k;
3488 557144 : if (gc_needed(av,1))
3489 : {
3490 0 : if(DEBUGMEM>1) pari_warn(warnmem,"detint. k=%ld",k);
3491 0 : gerepileall(av1, 2, &piv,&B); v = zerovec(m);
3492 : }
3493 : }
3494 14 : return gc_const(av, gen_0);
3495 : }
3496 :
3497 : /* Reduce x modulo (invertible) y */
3498 : GEN
3499 14979 : closemodinvertible(GEN x, GEN y)
3500 : {
3501 14979 : return gmul(y, ground(RgM_solve(y,x)));
3502 : }
3503 : GEN
3504 7 : reducemodinvertible(GEN x, GEN y)
3505 : {
3506 7 : return gsub(x, closemodinvertible(x,y));
3507 : }
3508 : GEN
3509 0 : reducemodlll(GEN x,GEN y)
3510 : {
3511 0 : return reducemodinvertible(x, ZM_lll(y, 0.75, LLL_INPLACE));
3512 : }
3513 :
3514 : /*******************************************************************/
3515 : /* */
3516 : /* KERNEL of an m x n matrix */
3517 : /* return n - rk(x) linearly independent vectors */
3518 : /* */
3519 : /*******************************************************************/
3520 : static GEN
3521 28 : RgM_deplin_i(GEN x0)
3522 : {
3523 28 : pari_sp av = avma, av2;
3524 28 : long i, j, k, nl, nc = lg(x0)-1;
3525 : GEN D, x, y, c, l, d, ck;
3526 :
3527 28 : if (!nc) return NULL;
3528 28 : nl = nbrows(x0);
3529 28 : c = zero_zv(nl);
3530 28 : l = cgetg(nc+1, t_VECSMALL); /* not initialized */
3531 28 : av2 = avma;
3532 28 : x = RgM_shallowcopy(x0);
3533 28 : d = const_vec(nl, gen_1); /* pivot list */
3534 28 : ck = NULL; /* gcc -Wall */
3535 98 : for (k=1; k<=nc; k++)
3536 : {
3537 91 : ck = gel(x,k);
3538 196 : for (j=1; j<k; j++)
3539 : {
3540 105 : GEN cj = gel(x,j), piv = gel(d,j), q = gel(ck,l[j]);
3541 420 : for (i=1; i<=nl; i++)
3542 315 : if (i!=l[j]) gel(ck,i) = gsub(gmul(piv, gel(ck,i)), gmul(q, gel(cj,i)));
3543 : }
3544 :
3545 91 : i = gauss_get_pivot_NZ(x, NULL, k, c);
3546 91 : if (i > nl) break;
3547 70 : if (gc_needed(av,1))
3548 : {
3549 0 : if (DEBUGMEM>1) pari_warn(warnmem,"deplin k = %ld/%ld",k,nc);
3550 0 : gerepileall(av2, 2, &x, &d);
3551 0 : ck = gel(x,k);
3552 : }
3553 70 : gel(d,k) = gel(ck,i);
3554 70 : c[i] = k; l[k] = i; /* pivot d[k] in x[i,k] */
3555 : }
3556 28 : if (k > nc) return gc_NULL(av);
3557 21 : if (k == 1) { set_avma(av); return scalarcol_shallow(gen_1,nc); }
3558 21 : y = cgetg(nc+1,t_COL);
3559 21 : gel(y,1) = gcopy(gel(ck, l[1]));
3560 49 : for (D=gel(d,1),j=2; j<k; j++)
3561 : {
3562 28 : gel(y,j) = gmul(gel(ck, l[j]), D);
3563 28 : D = gmul(D, gel(d,j));
3564 : }
3565 21 : gel(y,j) = gneg(D);
3566 21 : for (j++; j<=nc; j++) gel(y,j) = gen_0;
3567 21 : y = primitive_part(y, &c);
3568 21 : return c? gerepileupto(av, y): gerepilecopy(av, y);
3569 : }
3570 : static GEN
3571 0 : RgV_deplin(GEN v)
3572 : {
3573 0 : pari_sp av = avma;
3574 0 : long n = lg(v)-1;
3575 0 : GEN y, p = NULL;
3576 0 : if (n <= 1)
3577 : {
3578 0 : if (n == 1 && gequal0(gel(v,1))) return mkcol(gen_1);
3579 0 : return cgetg(1, t_COL);
3580 : }
3581 0 : if (gequal0(gel(v,1))) return scalarcol_shallow(gen_1, n);
3582 0 : v = primpart(mkvec2(gel(v,1),gel(v,2)));
3583 0 : if (RgV_is_FpV(v, &p) && p) v = centerlift(v);
3584 0 : y = zerocol(n);
3585 0 : gel(y,1) = gneg(gel(v,2));
3586 0 : gel(y,2) = gcopy(gel(v,1));
3587 0 : return gerepileupto(av, y);
3588 :
3589 : }
3590 :
3591 : static GEN
3592 105 : RgM_deplin_FpM(GEN x, GEN p)
3593 : {
3594 105 : pari_sp av = avma;
3595 : ulong pp;
3596 105 : x = RgM_Fp_init3(x, p, &pp);
3597 105 : switch(pp)
3598 : {
3599 35 : case 0:
3600 35 : x = FpM_ker_gen(x,p,1);
3601 35 : if (!x) return gc_NULL(av);
3602 21 : x = FpC_center(x,p,shifti(p,-1));
3603 21 : break;
3604 14 : case 2:
3605 14 : x = F2m_ker_sp(x,1);
3606 14 : if (!x) return gc_NULL(av);
3607 7 : x = F2c_to_ZC(x); break;
3608 0 : case 3:
3609 0 : x = F3m_ker_sp(x,1);
3610 0 : if (!x) return gc_NULL(av);
3611 0 : x = F3c_to_ZC(x); break;
3612 56 : default:
3613 56 : x = Flm_ker_sp(x,pp,1);
3614 56 : if (!x) return gc_NULL(av);
3615 35 : x = Flv_center(x, pp, pp>>1);
3616 35 : x = zc_to_ZC(x);
3617 35 : break;
3618 : }
3619 63 : return gerepileupto(av, x);
3620 : }
3621 :
3622 : /* FIXME: implement direct modular ZM_deplin ? */
3623 : static GEN
3624 119 : QM_deplin(GEN M)
3625 : {
3626 119 : pari_sp av = avma;
3627 119 : long l = lg(M)-1;
3628 : GEN k;
3629 119 : if (l==0) return NULL;
3630 84 : if (lgcols(M)==1) return col_ei(l, 1);
3631 84 : k = ZM_ker_i(row_Q_primpart(M));
3632 84 : if (lg(k)== 1) return gc_NULL(av);
3633 70 : return gerepilecopy(av, gel(k,1));
3634 : }
3635 :
3636 : static GEN
3637 49 : RgM_deplin_FqM(GEN x, GEN pol, GEN p)
3638 : {
3639 49 : pari_sp av = avma;
3640 49 : GEN b, T = RgX_to_FpX(pol, p);
3641 49 : if (signe(T) == 0) pari_err_OP("deplin",x,pol);
3642 49 : b = FqM_deplin(RgM_to_FqM(x, T, p), T, p);
3643 49 : if (!b) return gc_NULL(av);
3644 35 : return gerepileupto(av, b);
3645 : }
3646 :
3647 : #define code(t1,t2) ((t1 << 6) | t2)
3648 : static GEN
3649 385 : RgM_deplin_fast(GEN x)
3650 : {
3651 : GEN p, pol;
3652 : long pa;
3653 385 : long t = RgM_type(x, &p,&pol,&pa);
3654 385 : switch(t)
3655 : {
3656 119 : case t_INT: /* fall through */
3657 119 : case t_FRAC: return QM_deplin(x);
3658 84 : case t_FFELT: return FFM_deplin(x, pol);
3659 105 : case t_INTMOD: return RgM_deplin_FpM(x, p);
3660 49 : case code(t_POLMOD, t_INTMOD):
3661 49 : return RgM_deplin_FqM(x, pol, p);
3662 28 : default: return gen_0;
3663 : }
3664 : }
3665 : #undef code
3666 :
3667 : static GEN
3668 385 : RgM_deplin(GEN x)
3669 : {
3670 385 : GEN z = RgM_deplin_fast(x);
3671 385 : if (z!= gen_0) return z;
3672 28 : return RgM_deplin_i(x);
3673 : }
3674 :
3675 : GEN
3676 385 : deplin(GEN x)
3677 : {
3678 385 : switch(typ(x))
3679 : {
3680 385 : case t_MAT:
3681 : {
3682 385 : GEN z = RgM_deplin(x);
3683 385 : if (z) return z;
3684 147 : return cgetg(1, t_COL);
3685 : }
3686 0 : case t_VEC: return RgV_deplin(x);
3687 0 : default: pari_err_TYPE("deplin",x);
3688 : }
3689 : return NULL;/*LCOV_EXCL_LINE*/
3690 : }
3691 :
3692 : /*******************************************************************/
3693 : /* */
3694 : /* GAUSS REDUCTION OF MATRICES (m lines x n cols) */
3695 : /* (kernel, image, complementary image, rank) */
3696 : /* */
3697 : /*******************************************************************/
3698 : /* return the transform of x under a standard Gauss pivot.
3699 : * x0 is a reference point when guessing whether x[i,j] ~ 0
3700 : * (iff x[i,j] << x0[i,j])
3701 : * Set r = dim ker(x). d[k] contains the index of the first nonzero pivot
3702 : * in column k */
3703 : static GEN
3704 1271 : gauss_pivot_ker(GEN x, GEN x0, GEN *dd, long *rr)
3705 : {
3706 : GEN c, d, p, data;
3707 : pari_sp av;
3708 : long i, j, k, r, t, n, m;
3709 : pivot_fun pivot;
3710 :
3711 1271 : n=lg(x)-1; if (!n) { *dd=NULL; *rr=0; return cgetg(1,t_MAT); }
3712 1271 : m=nbrows(x); r=0;
3713 1271 : pivot = get_pivot_fun(x, x0, &data);
3714 1271 : x = RgM_shallowcopy(x);
3715 1271 : c = zero_zv(m);
3716 1271 : d = cgetg(n+1,t_VECSMALL);
3717 1271 : av=avma;
3718 7475 : for (k=1; k<=n; k++)
3719 : {
3720 6204 : j = pivot(x, data, k, c);
3721 6204 : if (j > m)
3722 : {
3723 1463 : r++; d[k]=0;
3724 6496 : for(j=1; j<k; j++)
3725 5033 : if (d[j]) gcoeff(x,d[j],k) = gclone(gcoeff(x,d[j],k));
3726 : }
3727 : else
3728 : { /* pivot for column k on row j */
3729 4741 : c[j]=k; d[k]=j; p = gdiv(gen_m1,gcoeff(x,j,k));
3730 4741 : gcoeff(x,j,k) = gen_m1;
3731 : /* x[j,] /= - x[j,k] */
3732 24169 : for (i=k+1; i<=n; i++) gcoeff(x,j,i) = gmul(p,gcoeff(x,j,i));
3733 42136 : for (t=1; t<=m; t++)
3734 37395 : if (t!=j)
3735 : { /* x[t,] -= 1 / x[j,k] x[j,] */
3736 32654 : p = gcoeff(x,t,k); gcoeff(x,t,k) = gen_0;
3737 32654 : if (gequal0(p)) continue;
3738 86920 : for (i=k+1; i<=n; i++)
3739 69463 : gcoeff(x,t,i) = gadd(gcoeff(x,t,i),gmul(p,gcoeff(x,j,i)));
3740 17457 : if (gc_needed(av,1)) gerepile_gauss_ker(x,k,t,av);
3741 : }
3742 : }
3743 : }
3744 1271 : *dd=d; *rr=r; return x;
3745 : }
3746 :
3747 : /* r = dim ker(x).
3748 : * Returns d:
3749 : * d[k] != 0 contains the index of a nonzero pivot in column k
3750 : * d[k] == 0 if column k is a linear combination of the (k-1) first ones */
3751 : GEN
3752 167478 : RgM_pivots(GEN x0, GEN data, long *rr, pivot_fun pivot)
3753 : {
3754 : GEN x, c, d, p;
3755 167478 : long i, j, k, r, t, m, n = lg(x0)-1;
3756 : pari_sp av;
3757 :
3758 167478 : if (RgM_is_ZM(x0)) return ZM_pivots(x0, rr);
3759 152080 : if (!n) { *rr = 0; return NULL; }
3760 :
3761 152080 : d = cgetg(n+1, t_VECSMALL);
3762 152080 : x = RgM_shallowcopy(x0);
3763 152080 : m = nbrows(x); r = 0;
3764 152080 : c = zero_zv(m);
3765 152092 : av = avma;
3766 926023 : for (k=1; k<=n; k++)
3767 : {
3768 773947 : j = pivot(x, data, k, c);
3769 773953 : if (j > m) { r++; d[k] = 0; }
3770 : else
3771 : {
3772 291180 : c[j] = k; d[k] = j; p = gdiv(gen_m1, gcoeff(x,j,k));
3773 1881057 : for (i=k+1; i<=n; i++) gcoeff(x,j,i) = gmul(p,gcoeff(x,j,i));
3774 :
3775 1053257 : for (t=1; t<=m; t++)
3776 762099 : if (!c[t]) /* no pivot on that line yet */
3777 : {
3778 256987 : p = gcoeff(x,t,k); gcoeff(x,t,k) = gen_0;
3779 4130351 : for (i=k+1; i<=n; i++)
3780 3873369 : gcoeff(x,t,i) = gadd(gcoeff(x,t,i), gmul(p, gcoeff(x,j,i)));
3781 256982 : if (gc_needed(av,1)) gerepile_gauss(x,k,t,av,j,c);
3782 : }
3783 2172279 : for (i=k; i<=n; i++) gcoeff(x,j,i) = gen_0; /* dummy */
3784 : }
3785 : }
3786 152076 : *rr = r; return gc_const((pari_sp)d, d);
3787 : }
3788 :
3789 : static long
3790 4244763 : ZM_count_0_cols(GEN M)
3791 : {
3792 4244763 : long i, l = lg(M), n = 0;
3793 18207896 : for (i = 1; i < l; i++)
3794 13963140 : if (ZV_equal0(gel(M,i))) n++;
3795 4244756 : return n;
3796 : }
3797 :
3798 : static void indexrank_all(long m, long n, long r, GEN d, GEN *prow, GEN *pcol);
3799 : /* As RgM_pivots, integer entries. Set *rr = dim Ker M0 */
3800 : GEN
3801 4258349 : ZM_pivots(GEN M0, long *rr)
3802 : {
3803 4258349 : GEN d, dbest = NULL;
3804 : long m, mm, n, nn, i, imax, rmin, rbest, zc;
3805 4258349 : int beenthere = 0;
3806 4258349 : pari_sp av, av0 = avma;
3807 : forprime_t S;
3808 :
3809 4258349 : rbest = n = lg(M0)-1;
3810 4258349 : if (n == 0) { *rr = 0; return NULL; }
3811 4244764 : zc = ZM_count_0_cols(M0);
3812 4244744 : if (n == zc) { *rr = zc; return zero_zv(n); }
3813 :
3814 4244616 : m = nbrows(M0);
3815 4244613 : rmin = maxss(zc, n-m);
3816 4244609 : init_modular_small(&S);
3817 4244651 : if (n <= m) { nn = n; mm = m; } else { nn = m; mm = n; }
3818 4244651 : imax = (nn < 16)? 1: (nn < 64)? 2: 3; /* heuristic */
3819 :
3820 : for(;;)
3821 0 : {
3822 : GEN row, col, M, KM, IM, RHS, X, cX;
3823 : long rk;
3824 4267813 : for (av = avma, i = 0;; set_avma(av), i++)
3825 23167 : {
3826 4267813 : ulong p = u_forprime_next(&S);
3827 : long rp;
3828 4267806 : if (!p) pari_err_OVERFLOW("ZM_pivots [ran out of primes]");
3829 4267806 : d = Flm_pivots(ZM_to_Flm(M0, p), p, &rp, 1);
3830 4267801 : if (rp == rmin) { rbest = rp; goto END; } /* maximal rank, return */
3831 44947 : if (rp < rbest) { /* save best r so far */
3832 21805 : rbest = rp;
3833 21805 : guncloneNULL(dbest);
3834 21805 : dbest = gclone(d);
3835 21805 : if (beenthere) break;
3836 : }
3837 44947 : if (!beenthere && i >= imax) break;
3838 : }
3839 21780 : beenthere = 1;
3840 : /* Dubious case: there is (probably) a non trivial kernel */
3841 21780 : indexrank_all(m,n, rbest, dbest, &row, &col);
3842 21780 : M = rowpermute(vecpermute(M0, col), row);
3843 21780 : rk = n - rbest; /* (probable) dimension of image */
3844 21780 : if (n > m) M = shallowtrans(M);
3845 21780 : IM = vecslice(M,1,rk);
3846 21780 : KM = vecslice(M,rk+1, nn);
3847 21780 : M = rowslice(IM, 1,rk); /* square maximal rank */
3848 21780 : X = ZM_gauss(M, rowslice(KM, 1,rk));
3849 21780 : RHS = rowslice(KM,rk+1,mm);
3850 21780 : M = rowslice(IM,rk+1,mm);
3851 21780 : X = Q_remove_denom(X, &cX);
3852 21780 : if (cX) RHS = ZM_Z_mul(RHS, cX);
3853 21780 : if (ZM_equal(ZM_mul(M, X), RHS)) { d = vecsmall_copy(dbest); goto END; }
3854 0 : set_avma(av);
3855 : }
3856 4244634 : END:
3857 4244634 : *rr = rbest; guncloneNULL(dbest);
3858 4244633 : return gerepileuptoleaf(av0, d);
3859 : }
3860 :
3861 : /* set *pr = dim Ker x */
3862 : static GEN
3863 75890 : gauss_pivot(GEN x, long *pr) {
3864 : GEN data;
3865 75890 : pivot_fun pivot = get_pivot_fun(x, x, &data);
3866 75890 : return RgM_pivots(x, data, pr, pivot);
3867 : }
3868 :
3869 : /* compute ker(x), x0 is a reference point when guessing whether x[i,j] ~ 0
3870 : * (iff x[i,j] << x0[i,j]) */
3871 : static GEN
3872 1271 : ker_aux(GEN x, GEN x0)
3873 : {
3874 1271 : pari_sp av = avma;
3875 : GEN d,y;
3876 : long i,j,k,r,n;
3877 :
3878 1271 : x = gauss_pivot_ker(x,x0,&d,&r);
3879 1271 : if (!r) { set_avma(av); return cgetg(1,t_MAT); }
3880 1211 : n = lg(x)-1; y=cgetg(r+1,t_MAT);
3881 2674 : for (j=k=1; j<=r; j++,k++)
3882 : {
3883 1463 : GEN p = cgetg(n+1,t_COL);
3884 :
3885 5586 : gel(y,j) = p; while (d[k]) k++;
3886 6496 : for (i=1; i<k; i++)
3887 5033 : if (d[i])
3888 : {
3889 4641 : GEN p1=gcoeff(x,d[i],k);
3890 4641 : gel(p,i) = gcopy(p1); gunclone(p1);
3891 : }
3892 : else
3893 392 : gel(p,i) = gen_0;
3894 2541 : gel(p,k) = gen_1; for (i=k+1; i<=n; i++) gel(p,i) = gen_0;
3895 : }
3896 1211 : return gerepileupto(av,y);
3897 : }
3898 :
3899 : static GEN
3900 539 : RgM_ker_FpM(GEN x, GEN p)
3901 : {
3902 539 : pari_sp av = avma;
3903 : ulong pp;
3904 539 : x = RgM_Fp_init3(x, p, &pp);
3905 539 : switch(pp)
3906 : {
3907 35 : case 0: x = FpM_to_mod(FpM_ker_gen(x,p,0),p); break;
3908 7 : case 2: x = F2m_to_mod(F2m_ker_sp(x,0)); break;
3909 77 : case 3: x = F3m_to_mod(F3m_ker_sp(x,0)); break;
3910 420 : default:x = Flm_to_mod(Flm_ker_sp(x,pp,0), pp); break;
3911 : }
3912 539 : return gerepileupto(av, x);
3913 : }
3914 :
3915 : static GEN
3916 91 : RgM_ker_FqM(GEN x, GEN pol, GEN p)
3917 : {
3918 91 : pari_sp av = avma;
3919 91 : GEN b, T = RgX_to_FpX(pol, p);
3920 91 : if (signe(T) == 0) pari_err_OP("ker",x,pol);
3921 84 : b = FqM_ker(RgM_to_FqM(x, T, p), T, p);
3922 84 : return gerepileupto(av, FqM_to_mod(b, T, p));
3923 : }
3924 :
3925 : #define code(t1,t2) ((t1 << 6) | t2)
3926 : static GEN
3927 9198 : RgM_ker_fast(GEN x)
3928 : {
3929 : GEN p, pol;
3930 : long pa;
3931 9198 : long t = RgM_type(x, &p,&pol,&pa);
3932 9198 : switch(t)
3933 : {
3934 7609 : case t_INT: /* fall through */
3935 7609 : case t_FRAC: return QM_ker(x);
3936 77 : case t_FFELT: return FFM_ker(x, pol);
3937 539 : case t_INTMOD: return RgM_ker_FpM(x, p);
3938 91 : case code(t_POLMOD, t_INTMOD):
3939 91 : return RgM_ker_FqM(x, pol, p);
3940 882 : default: return NULL;
3941 : }
3942 : }
3943 : #undef code
3944 :
3945 : GEN
3946 9198 : ker(GEN x)
3947 : {
3948 9198 : GEN b = RgM_ker_fast(x);
3949 9191 : if (b) return b;
3950 882 : return ker_aux(x,x);
3951 : }
3952 :
3953 : GEN
3954 46221 : matker0(GEN x,long flag)
3955 : {
3956 46221 : if (typ(x)!=t_MAT) pari_err_TYPE("matker",x);
3957 46221 : if (!flag) return ker(x);
3958 45934 : RgM_check_ZM(x, "matker");
3959 45934 : return ZM_ker(x);
3960 : }
3961 :
3962 : static GEN
3963 525 : RgM_image_FpM(GEN x, GEN p)
3964 : {
3965 525 : pari_sp av = avma;
3966 : ulong pp;
3967 525 : x = RgM_Fp_init(x, p, &pp);
3968 525 : switch(pp)
3969 : {
3970 28 : case 0: x = FpM_to_mod(FpM_image(x,p),p); break;
3971 7 : case 2: x = F2m_to_mod(F2m_image(x)); break;
3972 490 : default:x = Flm_to_mod(Flm_image(x,pp), pp); break;
3973 : }
3974 525 : return gerepileupto(av, x);
3975 : }
3976 :
3977 : static GEN
3978 35 : RgM_image_FqM(GEN x, GEN pol, GEN p)
3979 : {
3980 35 : pari_sp av = avma;
3981 35 : GEN b, T = RgX_to_FpX(pol, p);
3982 35 : if (signe(T) == 0) pari_err_OP("image",x,pol);
3983 28 : b = FqM_image(RgM_to_FqM(x, T, p), T, p);
3984 28 : return gerepileupto(av, FqM_to_mod(b, T, p));
3985 : }
3986 :
3987 : GEN
3988 6181 : QM_image_shallow(GEN A)
3989 : {
3990 6181 : A = vec_Q_primpart(A);
3991 6181 : return vecpermute(A, ZM_indeximage(A));
3992 : }
3993 : GEN
3994 5411 : QM_image(GEN A)
3995 : {
3996 5411 : pari_sp av = avma;
3997 5411 : return gerepilecopy(av, QM_image_shallow(A));
3998 : }
3999 :
4000 : #define code(t1,t2) ((t1 << 6) | t2)
4001 : static GEN
4002 6034 : RgM_image_fast(GEN x)
4003 : {
4004 : GEN p, pol;
4005 : long pa;
4006 6034 : long t = RgM_type(x, &p,&pol,&pa);
4007 6034 : switch(t)
4008 : {
4009 5411 : case t_INT: /* fall through */
4010 5411 : case t_FRAC: return QM_image(x);
4011 49 : case t_FFELT: return FFM_image(x, pol);
4012 525 : case t_INTMOD: return RgM_image_FpM(x, p);
4013 35 : case code(t_POLMOD, t_INTMOD):
4014 35 : return RgM_image_FqM(x, pol, p);
4015 14 : default: return NULL;
4016 : }
4017 : }
4018 : #undef code
4019 :
4020 : GEN
4021 6034 : image(GEN x)
4022 : {
4023 : GEN d, M;
4024 : long r;
4025 :
4026 6034 : if (typ(x)!=t_MAT) pari_err_TYPE("matimage",x);
4027 6034 : M = RgM_image_fast(x);
4028 6027 : if (M) return M;
4029 14 : d = gauss_pivot(x,&r); /* d left on stack for efficiency */
4030 14 : return image_from_pivot(x,d,r);
4031 : }
4032 :
4033 : static GEN
4034 84 : imagecompl_aux(GEN x, GEN(*PIVOT)(GEN,long*))
4035 : {
4036 84 : pari_sp av = avma;
4037 : GEN d,y;
4038 : long j,i,r;
4039 :
4040 84 : if (typ(x)!=t_MAT) pari_err_TYPE("imagecompl",x);
4041 84 : (void)new_chunk(lg(x) * 4 + 1); /* HACK */
4042 84 : d = PIVOT(x,&r); /* if (!d) then r = 0 */
4043 84 : set_avma(av); y = cgetg(r+1,t_VECSMALL);
4044 126 : for (i=j=1; j<=r; i++)
4045 42 : if (!d[i]) y[j++] = i;
4046 84 : return y;
4047 : }
4048 : GEN
4049 84 : imagecompl(GEN x) { return imagecompl_aux(x, &gauss_pivot); }
4050 : GEN
4051 0 : ZM_imagecompl(GEN x) { return imagecompl_aux(x, &ZM_pivots); }
4052 :
4053 : static GEN
4054 28 : RgM_RgC_invimage_FpC(GEN A, GEN y, GEN p)
4055 : {
4056 28 : pari_sp av = avma;
4057 : ulong pp;
4058 : GEN x;
4059 28 : A = RgM_Fp_init(A,p,&pp);
4060 28 : switch(pp)
4061 : {
4062 7 : case 0:
4063 7 : y = RgC_to_FpC(y,p);
4064 7 : x = FpM_FpC_invimage(A, y, p);
4065 7 : return x ? gerepileupto(av, FpC_to_mod(x,p)): NULL;
4066 7 : case 2:
4067 7 : y = RgV_to_F2v(y);
4068 7 : x = F2m_F2c_invimage(A, y);
4069 7 : return x ? gerepileupto(av, F2c_to_mod(x)): NULL;
4070 14 : default:
4071 14 : y = RgV_to_Flv(y,pp);
4072 14 : x = Flm_Flc_invimage(A, y, pp);
4073 14 : return x ? gerepileupto(av, Flc_to_mod(x,pp)): NULL;
4074 : }
4075 : }
4076 :
4077 : static GEN
4078 2184 : RgM_RgC_invimage_fast(GEN x, GEN y)
4079 : {
4080 : GEN p, pol;
4081 : long pa;
4082 2184 : long t = RgM_RgC_type(x, y, &p,&pol,&pa);
4083 2184 : switch(t)
4084 : {
4085 28 : case t_INTMOD: return RgM_RgC_invimage_FpC(x, y, p);
4086 63 : case t_FFELT: return FFM_FFC_invimage(x, y, pol);
4087 2093 : default: return gen_0;
4088 : }
4089 : }
4090 :
4091 : GEN
4092 2289 : RgM_RgC_invimage(GEN A, GEN y)
4093 : {
4094 2289 : pari_sp av = avma;
4095 2289 : long i, l = lg(A);
4096 : GEN M, x, t;
4097 2289 : if (l==1) return NULL;
4098 2184 : if (lg(y) != lgcols(A)) pari_err_DIM("inverseimage");
4099 2184 : M = RgM_RgC_invimage_fast(A, y);
4100 2184 : if (!M) return gc_NULL(av);
4101 2163 : if (M != gen_0) return M;
4102 2093 : M = ker(shallowconcat(A, y));
4103 2093 : i = lg(M)-1;
4104 2093 : if (!i) return gc_NULL(av);
4105 :
4106 1834 : x = gel(M,i); t = gel(x,l);
4107 1834 : if (gequal0(t)) return gc_NULL(av);
4108 :
4109 1799 : t = gneg_i(t); setlg(x,l);
4110 1799 : return gerepileupto(av, RgC_Rg_div(x, t));
4111 : }
4112 :
4113 : /* Return X such that m X = v (t_COL or t_MAT), resp. an empty t_COL / t_MAT
4114 : * if no solution exist */
4115 : GEN
4116 2450 : inverseimage(GEN m, GEN v)
4117 : {
4118 : GEN y;
4119 2450 : if (typ(m)!=t_MAT) pari_err_TYPE("inverseimage",m);
4120 2450 : switch(typ(v))
4121 : {
4122 2212 : case t_COL:
4123 2212 : y = RgM_RgC_invimage(m,v);
4124 2212 : return y? y: cgetg(1,t_COL);
4125 238 : case t_MAT:
4126 238 : y = RgM_invimage(m, v);
4127 238 : return y? y: cgetg(1,t_MAT);
4128 : }
4129 0 : pari_err_TYPE("inverseimage",v);
4130 : return NULL;/*LCOV_EXCL_LINE*/
4131 : }
4132 :
4133 : static GEN
4134 84 : RgM_invimage_FpM(GEN A, GEN B, GEN p)
4135 : {
4136 84 : pari_sp av = avma;
4137 : ulong pp;
4138 : GEN x;
4139 84 : A = RgM_Fp_init(A,p,&pp);
4140 84 : switch(pp)
4141 : {
4142 35 : case 0:
4143 35 : B = RgM_to_FpM(B,p);
4144 35 : x = FpM_invimage_gen(A, B, p);
4145 35 : return x ? gerepileupto(av, FpM_to_mod(x, p)): x;
4146 7 : case 2:
4147 7 : B = RgM_to_F2m(B);
4148 7 : x = F2m_invimage_i(A, B);
4149 7 : return x ? gerepileupto(av, F2m_to_mod(x)): x;
4150 42 : default:
4151 42 : B = RgM_to_Flm(B,pp);
4152 42 : x = Flm_invimage_i(A, B, pp);
4153 42 : return x ? gerepileupto(av, Flm_to_mod(x, pp)): x;
4154 : }
4155 : }
4156 :
4157 : static GEN
4158 364 : RgM_invimage_fast(GEN x, GEN y)
4159 : {
4160 : GEN p, pol;
4161 : long pa;
4162 364 : long t = RgM_type2(x, y, &p,&pol,&pa);
4163 364 : switch(t)
4164 : {
4165 84 : case t_INTMOD: return RgM_invimage_FpM(x, y, p);
4166 105 : case t_FFELT: return FFM_invimage(x, y, pol);
4167 175 : default: return gen_0;
4168 : }
4169 : }
4170 :
4171 : /* find Z such that A Z = B. Return NULL if no solution */
4172 : GEN
4173 364 : RgM_invimage(GEN A, GEN B)
4174 : {
4175 364 : pari_sp av = avma;
4176 : GEN d, x, X, Y;
4177 364 : long i, j, nY, nA = lg(A)-1, nB = lg(B)-1;
4178 364 : X = RgM_invimage_fast(A, B);
4179 364 : if (!X) return gc_NULL(av);
4180 252 : if (X != gen_0) return X;
4181 175 : x = ker(shallowconcat(RgM_neg(A), B));
4182 : /* AX = BY, Y in strict upper echelon form with pivots = 1.
4183 : * We must find T such that Y T = Id_nB then X T = Z. This exists iff
4184 : * Y has at least nB columns and full rank */
4185 175 : nY = lg(x)-1;
4186 175 : if (nY < nB) return gc_NULL(av);
4187 161 : Y = rowslice(x, nA+1, nA+nB); /* nB rows */
4188 161 : d = cgetg(nB+1, t_VECSMALL);
4189 721 : for (i = nB, j = nY; i >= 1; i--, j--)
4190 : {
4191 805 : for (; j>=1; j--)
4192 756 : if (!gequal0(gcoeff(Y,i,j))) { d[i] = j; break; }
4193 609 : if (!j) return gc_NULL(av);
4194 : }
4195 : /* reduce to the case Y square, upper triangular with 1s on diagonal */
4196 112 : Y = vecpermute(Y, d);
4197 112 : x = vecpermute(x, d);
4198 112 : X = rowslice(x, 1, nA);
4199 112 : return gerepileupto(av, RgM_mul(X, RgM_inv_upper(Y)));
4200 : }
4201 :
4202 : static GEN
4203 70 : RgM_suppl_FpM(GEN x, GEN p)
4204 : {
4205 70 : pari_sp av = avma;
4206 : ulong pp;
4207 70 : x = RgM_Fp_init(x, p, &pp);
4208 70 : switch(pp)
4209 : {
4210 21 : case 0: x = FpM_to_mod(FpM_suppl(x,p), p); break;
4211 14 : case 2: x = F2m_to_mod(F2m_suppl(x)); break;
4212 35 : default:x = Flm_to_mod(Flm_suppl(x,pp), pp); break;
4213 : }
4214 70 : return gerepileupto(av, x);
4215 : }
4216 :
4217 : static GEN
4218 175 : RgM_suppl_fast(GEN x)
4219 : {
4220 : GEN p, pol;
4221 : long pa;
4222 175 : long t = RgM_type(x,&p,&pol,&pa);
4223 175 : switch(t)
4224 : {
4225 70 : case t_INTMOD: return RgM_suppl_FpM(x, p);
4226 35 : case t_FFELT: return FFM_suppl(x, pol);
4227 70 : default: return NULL;
4228 : }
4229 : }
4230 :
4231 : /* x is an n x k matrix, rank(x) = k <= n. Return an invertible n x n matrix
4232 : * whose first k columns are given by x. If rank(x) < k, undefined result. */
4233 : GEN
4234 175 : suppl(GEN x)
4235 : {
4236 175 : pari_sp av = avma;
4237 : GEN d, M;
4238 : long r;
4239 175 : if (typ(x)!=t_MAT) pari_err_TYPE("suppl",x);
4240 175 : M = RgM_suppl_fast(x);
4241 175 : if (M) return M;
4242 70 : init_suppl(x);
4243 70 : d = gauss_pivot(x,&r);
4244 70 : set_avma(av); return get_suppl(x,d,nbrows(x),r,&col_ei);
4245 : }
4246 :
4247 : GEN
4248 7 : image2(GEN x)
4249 : {
4250 7 : pari_sp av = avma;
4251 : long k, n, i;
4252 : GEN A, B;
4253 :
4254 7 : if (typ(x)!=t_MAT) pari_err_TYPE("image2",x);
4255 7 : if (lg(x) == 1) return cgetg(1,t_MAT);
4256 7 : A = ker(x); k = lg(A)-1;
4257 7 : if (!k) { set_avma(av); return gcopy(x); }
4258 7 : A = suppl(A); n = lg(A)-1;
4259 7 : B = cgetg(n-k+1, t_MAT);
4260 21 : for (i = k+1; i <= n; i++) gel(B,i-k) = RgM_RgC_mul(x, gel(A,i));
4261 7 : return gerepileupto(av, B);
4262 : }
4263 :
4264 : GEN
4265 217 : matimage0(GEN x,long flag)
4266 : {
4267 217 : switch(flag)
4268 : {
4269 210 : case 0: return image(x);
4270 7 : case 1: return image2(x);
4271 0 : default: pari_err_FLAG("matimage");
4272 : }
4273 : return NULL; /* LCOV_EXCL_LINE */
4274 : }
4275 :
4276 : static long
4277 126 : RgM_rank_FpM(GEN x, GEN p)
4278 : {
4279 126 : pari_sp av = avma;
4280 : ulong pp;
4281 : long r;
4282 126 : x = RgM_Fp_init(x,p,&pp);
4283 126 : switch(pp)
4284 : {
4285 28 : case 0: r = FpM_rank(x,p); break;
4286 63 : case 2: r = F2m_rank(x); break;
4287 35 : default:r = Flm_rank(x,pp); break;
4288 : }
4289 126 : return gc_long(av, r);
4290 : }
4291 :
4292 : static long
4293 49 : RgM_rank_FqM(GEN x, GEN pol, GEN p)
4294 : {
4295 49 : pari_sp av = avma;
4296 : long r;
4297 49 : GEN T = RgX_to_FpX(pol, p);
4298 49 : if (signe(T) == 0) pari_err_OP("rank",x,pol);
4299 42 : r = FqM_rank(RgM_to_FqM(x, T, p), T, p);
4300 42 : return gc_long(av,r);
4301 : }
4302 :
4303 : #define code(t1,t2) ((t1 << 6) | t2)
4304 : static long
4305 315 : RgM_rank_fast(GEN x)
4306 : {
4307 : GEN p, pol;
4308 : long pa;
4309 315 : long t = RgM_type(x,&p,&pol,&pa);
4310 315 : switch(t)
4311 : {
4312 42 : case t_INT: return ZM_rank(x);
4313 21 : case t_FRAC: return QM_rank(x);
4314 126 : case t_INTMOD: return RgM_rank_FpM(x, p);
4315 70 : case t_FFELT: return FFM_rank(x, pol);
4316 49 : case code(t_POLMOD, t_INTMOD):
4317 49 : return RgM_rank_FqM(x, pol, p);
4318 7 : default: return -1;
4319 : }
4320 : }
4321 : #undef code
4322 :
4323 : long
4324 315 : rank(GEN x)
4325 : {
4326 315 : pari_sp av = avma;
4327 : long r;
4328 :
4329 315 : if (typ(x)!=t_MAT) pari_err_TYPE("rank",x);
4330 315 : r = RgM_rank_fast(x);
4331 308 : if (r >= 0) return r;
4332 7 : (void)gauss_pivot(x, &r);
4333 7 : return gc_long(av, lg(x)-1 - r);
4334 : }
4335 :
4336 : /* d a t_VECSMALL of integers in 1..n. Return the vector of the d[i]
4337 : * followed by the missing indices */
4338 : static GEN
4339 43560 : perm_complete(GEN d, long n)
4340 : {
4341 43560 : GEN y = cgetg(n+1, t_VECSMALL);
4342 43560 : long i, j = 1, k = n, l = lg(d);
4343 43560 : pari_sp av = avma;
4344 43560 : char *T = stack_calloc(n+1);
4345 214334 : for (i = 1; i < l; i++) T[d[i]] = 1;
4346 417463 : for (i = 1; i <= n; i++)
4347 373903 : if (T[i]) y[j++] = i; else y[k--] = i;
4348 43560 : return gc_const(av, y);
4349 : }
4350 :
4351 : /* n = dim x, r = dim Ker(x), d from gauss_pivot */
4352 : static GEN
4353 6181 : indeximage0(long n, long r, GEN d)
4354 : {
4355 : long i, j;
4356 : GEN v;
4357 :
4358 6181 : r = n - r; /* now r = dim Im(x) */
4359 6181 : v = cgetg(r+1,t_VECSMALL);
4360 34419 : if (d) for (i=j=1; j<=n; j++)
4361 28238 : if (d[j]) v[i++] = j;
4362 6181 : return v;
4363 : }
4364 : /* x an m x n t_MAT, n > 0, r = dim Ker(x), d from gauss_pivot */
4365 : static void
4366 21780 : indexrank_all(long m, long n, long r, GEN d, GEN *prow, GEN *pcol)
4367 : {
4368 21780 : GEN IR = indexrank0(n, r, d);
4369 21780 : *prow = perm_complete(gel(IR,1), m);
4370 21780 : *pcol = perm_complete(gel(IR,2), n);
4371 21780 : }
4372 :
4373 : static GEN
4374 28 : RgM_indexrank_FpM(GEN x, GEN p)
4375 : {
4376 28 : pari_sp av = avma;
4377 : ulong pp;
4378 : GEN r;
4379 28 : x = RgM_Fp_init(x,p,&pp);
4380 28 : switch(pp)
4381 : {
4382 7 : case 0: r = FpM_indexrank(x,p); break;
4383 7 : case 2: r = F2m_indexrank(x); break;
4384 14 : default: r = Flm_indexrank(x,pp); break;
4385 : }
4386 28 : return gerepileupto(av, r);
4387 : }
4388 :
4389 : static GEN
4390 0 : RgM_indexrank_FqM(GEN x, GEN pol, GEN p)
4391 : {
4392 0 : pari_sp av = avma;
4393 0 : GEN r, T = RgX_to_FpX(pol, p);
4394 0 : if (signe(T) == 0) pari_err_OP("indexrank",x,pol);
4395 0 : r = FqM_indexrank(RgM_to_FqM(x, T, p), T, p);
4396 0 : return gerepileupto(av, r);
4397 : }
4398 :
4399 : #define code(t1,t2) ((t1 << 6) | t2)
4400 : static GEN
4401 77511 : RgM_indexrank_fast(GEN x)
4402 : {
4403 : GEN p, pol;
4404 : long pa;
4405 77511 : long t = RgM_type(x,&p,&pol,&pa);
4406 77514 : switch(t)
4407 : {
4408 406 : case t_INT: return ZM_indexrank(x);
4409 1344 : case t_FRAC: return QM_indexrank(x);
4410 28 : case t_INTMOD: return RgM_indexrank_FpM(x, p);
4411 21 : case t_FFELT: return FFM_indexrank(x, pol);
4412 0 : case code(t_POLMOD, t_INTMOD):
4413 0 : return RgM_indexrank_FqM(x, pol, p);
4414 75715 : default: return NULL;
4415 : }
4416 : }
4417 : #undef code
4418 :
4419 : GEN
4420 77511 : indexrank(GEN x)
4421 : {
4422 : pari_sp av;
4423 : long r;
4424 : GEN d;
4425 77511 : if (typ(x)!=t_MAT) pari_err_TYPE("indexrank",x);
4426 77511 : d = RgM_indexrank_fast(x);
4427 77514 : if (d) return d;
4428 75715 : av = avma;
4429 75715 : init_indexrank(x);
4430 75715 : d = gauss_pivot(x, &r);
4431 75713 : set_avma(av); return indexrank0(lg(x)-1, r, d);
4432 : }
4433 :
4434 : GEN
4435 6181 : ZM_indeximage(GEN x) {
4436 6181 : pari_sp av = avma;
4437 : long r;
4438 : GEN d;
4439 6181 : init_indexrank(x);
4440 6181 : d = ZM_pivots(x,&r);
4441 6181 : set_avma(av); return indeximage0(lg(x)-1, r, d);
4442 : }
4443 : long
4444 2225006 : ZM_rank(GEN x) {
4445 2225006 : pari_sp av = avma;
4446 : long r;
4447 2225006 : (void)ZM_pivots(x,&r);
4448 2225004 : return gc_long(av, lg(x)-1-r);
4449 : }
4450 : GEN
4451 1773318 : ZM_indexrank(GEN x) {
4452 1773318 : pari_sp av = avma;
4453 : long r;
4454 : GEN d;
4455 1773318 : init_indexrank(x);
4456 1773315 : d = ZM_pivots(x,&r);
4457 1773317 : set_avma(av); return indexrank0(lg(x)-1, r, d);
4458 : }
4459 :
4460 : long
4461 21 : QM_rank(GEN x)
4462 : {
4463 21 : pari_sp av = avma;
4464 21 : long r = ZM_rank(Q_primpart(x));
4465 21 : set_avma(av);
4466 21 : return r;
4467 : }
4468 :
4469 : GEN
4470 1344 : QM_indexrank(GEN x)
4471 : {
4472 1344 : pari_sp av = avma;
4473 1344 : GEN r = ZM_indexrank(Q_primpart(x));
4474 1344 : return gerepileupto(av, r);
4475 : }
4476 :
4477 : /*******************************************************************/
4478 : /* */
4479 : /* ZabM */
4480 : /* */
4481 : /*******************************************************************/
4482 :
4483 : static GEN
4484 1276 : FpXM_ratlift(GEN a, GEN q)
4485 : {
4486 : GEN B, y;
4487 1276 : long i, j, l = lg(a), n;
4488 1276 : B = sqrti(shifti(q,-1));
4489 1276 : y = cgetg(l, t_MAT);
4490 1276 : if (l==1) return y;
4491 1276 : n = lgcols(a);
4492 3059 : for (i=1; i<l; i++)
4493 : {
4494 2404 : GEN yi = cgetg(n, t_COL);
4495 32311 : for (j=1; j<n; j++)
4496 : {
4497 30528 : GEN v = FpX_ratlift(gmael(a,i,j), q, B, B, NULL);
4498 30528 : if (!v) return NULL;
4499 29907 : gel(yi, j) = RgX_renormalize(v);
4500 : }
4501 1783 : gel(y,i) = yi;
4502 : }
4503 655 : return y;
4504 : }
4505 :
4506 : static GEN
4507 4477 : FlmV_recover_pre(GEN a, GEN M, ulong p, ulong pi, long sv)
4508 : {
4509 4477 : GEN a1 = gel(a,1);
4510 4477 : long i, j, k, l = lg(a1), n, lM = lg(M);
4511 4477 : GEN v = cgetg(lM, t_VECSMALL);
4512 4477 : GEN y = cgetg(l, t_MAT);
4513 4477 : if (l==1) return y;
4514 4477 : n = lgcols(a1);
4515 22470 : for (i=1; i<l; i++)
4516 : {
4517 17988 : GEN yi = cgetg(n, t_COL);
4518 347263 : for (j=1; j<n; j++)
4519 : {
4520 4674526 : for (k=1; k<lM; k++) uel(v,k) = umael(gel(a,k),i,j);
4521 329270 : gel(yi, j) = Flm_Flc_mul_pre_Flx(M, v, p, pi, sv);
4522 : }
4523 17993 : gel(y,i) = yi;
4524 : }
4525 4482 : return y;
4526 : }
4527 :
4528 : static GEN
4529 0 : FlkM_inv(GEN M, GEN P, ulong p)
4530 : {
4531 0 : ulong PI = get_Fl_red(p), pi = SMALL_ULONG(p)? 0: PI;
4532 0 : GEN R = Flx_roots_pre(P, p, pi);
4533 0 : long l = lg(R), i;
4534 0 : GEN W = Flv_invVandermonde(R, 1UL, p);
4535 0 : GEN V = cgetg(l, t_VEC);
4536 0 : for(i=1; i<l; i++)
4537 : {
4538 0 : GEN pows = Fl_powers_pre(uel(R,i), degpol(P), p, PI);
4539 0 : GEN H = Flm_inv_sp(FlxM_eval_powers_pre(M, pows, p, pi), NULL, p);
4540 0 : if (!H) return NULL;
4541 0 : gel(V, i) = H;
4542 : }
4543 0 : return FlmV_recover_pre(V, W, p, pi, P[1]);
4544 : }
4545 :
4546 : static GEN
4547 3201 : FlkM_adjoint(GEN M, GEN P, ulong p)
4548 : {
4549 3201 : ulong PI = get_Fl_red(p), pi = SMALL_ULONG(p)? 0: PI;
4550 3201 : GEN R = Flx_roots_pre(P, p, pi);
4551 3201 : long l = lg(R), i;
4552 3201 : GEN W = Flv_invVandermonde(R, 1UL, p);
4553 3201 : GEN V = cgetg(l, t_VEC);
4554 15521 : for(i=1; i<l; i++)
4555 : {
4556 12320 : GEN pows = Fl_powers_pre(uel(R,i), degpol(P), p, PI);
4557 12320 : gel(V, i) = Flm_adjoint(FlxM_eval_powers_pre(M, pows, p, pi), p);
4558 : }
4559 3201 : return FlmV_recover_pre(V, W, p, pi, P[1]);
4560 : }
4561 :
4562 : static GEN
4563 1978 : ZabM_inv_slice(GEN A, GEN Q, GEN P, GEN *mod)
4564 : {
4565 1978 : pari_sp av = avma;
4566 1978 : long i, n = lg(P)-1, w = varn(Q);
4567 : GEN H, T;
4568 1978 : if (n == 1)
4569 : {
4570 1548 : ulong p = uel(P,1);
4571 1548 : GEN Qp = ZX_to_Flx(Q, p);
4572 1548 : GEN Ap = ZXM_to_FlxM(A, p, get_Flx_var(Qp));
4573 1548 : GEN Hp = FlkM_adjoint(Ap, Qp, p);
4574 1548 : Hp = gerepileupto(av, FlxM_to_ZXM(Hp));
4575 1548 : *mod = utoipos(p); return Hp;
4576 : }
4577 430 : T = ZV_producttree(P);
4578 430 : A = ZXM_nv_mod_tree(A, P, T, w);
4579 430 : Q = ZX_nv_mod_tree(Q, P, T);
4580 430 : H = cgetg(n+1, t_VEC);
4581 2083 : for(i=1; i <= n; i++)
4582 : {
4583 1653 : ulong p = P[i];
4584 1653 : GEN a = gel(A,i), q = gel(Q, i);
4585 1653 : gel(H,i) = FlkM_adjoint(a, q, p);
4586 : }
4587 430 : H = nxMV_chinese_center_tree_seq(H, P, T, ZV_chinesetree(P,T));
4588 430 : *mod = gmael(T, lg(T)-1, 1); return gc_all(av, 2, &H, mod);
4589 : }
4590 :
4591 : GEN
4592 1978 : ZabM_inv_worker(GEN P, GEN A, GEN Q)
4593 : {
4594 1978 : GEN V = cgetg(3, t_VEC);
4595 1978 : gel(V,1) = ZabM_inv_slice(A, Q, P, &gel(V,2));
4596 1978 : return V;
4597 : }
4598 :
4599 : static GEN
4600 5467 : vecnorml1(GEN a)
4601 : {
4602 : long i, l;
4603 5467 : GEN g = cgetg_copy(a, &l);
4604 60214 : for (i=1; i<l; i++)
4605 54747 : gel(g, i) = gnorml1_fake(gel(a,i));
4606 5467 : return g;
4607 : }
4608 :
4609 : static GEN
4610 1820 : ZabM_true_Hadamard(GEN a)
4611 : {
4612 1820 : pari_sp av = avma;
4613 1820 : long n = lg(a)-1, i;
4614 : GEN B;
4615 1820 : if (n == 0) return gen_1;
4616 1820 : if (n == 1) return gnorml1_fake(gcoeff(a,1,1));
4617 1176 : B = gen_1;
4618 6643 : for (i = 1; i <= n; i++)
4619 5467 : B = gmul(B, gnorml2(RgC_gtofp(vecnorml1(gel(a,i)),DEFAULTPREC)));
4620 1176 : return gerepileuptoint(av, ceil_safe(sqrtr_abs(B)));
4621 : }
4622 :
4623 : GEN
4624 1820 : ZabM_inv(GEN A, GEN Q, long n, GEN *pt_den)
4625 : {
4626 1820 : pari_sp av = avma;
4627 : forprime_t S;
4628 : GEN bnd, H, D, d, mod, worker;
4629 1820 : if (lg(A) == 1)
4630 : {
4631 0 : if (pt_den) *pt_den = gen_1;
4632 0 : return cgetg(1, t_MAT);
4633 : }
4634 1820 : bnd = ZabM_true_Hadamard(A);
4635 1820 : worker = snm_closure(is_entry("_ZabM_inv_worker"), mkvec2(A, Q));
4636 1820 : u_forprime_arith_init(&S, HIGHBIT+1, ULONG_MAX, 1, n);
4637 1820 : H = gen_crt("ZabM_inv", worker, &S, NULL, expi(bnd), 0, &mod,
4638 : nxMV_chinese_center, FpXM_center);
4639 1820 : D = RgMrow_RgC_mul(H, gel(A,1), 1);
4640 1820 : D = ZX_rem(D, Q);
4641 1820 : d = Z_content(mkvec2(H, D));
4642 1820 : if (d)
4643 : {
4644 511 : D = ZX_Z_divexact(D, d);
4645 511 : H = Q_div_to_int(H, d);
4646 : }
4647 1820 : if (!pt_den) return gerepileupto(av, H);
4648 1820 : *pt_den = D; return gc_all(av, 2, &H, pt_den);
4649 : }
4650 :
4651 : GEN
4652 0 : ZabM_inv_ratlift(GEN M, GEN P, long n, GEN *pden)
4653 : {
4654 0 : pari_sp av2, av = avma;
4655 : GEN q, H;
4656 0 : ulong m = LONG_MAX>>1;
4657 0 : ulong p= 1 + m - (m % n);
4658 0 : long lM = lg(M);
4659 0 : if (lM == 1) { *pden = gen_1; return cgetg(1,t_MAT); }
4660 :
4661 0 : av2 = avma;
4662 0 : H = NULL;
4663 : for(;;)
4664 0 : {
4665 : GEN Hp, Pp, Mp, Hr;
4666 0 : do p += n; while(!uisprime(p));
4667 0 : Pp = ZX_to_Flx(P, p);
4668 0 : Mp = ZXM_to_FlxM(M, p, get_Flx_var(Pp));
4669 0 : Hp = FlkM_inv(Mp, Pp, p);
4670 0 : if (!Hp) continue;
4671 0 : if (!H)
4672 : {
4673 0 : H = ZXM_init_CRT(Hp, degpol(P)-1, p);
4674 0 : q = utoipos(p);
4675 : }
4676 : else
4677 0 : ZXM_incremental_CRT(&H, Hp, &q, p);
4678 0 : Hr = FpXM_ratlift(H, q);
4679 0 : if (DEBUGLEVEL>5) err_printf("ZabM_inv mod %ld (ratlift=%ld)\n", p,!!Hr);
4680 0 : if (Hr) {/* DONE ? */
4681 0 : GEN Hl = Q_remove_denom(Hr, pden);
4682 0 : GEN MH = ZXQM_mul(Hl, M, P);
4683 0 : if (*pden)
4684 0 : { if (RgM_isscalar(MH, *pden)) { H = Hl; break; }}
4685 : else
4686 0 : { if (RgM_isidentity(MH)) { H = Hl; *pden = gen_1; break; } }
4687 : }
4688 :
4689 0 : if (gc_needed(av,2))
4690 : {
4691 0 : if (DEBUGMEM>1) pari_warn(warnmem,"ZabM_inv");
4692 0 : gerepileall(av2, 2, &H, &q);
4693 : }
4694 : }
4695 0 : return gc_all(av, 2, &H, pden);
4696 : }
4697 :
4698 : static GEN
4699 1276 : FlkM_ker(GEN M, GEN P, ulong p)
4700 : {
4701 1276 : ulong PI = get_Fl_red(p), pi = SMALL_ULONG(p)? 0: PI;
4702 1276 : GEN R = Flx_roots_pre(P, p, pi);
4703 1276 : long l = lg(R), i, dP = degpol(P), r;
4704 : GEN M1, K, D;
4705 1276 : GEN W = Flv_invVandermonde(R, 1UL, p);
4706 1276 : GEN V = cgetg(l, t_VEC);
4707 1276 : M1 = FlxM_eval_powers_pre(M, Fl_powers_pre(uel(R,1), dP, p, PI), p, pi);
4708 1276 : K = Flm_ker_sp(M1, p, 2);
4709 1276 : r = lg(gel(K,1)); D = gel(K,2);
4710 1276 : gel(V, 1) = gel(K,1);
4711 2652 : for(i=2; i<l; i++)
4712 : {
4713 1376 : GEN Mi = FlxM_eval_powers_pre(M, Fl_powers_pre(uel(R,i), dP, p, PI), p, pi);
4714 1376 : GEN K = Flm_ker_sp(Mi, p, 2);
4715 1376 : if (lg(gel(K,1)) != r || !zv_equal(D, gel(K,2))) return NULL;
4716 1376 : gel(V, i) = gel(K,1);
4717 : }
4718 1276 : return mkvec2(FlmV_recover_pre(V, W, p, pi, P[1]), D);
4719 : }
4720 :
4721 : static int
4722 655 : ZabM_ker_check(GEN M, GEN H, ulong p, GEN P, long n)
4723 : {
4724 : GEN pow;
4725 655 : long j, l = lg(H);
4726 : ulong pi, r;
4727 3899 : do p += n; while(!uisprime(p));
4728 655 : pi = get_Fl_red(p);
4729 655 : P = ZX_to_Flx(P, p);
4730 655 : r = Flx_oneroot_pre(P, p, pi);
4731 655 : pow = Fl_powers_pre(r, degpol(P),p, (p & HIGHMASK)? pi: 0);
4732 655 : M = ZXM_to_FlxM(M, p, P[1]); M = FlxM_eval_powers_pre(M, pow, p, pi);
4733 655 : H = ZXM_to_FlxM(H, p, P[1]); H = FlxM_eval_powers_pre(H, pow, p, pi);
4734 2178 : for (j = 1; j < l; j++)
4735 1555 : if (!zv_equal0(Flm_Flc_mul_pre(M, gel(H,j), p, pi))) return 0;
4736 623 : return 1;
4737 : }
4738 :
4739 : GEN
4740 623 : ZabM_ker(GEN M, GEN P, long n)
4741 : {
4742 623 : pari_sp av = avma;
4743 : pari_timer ti;
4744 623 : GEN q, H = NULL, D = NULL;
4745 623 : ulong m = LONG_MAX>>1;
4746 623 : ulong p = 1 + m - (m % n);
4747 :
4748 623 : if (DEBUGLEVEL>5) timer_start(&ti);
4749 : for(;;)
4750 653 : {
4751 : GEN Kp, Hp, Dp, Pp, Mp, Hr;
4752 22341 : do p += n; while(!uisprime(p));
4753 1276 : Pp = ZX_to_Flx(P, p);
4754 1276 : Mp = ZXM_to_FlxM(M, p, get_Flx_var(Pp));
4755 1276 : Kp = FlkM_ker(Mp, Pp, p);
4756 1276 : if (!Kp) continue;
4757 1276 : Hp = gel(Kp,1); Dp = gel(Kp,2);
4758 1276 : if (H && (lg(Hp)>lg(H) || (lg(Hp)==lg(H) && vecsmall_lexcmp(Dp,D)>0))) continue;
4759 1276 : if (!H || (lg(Hp)<lg(H) || vecsmall_lexcmp(Dp,D)<0))
4760 : {
4761 623 : H = ZXM_init_CRT(Hp, degpol(P)-1, p); D = Dp;
4762 623 : q = utoipos(p);
4763 : }
4764 : else
4765 653 : ZXM_incremental_CRT(&H, Hp, &q, p);
4766 1276 : Hr = FpXM_ratlift(H, q);
4767 1276 : if (DEBUGLEVEL>5) timer_printf(&ti,"ZabM_ker mod %ld (ratlift=%ld)", p,!!Hr);
4768 1276 : if (Hr) {/* DONE ? */
4769 655 : GEN Hl = vec_Q_primpart(Hr);
4770 655 : if (ZabM_ker_check(M, Hl, p, P, n)) { H = Hl; break; }
4771 : }
4772 :
4773 653 : if (gc_needed(av,2))
4774 : {
4775 4 : if (DEBUGMEM>1) pari_warn(warnmem,"ZabM_ker");
4776 4 : gerepileall(av, 3, &H, &D, &q);
4777 : }
4778 : }
4779 623 : return gerepilecopy(av, H);
4780 : }
4781 :
4782 : GEN
4783 2387 : ZabM_indexrank(GEN M, GEN P, long n)
4784 : {
4785 2387 : pari_sp av = avma;
4786 2387 : ulong m = LONG_MAX>>1;
4787 2387 : ulong p = 1+m-(m%n), D = degpol(P);
4788 2387 : long lM = lg(M), lmax = 0, c = 0;
4789 : GEN v;
4790 : for(;;)
4791 735 : {
4792 : GEN R, Pp, Mp, K;
4793 : ulong pi;
4794 : long l;
4795 61415 : do p += n; while (!uisprime(p));
4796 3122 : pi = (p & HIGHMASK)? get_Fl_red(p): 0;
4797 3122 : Pp = ZX_to_Flx(P, p);
4798 3122 : R = Flx_roots_pre(Pp, p, pi);
4799 3122 : Mp = ZXM_to_FlxM(M, p, get_Flx_var(Pp));
4800 3122 : K = FlxM_eval_powers_pre(Mp, Fl_powers_pre(uel(R,1), D,p,pi), p,pi);
4801 3122 : v = Flm_indexrank(K, p);
4802 3122 : l = lg(gel(v,2));
4803 3122 : if (l == lM) break;
4804 980 : if (lmax >= 0 && l > lmax) { lmax = l; c = 0; } else c++;
4805 980 : if (c > 2)
4806 : { /* probably not maximal rank, expensive check */
4807 245 : lM -= lg(ZabM_ker(M, P, n))-1; /* actual rank (+1) */
4808 245 : if (lmax == lM) break;
4809 0 : lmax = -1; /* disable check */
4810 : }
4811 : }
4812 2387 : return gerepileupto(av, v);
4813 : }
4814 :
4815 : #if 0
4816 : GEN
4817 : ZabM_gauss(GEN M, GEN P, long n, GEN *den)
4818 : {
4819 : pari_sp av = avma;
4820 : GEN v, S, W;
4821 : v = ZabM_indexrank(M, P, n);
4822 : S = shallowmatextract(M,gel(v,1),gel(v,2));
4823 : W = ZabM_inv(S, P, n, den);
4824 : return gc_all(av,2,&W,den);
4825 : }
4826 : #endif
4827 :
4828 : GEN
4829 140 : ZabM_pseudoinv(GEN M, GEN P, long n, GEN *pv, GEN *den)
4830 : {
4831 140 : GEN v = ZabM_indexrank(M, P, n);
4832 140 : if (pv) *pv = v;
4833 140 : M = shallowmatextract(M,gel(v,1),gel(v,2));
4834 140 : return ZabM_inv(M, P, n, den);
4835 : }
4836 : GEN
4837 5019 : ZM_pseudoinv(GEN M, GEN *pv, GEN *den)
4838 : {
4839 5019 : GEN v = ZM_indexrank(M);
4840 5019 : if (pv) *pv = v;
4841 5019 : M = shallowmatextract(M,gel(v,1),gel(v,2));
4842 5019 : return ZM_inv(M, den);
4843 : }
4844 :
4845 : /*******************************************************************/
4846 : /* */
4847 : /* Structured Elimination */
4848 : /* */
4849 : /*******************************************************************/
4850 :
4851 : static void
4852 95961 : rem_col(GEN c, long i, GEN iscol, GEN Wrow, long *rcol, long *rrow)
4853 : {
4854 95961 : long lc = lg(c), k;
4855 95961 : iscol[i] = 0; (*rcol)--;
4856 891372 : for (k = 1; k < lc; ++k)
4857 : {
4858 795411 : Wrow[c[k]]--;
4859 795411 : if (Wrow[c[k]]==0) (*rrow)--;
4860 : }
4861 95961 : }
4862 :
4863 : static void
4864 7640 : rem_singleton(GEN M, GEN iscol, GEN Wrow, long idx, long *rcol, long *rrow)
4865 : {
4866 : long i, j;
4867 7640 : long nbcol = lg(iscol)-1, last;
4868 : do
4869 : {
4870 9562 : last = 0;
4871 16912086 : for (i = 1; i <= nbcol; ++i)
4872 16902524 : if (iscol[i])
4873 : {
4874 9074225 : GEN c = idx ? gmael(M, i, idx): gel(M,i);
4875 9074225 : long lc = lg(c);
4876 83828469 : for (j = 1; j < lc; ++j)
4877 74772288 : if (Wrow[c[j]] == 1)
4878 : {
4879 18044 : rem_col(c, i, iscol, Wrow, rcol, rrow);
4880 18044 : last=1; break;
4881 : }
4882 : }
4883 9562 : } while (last);
4884 7640 : }
4885 :
4886 : static GEN
4887 7447 : fill_wcol(GEN M, GEN iscol, GEN Wrow, long *w, GEN wcol)
4888 : {
4889 7447 : long nbcol = lg(iscol)-1;
4890 : long i, j, m, last;
4891 : GEN per;
4892 20550 : for (m = 2, last=0; !last ; m++)
4893 : {
4894 25076958 : for (i = 1; i <= nbcol; ++i)
4895 : {
4896 25063855 : wcol[i] = 0;
4897 25063855 : if (iscol[i])
4898 : {
4899 13864061 : GEN c = gmael(M, i, 1);
4900 13864061 : long lc = lg(c);
4901 123891095 : for (j = 1; j < lc; ++j)
4902 110027034 : if (Wrow[c[j]] == m) { wcol[i]++; last = 1; }
4903 : }
4904 : }
4905 : }
4906 7447 : per = vecsmall_indexsort(wcol);
4907 7447 : *w = wcol[per[nbcol]];
4908 7447 : return per;
4909 : }
4910 :
4911 : /* M is a RgMs with nbrow rows, A a list of row indices.
4912 : Eliminate rows of M with a single entry that do not belong to A,
4913 : and the corresponding columns. Also eliminate columns until #colums=#rows.
4914 : Return pcol and prow:
4915 : pcol is a map from the new columns indices to the old one.
4916 : prow is a map from the old rows indices to the new one (0 if removed).
4917 : */
4918 :
4919 : void
4920 147 : RgMs_structelim_col(GEN M, long nbcol, long nbrow, GEN A, GEN *p_col, GEN *p_row)
4921 : {
4922 147 : long i, j, k, lA = lg(A);
4923 147 : GEN prow = cgetg(nbrow+1, t_VECSMALL);
4924 147 : GEN pcol = zero_zv(nbcol);
4925 147 : pari_sp av = avma;
4926 147 : long rcol = nbcol, rrow = 0, imin = nbcol - usqrt(nbcol);
4927 147 : GEN iscol = const_vecsmall(nbcol, 1);
4928 147 : GEN Wrow = zero_zv(nbrow);
4929 147 : GEN wcol = cgetg(nbcol+1, t_VECSMALL);
4930 147 : pari_sp av2 = avma;
4931 110397 : for (i = 1; i <= nbcol; ++i)
4932 : {
4933 110250 : GEN F = gmael(M, i, 1);
4934 110250 : long l = lg(F)-1;
4935 924684 : for (j = 1; j <= l; ++j) Wrow[F[j]]++;
4936 : }
4937 147 : for (j = 1; j < lA; ++j)
4938 : {
4939 0 : if (Wrow[A[j]] == 0) { *p_col=NULL; return; }
4940 0 : Wrow[A[j]] = -1;
4941 : }
4942 228354 : for (i = 1; i <= nbrow; ++i)
4943 228207 : if (Wrow[i]) rrow++;
4944 147 : rem_singleton(M, iscol, Wrow, 1, &rcol, &rrow);
4945 147 : if (rcol < rrow) pari_err_BUG("RgMs_structelim, rcol<rrow");
4946 7594 : while (rcol > rrow)
4947 : {
4948 : long w;
4949 7447 : GEN per = fill_wcol(M, iscol, Wrow, &w, wcol);
4950 85364 : for (i = nbcol; i>=imin && wcol[per[i]]>=w && rcol>rrow; i--)
4951 77917 : rem_col(gmael(M, per[i], 1), per[i], iscol, Wrow, &rcol, &rrow);
4952 7447 : rem_singleton(M, iscol, Wrow, 1, &rcol, &rrow); set_avma(av2);
4953 : }
4954 110397 : for (j = 1, i = 1; i <= nbcol; ++i)
4955 110250 : if (iscol[i]) pcol[j++] = i;
4956 147 : setlg(pcol,j);
4957 228354 : for (k = 1, i = 1; i <= nbrow; ++i) prow[i] = Wrow[i]? k++: 0;
4958 147 : *p_col = pcol; *p_row = prow; set_avma(av);
4959 : }
4960 :
4961 : void
4962 0 : RgMs_structelim(GEN M, long nbrow, GEN A, GEN *p_col, GEN *p_row)
4963 0 : { RgMs_structelim_col(M, lg(M)-1, nbrow, A, p_col, p_row); }
4964 :
4965 : GEN
4966 46 : F2Ms_colelim(GEN M, long nbrow)
4967 : {
4968 46 : long i,j, nbcol = lg(M)-1, rcol = nbcol, rrow = 0;
4969 46 : GEN pcol = zero_zv(nbcol);
4970 46 : pari_sp av = avma;
4971 46 : GEN iscol = const_vecsmall(nbcol, 1), Wrow = zero_zv(nbrow);
4972 77470 : for (i = 1; i <= nbcol; ++i)
4973 : {
4974 77424 : GEN F = gel(M, i);
4975 77424 : long l = lg(F)-1;
4976 1431938 : for (j = 1; j <= l; ++j) Wrow[F[j]]++;
4977 : }
4978 46 : rem_singleton(M, iscol, Wrow, 0, &rcol, &rrow);
4979 77470 : for (j = 1, i = 1; i <= nbcol; ++i)
4980 77424 : if (iscol[i]) pcol[j++] = i;
4981 46 : fixlg(pcol,j); return gc_const(av, pcol);
4982 : }
4983 :
4984 : /*******************************************************************/
4985 : /* */
4986 : /* EIGENVECTORS */
4987 : /* (independent eigenvectors, sorted by increasing eigenvalue) */
4988 : /* */
4989 : /*******************************************************************/
4990 : /* assume x is square of dimension > 0 */
4991 : static int
4992 53 : RgM_is_symmetric_cx(GEN x, long bit)
4993 : {
4994 53 : pari_sp av = avma;
4995 53 : long i, j, l = lg(x);
4996 239 : for (i = 1; i < l; i++)
4997 708 : for (j = 1; j < i; j++)
4998 : {
4999 522 : GEN a = gcoeff(x,i,j), b = gcoeff(x,j,i), c = gsub(a,b);
5000 522 : if (!gequal0(c) && gexpo(c) - gexpo(a) > -bit) return gc_long(av,0);
5001 : }
5002 21 : return gc_long(av,1);
5003 : }
5004 : static GEN
5005 53 : eigen_err(int exact, GEN x, long flag, long prec)
5006 : {
5007 53 : pari_sp av = avma;
5008 : GEN y;
5009 53 : if (RgM_is_symmetric_cx(x, prec - 10))
5010 : { /* approximately symmetric: recover */
5011 21 : x = jacobi(x, prec); if (flag) return x;
5012 14 : return gerepilecopy(av, gel(x,2));
5013 : }
5014 32 : if (!exact) x = bestappr(x, NULL);
5015 32 : y = mateigen(x, flag, precdbl(prec));
5016 32 : if (exact)
5017 18 : y = gprec_wtrunc(y, prec);
5018 14 : else if (flag)
5019 7 : y = mkvec2(RgV_gtofp(gel(y,1), prec), RgM_gtofp(gel(y,2), prec));
5020 : else
5021 7 : y = RgM_gtofp(y, prec);
5022 32 : return gerepilecopy(av, y);
5023 : }
5024 : GEN
5025 144 : mateigen(GEN x, long flag, long prec)
5026 : {
5027 : GEN y, R, T;
5028 144 : long k, l, ex, n = lg(x);
5029 : int exact;
5030 144 : pari_sp av = avma;
5031 :
5032 144 : if (typ(x)!=t_MAT) pari_err_TYPE("eigen",x);
5033 144 : if (n != 1 && n != lgcols(x)) pari_err_DIM("eigen");
5034 144 : if (flag < 0 || flag > 1) pari_err_FLAG("mateigen");
5035 144 : if (n == 1)
5036 : {
5037 14 : if (flag) retmkvec2(cgetg(1,t_COL), cgetg(1,t_MAT));
5038 7 : return cgetg(1,t_MAT);
5039 : }
5040 130 : if (n == 2)
5041 : {
5042 14 : if (flag) retmkvec2(mkcolcopy(gcoeff(x,1,1)), matid(1));
5043 7 : return matid(1);
5044 : }
5045 :
5046 116 : ex = 16 - prec;
5047 116 : T = charpoly(x,0);
5048 116 : exact = RgX_is_QX(T);
5049 116 : if (exact)
5050 : {
5051 74 : T = ZX_radical( Q_primpart(T) );
5052 74 : R = nfrootsQ(T); settyp(R, t_COL);
5053 74 : if (lg(R)-1 < degpol(T))
5054 : { /* add missing complex roots */
5055 60 : GEN r = cleanroots(RgX_div(T, roots_to_pol(R, 0)), prec);
5056 60 : R = shallowconcat(R, r);
5057 : }
5058 : }
5059 : else
5060 : {
5061 42 : GEN r1, v = vectrunc_init(lg(T));
5062 : long e;
5063 42 : R = cleanroots(T,prec);
5064 42 : r1 = NULL;
5065 266 : for (k = 1; k < lg(R); k++)
5066 : {
5067 224 : GEN r2 = gel(R,k), r = grndtoi(r2, &e);
5068 224 : if (e < ex) r2 = r;
5069 224 : if (r1)
5070 : {
5071 182 : r = gsub(r1,r2);
5072 182 : if (gequal0(r) || gexpo(r) < ex) continue;
5073 : }
5074 182 : vectrunc_append(v, r2);
5075 182 : r1 = r2;
5076 : }
5077 42 : R = v;
5078 : }
5079 : /* R = distinct complex roots of charpoly(x) */
5080 116 : l = lg(R); y = cgetg(l, t_VEC);
5081 452 : for (k = 1; k < l; k++)
5082 : {
5083 389 : GEN F = ker_aux(RgM_Rg_sub_shallow(x, gel(R,k)), x);
5084 389 : long d = lg(F)-1;
5085 389 : if (!d) { set_avma(av); return eigen_err(exact, x, flag, prec); }
5086 336 : gel(y,k) = F;
5087 336 : if (flag) gel(R,k) = const_col(d, gel(R,k));
5088 : }
5089 63 : y = shallowconcat1(y);
5090 63 : if (lg(y) > n) { set_avma(av); return eigen_err(exact, x, flag, prec); }
5091 : /* lg(y) < n if x is not diagonalizable */
5092 63 : if (flag) y = mkvec2(shallowconcat1(R), y);
5093 63 : return gerepilecopy(av,y);
5094 : }
5095 : GEN
5096 0 : eigen(GEN x, long prec) { return mateigen(x, 0, prec); }
5097 :
5098 : /*******************************************************************/
5099 : /* */
5100 : /* DETERMINANT */
5101 : /* */
5102 : /*******************************************************************/
5103 :
5104 : GEN
5105 26593 : det0(GEN a,long flag)
5106 : {
5107 26593 : switch(flag)
5108 : {
5109 26579 : case 0: return det(a);
5110 14 : case 1: return det2(a);
5111 0 : default: pari_err_FLAG("matdet");
5112 : }
5113 : return NULL; /* LCOV_EXCL_LINE */
5114 : }
5115 :
5116 : /* M a 2x2 matrix, returns det(M) */
5117 : static GEN
5118 94043 : RgM_det2(GEN M)
5119 : {
5120 94043 : pari_sp av = avma;
5121 94043 : GEN a = gcoeff(M,1,1), b = gcoeff(M,1,2);
5122 94043 : GEN c = gcoeff(M,2,1), d = gcoeff(M,2,2);
5123 94043 : return gerepileupto(av, gsub(gmul(a,d), gmul(b,c)));
5124 : }
5125 : /* M a 2x2 ZM, returns det(M) */
5126 : static GEN
5127 8617 : ZM_det2(GEN M)
5128 : {
5129 8617 : pari_sp av = avma;
5130 8617 : GEN a = gcoeff(M,1,1), b = gcoeff(M,1,2);
5131 8617 : GEN c = gcoeff(M,2,1), d = gcoeff(M,2,2);
5132 8617 : return gerepileuptoint(av, subii(mulii(a,d), mulii(b, c)));
5133 : }
5134 : /* M a 3x3 ZM, return det(M) */
5135 : static GEN
5136 100472 : ZM_det3(GEN M)
5137 : {
5138 100472 : pari_sp av = avma;
5139 100472 : GEN a = gcoeff(M,1,1), b = gcoeff(M,1,2), c = gcoeff(M,1,3);
5140 100472 : GEN d = gcoeff(M,2,1), e = gcoeff(M,2,2), f = gcoeff(M,2,3);
5141 100472 : GEN g = gcoeff(M,3,1), h = gcoeff(M,3,2), i = gcoeff(M,3,3);
5142 100472 : GEN t, D = signe(i)? mulii(subii(mulii(a,e), mulii(b,d)), i): gen_0;
5143 100472 : if (signe(g))
5144 : {
5145 66202 : t = mulii(subii(mulii(b,f), mulii(c,e)), g);
5146 66202 : D = addii(D, t);
5147 : }
5148 100472 : if (signe(h))
5149 : {
5150 77604 : t = mulii(subii(mulii(c,d), mulii(a,f)), h);
5151 77604 : D = addii(D, t);
5152 : }
5153 100472 : return gerepileuptoint(av, D);
5154 : }
5155 :
5156 : static GEN
5157 58284 : det_simple_gauss(GEN a, GEN data, pivot_fun pivot)
5158 : {
5159 58284 : pari_sp av = avma;
5160 58284 : long i,j,k, s = 1, nbco = lg(a)-1;
5161 58284 : GEN p, x = gen_1;
5162 :
5163 58284 : a = RgM_shallowcopy(a);
5164 342215 : for (i=1; i<nbco; i++)
5165 : {
5166 283939 : k = pivot(a, data, i, NULL);
5167 283940 : if (k > nbco) return gerepilecopy(av, gcoeff(a,i,i));
5168 283933 : if (k != i)
5169 : { /* exchange the lines s.t. k = i */
5170 1159511 : for (j=i; j<=nbco; j++) swap(gcoeff(a,i,j), gcoeff(a,k,j));
5171 119118 : s = -s;
5172 : }
5173 283933 : p = gcoeff(a,i,i);
5174 :
5175 283933 : x = gmul(x,p);
5176 1787218 : for (k=i+1; k<=nbco; k++)
5177 : {
5178 1503289 : GEN m = gcoeff(a,i,k);
5179 1503289 : if (gequal0(m)) continue;
5180 :
5181 1067978 : m = gdiv(m,p);
5182 9953063 : for (j=i+1; j<=nbco; j++)
5183 8885088 : gcoeff(a,j,k) = gsub(gcoeff(a,j,k), gmul(m,gcoeff(a,j,i)));
5184 : }
5185 283929 : if (gc_needed(av,2))
5186 : {
5187 0 : if(DEBUGMEM>1) pari_warn(warnmem,"det. col = %ld",i);
5188 0 : gerepileall(av,2, &a,&x);
5189 : }
5190 : }
5191 58276 : if (s < 0) x = gneg_i(x);
5192 58276 : return gerepileupto(av, gmul(x, gcoeff(a,nbco,nbco)));
5193 : }
5194 :
5195 : GEN
5196 134100 : det2(GEN a)
5197 : {
5198 : GEN data;
5199 : pivot_fun pivot;
5200 134100 : long n = lg(a)-1;
5201 134100 : if (typ(a)!=t_MAT) pari_err_TYPE("det2",a);
5202 134100 : if (!n) return gen_1;
5203 134100 : if (n != nbrows(a)) pari_err_DIM("det2");
5204 134103 : if (n == 1) return gcopy(gcoeff(a,1,1));
5205 85640 : if (n == 2) return RgM_det2(a);
5206 26764 : pivot = get_pivot_fun(a, a, &data);
5207 26764 : return det_simple_gauss(a, data, pivot);
5208 : }
5209 :
5210 : /* Assumes a a square t_MAT of dimension n > 0. Returns det(a) using
5211 : * Gauss-Bareiss. */
5212 : static GEN
5213 462 : det_bareiss(GEN a)
5214 : {
5215 462 : pari_sp av = avma;
5216 462 : long nbco = lg(a)-1,i,j,k,s = 1;
5217 : GEN p, pprec;
5218 :
5219 462 : a = RgM_shallowcopy(a);
5220 1337 : for (pprec=gen_1,i=1; i<nbco; i++,pprec=p)
5221 : {
5222 882 : int diveuc = (gequal1(pprec)==0);
5223 : GEN ci;
5224 :
5225 882 : p = gcoeff(a,i,i);
5226 882 : if (gequal0(p))
5227 : {
5228 14 : k=i+1; while (k<=nbco && gequal0(gcoeff(a,i,k))) k++;
5229 7 : if (k>nbco) return gerepilecopy(av, p);
5230 0 : swap(gel(a,k), gel(a,i)); s = -s;
5231 0 : p = gcoeff(a,i,i);
5232 : }
5233 875 : ci = gel(a,i);
5234 2373 : for (k=i+1; k<=nbco; k++)
5235 : {
5236 1498 : GEN ck = gel(a,k), m = gel(ck,i);
5237 1498 : if (gequal0(m))
5238 : {
5239 7 : if (gequal1(p))
5240 : {
5241 0 : if (diveuc)
5242 0 : gel(a,k) = gdiv(gel(a,k), pprec);
5243 : }
5244 : else
5245 42 : for (j=i+1; j<=nbco; j++)
5246 : {
5247 35 : GEN p1 = gmul(p, gel(ck,j));
5248 35 : if (diveuc) p1 = gdiv(p1,pprec);
5249 35 : gel(ck,j) = p1;
5250 : }
5251 : }
5252 : else
5253 4662 : for (j=i+1; j<=nbco; j++)
5254 : {
5255 3171 : pari_sp av2 = avma;
5256 3171 : GEN p1 = gsub(gmul(p,gel(ck,j)), gmul(m,gel(ci,j)));
5257 3171 : if (diveuc) p1 = gdiv(p1,pprec);
5258 3171 : gel(ck,j) = gerepileupto(av2, p1);
5259 : }
5260 1498 : if (gc_needed(av,2))
5261 : {
5262 0 : if(DEBUGMEM>1) pari_warn(warnmem,"det. col = %ld",i);
5263 0 : gerepileall(av,2, &a,&pprec);
5264 0 : ci = gel(a,i);
5265 0 : p = gcoeff(a,i,i);
5266 : }
5267 : }
5268 : }
5269 455 : p = gcoeff(a,nbco,nbco);
5270 455 : p = (s < 0)? gneg(p): gcopy(p);
5271 455 : return gerepileupto(av, p);
5272 : }
5273 :
5274 : /* count nonzero entries in col j, at most 'max' of them.
5275 : * Return their indices */
5276 : static GEN
5277 1470 : col_count_non_zero(GEN a, long j, long max)
5278 : {
5279 1470 : GEN v = cgetg(max+1, t_VECSMALL);
5280 1470 : GEN c = gel(a,j);
5281 1470 : long i, l = lg(a), k = 1;
5282 5614 : for (i = 1; i < l; i++)
5283 5376 : if (!gequal0(gel(c,i)))
5284 : {
5285 5110 : if (k > max) return NULL; /* fail */
5286 3878 : v[k++] = i;
5287 : }
5288 238 : setlg(v, k); return v;
5289 : }
5290 : /* count nonzero entries in row i, at most 'max' of them.
5291 : * Return their indices */
5292 : static GEN
5293 1456 : row_count_non_zero(GEN a, long i, long max)
5294 : {
5295 1456 : GEN v = cgetg(max+1, t_VECSMALL);
5296 1456 : long j, l = lg(a), k = 1;
5297 5558 : for (j = 1; j < l; j++)
5298 5334 : if (!gequal0(gcoeff(a,i,j)))
5299 : {
5300 5096 : if (k > max) return NULL; /* fail */
5301 3864 : v[k++] = j;
5302 : }
5303 224 : setlg(v, k); return v;
5304 : }
5305 :
5306 : static GEN det_develop(GEN a, long max, double bound);
5307 : /* (-1)^(i+j) a[i,j] * det RgM_minor(a,i,j) */
5308 : static GEN
5309 406 : coeff_det(GEN a, long i, long j, long max, double bound)
5310 : {
5311 406 : GEN c = gcoeff(a, i, j);
5312 406 : c = gmul(c, det_develop(RgM_minor(a, i,j), max, bound));
5313 406 : if (odd(i+j)) c = gneg(c);
5314 406 : return c;
5315 : }
5316 : /* a square t_MAT, 'bound' a rough upper bound for the number of
5317 : * multiplications we are willing to pay while developing rows/columns before
5318 : * switching to Gaussian elimination */
5319 : static GEN
5320 658 : det_develop(GEN M, long max, double bound)
5321 : {
5322 658 : pari_sp av = avma;
5323 658 : long i,j, n = lg(M)-1, lbest = max+2, best_col = 0, best_row = 0;
5324 658 : GEN best = NULL;
5325 :
5326 658 : if (bound < 1.) return det_bareiss(M); /* too costly now */
5327 :
5328 434 : switch(n)
5329 : {
5330 0 : case 0: return gen_1;
5331 0 : case 1: return gcopy(gcoeff(M,1,1));
5332 14 : case 2: return RgM_det2(M);
5333 : }
5334 420 : if (max > ((n+2)>>1)) max = (n+2)>>1;
5335 1876 : for (j = 1; j <= n; j++)
5336 : {
5337 1470 : pari_sp av2 = avma;
5338 1470 : GEN v = col_count_non_zero(M, j, max);
5339 : long lv;
5340 1470 : if (!v || (lv = lg(v)) >= lbest) { set_avma(av2); continue; }
5341 182 : if (lv == 1) { set_avma(av); return gen_0; }
5342 182 : if (lv == 2) {
5343 14 : set_avma(av);
5344 14 : return gerepileupto(av, coeff_det(M,v[1],j,max,bound));
5345 : }
5346 168 : best = v; lbest = lv; best_col = j;
5347 : }
5348 1862 : for (i = 1; i <= n; i++)
5349 : {
5350 1456 : pari_sp av2 = avma;
5351 1456 : GEN v = row_count_non_zero(M, i, max);
5352 : long lv;
5353 1456 : if (!v || (lv = lg(v)) >= lbest) { set_avma(av2); continue; }
5354 0 : if (lv == 1) { set_avma(av); return gen_0; }
5355 0 : if (lv == 2) {
5356 0 : set_avma(av);
5357 0 : return gerepileupto(av, coeff_det(M,i,v[1],max,bound));
5358 : }
5359 0 : best = v; lbest = lv; best_row = i;
5360 : }
5361 406 : if (best_row)
5362 : {
5363 0 : double d = lbest-1;
5364 0 : GEN s = NULL;
5365 : long k;
5366 0 : bound /= d*d*d;
5367 0 : for (k = 1; k < lbest; k++)
5368 : {
5369 0 : GEN c = coeff_det(M, best_row, best[k], max, bound);
5370 0 : s = s? gadd(s, c): c;
5371 : }
5372 0 : return gerepileupto(av, s);
5373 : }
5374 406 : if (best_col)
5375 : {
5376 168 : double d = lbest-1;
5377 168 : GEN s = NULL;
5378 : long k;
5379 168 : bound /= d*d*d;
5380 560 : for (k = 1; k < lbest; k++)
5381 : {
5382 392 : GEN c = coeff_det(M, best[k], best_col, max, bound);
5383 392 : s = s? gadd(s, c): c;
5384 : }
5385 168 : return gerepileupto(av, s);
5386 : }
5387 238 : return det_bareiss(M);
5388 : }
5389 :
5390 : /* area of parallelogram bounded by (v1,v2) */
5391 : static GEN
5392 64282 : parallelogramarea(GEN v1, GEN v2)
5393 64282 : { return gsub(gmul(gnorml2(v1), gnorml2(v2)), gsqr(RgV_dotproduct(v1, v2))); }
5394 :
5395 : /* Square of Hadamard bound for det(a), a square matrix.
5396 : * Slight improvement: instead of using the column norms, use the area of
5397 : * the parallelogram formed by pairs of consecutive vectors */
5398 : GEN
5399 19996 : RgM_Hadamard(GEN a)
5400 : {
5401 19996 : pari_sp av = avma;
5402 19996 : long n = lg(a)-1, i;
5403 : GEN B;
5404 19996 : if (n == 0) return gen_1;
5405 19996 : if (n == 1) return gsqr(gcoeff(a,1,1));
5406 19996 : a = RgM_gtofp(a, LOWDEFAULTPREC);
5407 19996 : B = gen_1;
5408 84278 : for (i = 1; i <= n/2; i++)
5409 64282 : B = gmul(B, parallelogramarea(gel(a,2*i-1), gel(a,2*i)));
5410 19996 : if (odd(n)) B = gmul(B, gnorml2(gel(a, n)));
5411 19996 : return gerepileuptoint(av, ceil_safe(B));
5412 : }
5413 :
5414 : /* If B=NULL, assume B=A' */
5415 : static GEN
5416 20875 : ZM_det_slice(GEN A, GEN P, GEN *mod)
5417 : {
5418 20875 : pari_sp av = avma;
5419 20875 : long i, n = lg(P)-1;
5420 : GEN H, T;
5421 20875 : if (n == 1)
5422 : {
5423 0 : ulong Hp, p = uel(P,1);
5424 0 : GEN a = ZM_to_Flm(A, p);
5425 0 : Hp = Flm_det_sp(a, p);
5426 0 : set_avma(av); *mod = utoipos(p); return utoi(Hp);
5427 : }
5428 20875 : T = ZV_producttree(P);
5429 20875 : A = ZM_nv_mod_tree(A, P, T);
5430 20875 : H = cgetg(n+1, t_VECSMALL);
5431 87556 : for(i=1; i <= n; i++)
5432 : {
5433 66681 : ulong p = P[i];
5434 66681 : GEN a = gel(A,i);
5435 66681 : H[i] = Flm_det_sp(a, p);
5436 : }
5437 20875 : H = ZV_chinese_tree(H, P, T, ZV_chinesetree(P,T));
5438 20875 : *mod = gmael(T, lg(T)-1, 1); return gc_all(av, 2, &H, mod);
5439 : }
5440 :
5441 : GEN
5442 20875 : ZM_det_worker(GEN P, GEN A)
5443 : {
5444 20875 : GEN V = cgetg(3, t_VEC);
5445 20875 : gel(V,1) = ZM_det_slice(A, P, &gel(V,2));
5446 20875 : return V;
5447 : }
5448 :
5449 : GEN
5450 130653 : ZM_det(GEN M)
5451 : {
5452 : pari_sp av, av2;
5453 130653 : long n = lg(M)-1;
5454 : ulong p, Dp;
5455 : forprime_t S;
5456 : pari_timer ti;
5457 : GEN H, mod, h, q, worker;
5458 : #ifdef LONG_IS_64BIT
5459 111996 : const ulong PMAX = 18446744073709551557UL;
5460 : #else
5461 18657 : const ulong PMAX = 4294967291UL;
5462 : #endif
5463 :
5464 130653 : switch(n)
5465 : {
5466 7 : case 0: return gen_1;
5467 1561 : case 1: return icopy(gcoeff(M,1,1));
5468 8617 : case 2: return ZM_det2(M);
5469 100472 : case 3: return ZM_det3(M);
5470 : }
5471 19996 : if (DEBUGLEVEL>=4) timer_start(&ti);
5472 19996 : av = avma; h = RgM_Hadamard(M); /* |D| <= sqrt(h) */
5473 19996 : if (!signe(h)) { set_avma(av); return gen_0; }
5474 19996 : h = sqrti(h);
5475 19996 : if (lgefint(h) == 3 && (ulong)h[2] <= (PMAX >> 1))
5476 : { /* h < p/2 => direct result */
5477 7209 : p = PMAX;
5478 7209 : Dp = Flm_det_sp(ZM_to_Flm(M, p), p);
5479 7209 : set_avma(av);
5480 7209 : if (!Dp) return gen_0;
5481 7209 : return (Dp <= (p>>1))? utoipos(Dp): utoineg(p - Dp);
5482 : }
5483 12787 : q = gen_1; Dp = 1;
5484 12787 : init_modular_big(&S);
5485 12787 : p = 0; /* -Wall */
5486 12787 : while (cmpii(q, h) <= 0 && (p = u_forprime_next(&S)))
5487 : {
5488 12787 : av2 = avma; Dp = Flm_det_sp(ZM_to_Flm(M, p), p);
5489 12787 : set_avma(av2);
5490 12787 : if (Dp) break;
5491 0 : q = muliu(q, p);
5492 : }
5493 12787 : if (!p) pari_err_OVERFLOW("ZM_det [ran out of primes]");
5494 12787 : if (!Dp) { set_avma(av); return gen_0; }
5495 12787 : worker = snm_closure(is_entry("_ZM_det_worker"), mkvec(M));
5496 12787 : H = gen_crt("ZM_det", worker, &S, NULL, expi(h)+1, 0, &mod,
5497 : ZV_chinese, NULL);
5498 : /* H = det(M) modulo mod, (mod,D) = 1; |det(M) / D| <= h */
5499 12787 : H = Fp_center(H, mod, shifti(mod,-1));
5500 12787 : return gerepileuptoint(av, H);
5501 : }
5502 :
5503 : static GEN
5504 1519 : RgM_det_FpM(GEN a, GEN p)
5505 : {
5506 1519 : pari_sp av = avma;
5507 : ulong pp, d;
5508 1519 : a = RgM_Fp_init(a,p,&pp);
5509 1519 : switch(pp)
5510 : {
5511 70 : case 0: return gerepileupto(av, Fp_to_mod(FpM_det(a,p),p)); break;
5512 14 : case 2: d = F2m_det_sp(a); break;
5513 1435 : default:d = Flm_det_sp(a, pp); break;
5514 : }
5515 1449 : set_avma(av); return mkintmodu(d, pp);
5516 : }
5517 :
5518 : static GEN
5519 42 : RgM_det_FqM(GEN x, GEN pol, GEN p)
5520 : {
5521 42 : pari_sp av = avma;
5522 42 : GEN b, T = RgX_to_FpX(pol, p);
5523 42 : if (signe(T) == 0) pari_err_OP("%",x,pol);
5524 42 : b = FqM_det(RgM_to_FqM(x, T, p), T, p);
5525 42 : if (!b) return gc_NULL(av);
5526 42 : return gerepilecopy(av, mkpolmod(FpX_to_mod(b, p), FpX_to_mod(T, p)));
5527 : }
5528 :
5529 : #define code(t1,t2) ((t1 << 6) | t2)
5530 : static GEN
5531 33900 : RgM_det_fast(GEN x)
5532 : {
5533 : GEN p, pol;
5534 : long pa;
5535 33900 : long t = RgM_type(x, &p,&pol,&pa);
5536 33900 : switch(t)
5537 : {
5538 301 : case t_INT: return ZM_det(x);
5539 203 : case t_FRAC: return QM_det(x);
5540 63 : case t_FFELT: return FFM_det(x, pol);
5541 1519 : case t_INTMOD: return RgM_det_FpM(x, p);
5542 42 : case code(t_POLMOD, t_INTMOD):
5543 42 : return RgM_det_FqM(x, pol, p);
5544 31772 : default: return NULL;
5545 : }
5546 : }
5547 : #undef code
5548 :
5549 : static long
5550 252 : det_init_max(long n)
5551 : {
5552 252 : if (n > 100) return 0;
5553 252 : if (n > 50) return 1;
5554 252 : if (n > 30) return 4;
5555 252 : return 7;
5556 : }
5557 :
5558 : GEN
5559 246213 : det(GEN a)
5560 : {
5561 246213 : long n = lg(a)-1;
5562 : double B;
5563 : GEN data, b;
5564 : pivot_fun pivot;
5565 :
5566 246213 : if (typ(a)!=t_MAT) pari_err_TYPE("det",a);
5567 246213 : if (!n) return gen_1;
5568 246171 : if (n != nbrows(a)) pari_err_DIM("det");
5569 246164 : if (n == 1) return gcopy(gcoeff(a,1,1));
5570 69053 : if (n == 2) return RgM_det2(a);
5571 33900 : b = RgM_det_fast(a);
5572 33900 : if (b) return b;
5573 31772 : pivot = get_pivot_fun(a, a, &data);
5574 31772 : if (pivot != gauss_get_pivot_NZ) return det_simple_gauss(a, data, pivot);
5575 252 : B = (double)n;
5576 252 : return det_develop(a, det_init_max(n), B*B*B);
5577 : }
5578 :
5579 : GEN
5580 203 : QM_det(GEN M)
5581 : {
5582 203 : pari_sp av = avma;
5583 203 : GEN cM, pM = Q_primitive_part(M, &cM);
5584 203 : GEN b = ZM_det(pM);
5585 203 : if (cM) b = gmul(b, gpowgs(cM, lg(M)-1));
5586 203 : return gerepileupto(av, b);
5587 : }
|