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