1
2 #include <NTL/mat_lzz_pE.h>
3 #include <NTL/BasicThreadPool.h>
4
5 NTL_START_IMPL
6
7
8
9
10 // ==========================================
11
12
13
14
15 #define PAR_THRESH (40000.0)
16
17 static double
zz_pE_SizeInWords()18 zz_pE_SizeInWords()
19 {
20 return deg(zz_pE::modulus());
21 }
22
23
24 static
mul_aux(Mat<zz_pE> & X,const Mat<zz_pE> & A,const Mat<zz_pE> & B)25 void mul_aux(Mat<zz_pE>& X, const Mat<zz_pE>& A, const Mat<zz_pE>& B)
26 {
27 long n = A.NumRows();
28 long l = A.NumCols();
29 long m = B.NumCols();
30
31 if (l != B.NumRows())
32 LogicError("matrix mul: dimension mismatch");
33
34 X.SetDims(n, m);
35
36
37 zz_pContext zz_p_context;
38 zz_p_context.save();
39 zz_pEContext zz_pE_context;
40 zz_pE_context.save();
41 double sz = zz_pE_SizeInWords();
42
43 bool seq = (double(n)*double(l)*double(m)*sz*sz < PAR_THRESH);
44
45 NTL_GEXEC_RANGE(seq, m, first, last)
46 NTL_IMPORT(n)
47 NTL_IMPORT(l)
48 NTL_IMPORT(m)
49
50 zz_p_context.restore();
51 zz_pE_context.restore();
52
53 long i, j, k;
54 zz_pX acc, tmp;
55
56 Vec<zz_pE> B_col;
57 B_col.SetLength(l);
58
59 for (j = first; j < last; j++) {
60 for (k = 0; k < l; k++) B_col[k] = B[k][j];
61
62 for (i = 0; i < n; i++) {
63 clear(acc);
64 for (k = 0; k < l; k++) {
65 mul(tmp, rep(A[i][k]), rep(B_col[k]));
66 add(acc, acc, tmp);
67 }
68 conv(X[i][j], acc);
69 }
70 }
71
72 NTL_GEXEC_RANGE_END
73 }
74
75
mul(mat_zz_pE & X,const mat_zz_pE & A,const mat_zz_pE & B)76 void mul(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B)
77 {
78 if (&X == &A || &X == &B) {
79 mat_zz_pE tmp;
80 mul_aux(tmp, A, B);
81 X = tmp;
82 }
83 else
84 mul_aux(X, A, B);
85 }
86
87
inv(zz_pE & d,Mat<zz_pE> & X,const Mat<zz_pE> & A)88 void inv(zz_pE& d, Mat<zz_pE>& X, const Mat<zz_pE>& A)
89 {
90 long n = A.NumRows();
91
92 if (A.NumCols() != n)
93 LogicError("inv: nonsquare matrix");
94
95 if (n == 0) {
96 set(d);
97 X.SetDims(0, 0);
98 return;
99 }
100
101 const zz_pXModulus& G = zz_pE::modulus();
102
103 zz_pX t1, t2;
104 zz_pX pivot;
105 zz_pX pivot_inv;
106
107 Vec< Vec<zz_pX> > M;
108 // scratch space
109
110 M.SetLength(n);
111 for (long i = 0; i < n; i++) {
112 M[i].SetLength(n);
113 for (long j = 0; j < n; j++) {
114 M[i][j].SetMaxLength(2*deg(G)-1);
115 M[i][j] = rep(A[i][j]);
116 }
117 }
118
119 zz_pX det;
120 det = 1;
121
122
123 Vec<long> P;
124 P.SetLength(n);
125 for (long k = 0; k < n; k++) P[k] = k;
126 // records swap operations
127
128
129 zz_pContext zz_p_context;
130 zz_p_context.save();
131 double sz = zz_pE_SizeInWords();
132
133 bool seq = double(n)*double(n)*sz*sz < PAR_THRESH;
134
135 bool pivoting = false;
136
137 for (long k = 0; k < n; k++) {
138
139 long pos = -1;
140
141 for (long i = k; i < n; i++) {
142 rem(pivot, M[i][k], G);
143 if (pivot != 0) {
144 InvMod(pivot_inv, pivot, G);
145 pos = i;
146 break;
147 }
148 }
149
150 if (pos != -1) {
151 if (k != pos) {
152 swap(M[pos], M[k]);
153 negate(det, det);
154 P[k] = pos;
155 pivoting = true;
156 }
157
158 MulMod(det, det, pivot, G);
159
160 {
161 // multiply row k by pivot_inv
162 zz_pX *y = &M[k][0];
163 for (long j = 0; j < n; j++) {
164 rem(t2, y[j], G);
165 MulMod(y[j], t2, pivot_inv, G);
166 }
167 y[k] = pivot_inv;
168 }
169
170
171 NTL_GEXEC_RANGE(seq, n, first, last)
172 NTL_IMPORT(n)
173 NTL_IMPORT(k)
174
175 zz_p_context.restore();
176
177 zz_pX *y = &M[k][0];
178 zz_pX t1, t2;
179
180 for (long i = first; i < last; i++) {
181 if (i == k) continue; // skip row k
182
183 zz_pX *x = &M[i][0];
184 rem(t1, x[k], G);
185 negate(t1, t1);
186 x[k] = 0;
187 if (t1 == 0) continue;
188
189 // add t1 * row k to row i
190 for (long j = 0; j < n; j++) {
191 mul(t2, y[j], t1);
192 add(x[j], x[j], t2);
193 }
194 }
195 NTL_GEXEC_RANGE_END
196 }
197 else {
198 clear(d);
199 return;
200 }
201 }
202
203 if (pivoting) {
204 // pivot colums, using reverse swap sequence
205
206 for (long i = 0; i < n; i++) {
207 zz_pX *x = &M[i][0];
208
209 for (long k = n-1; k >= 0; k--) {
210 long pos = P[k];
211 if (pos != k) swap(x[pos], x[k]);
212 }
213 }
214 }
215
216 X.SetDims(n, n);
217 for (long i = 0; i < n; i++)
218 for (long j = 0; j < n; j++)
219 conv(X[i][j], M[i][j]);
220
221 conv(d, det);
222 }
223
224 static
solve_impl(zz_pE & d,Vec<zz_pE> & X,const Mat<zz_pE> & A,const Vec<zz_pE> & b,bool trans)225 void solve_impl(zz_pE& d, Vec<zz_pE>& X,
226 const Mat<zz_pE>& A, const Vec<zz_pE>& b, bool trans)
227
228 {
229 long n = A.NumRows();
230 if (A.NumCols() != n)
231 LogicError("solve: nonsquare matrix");
232
233 if (b.length() != n)
234 LogicError("solve: dimension mismatch");
235
236 if (n == 0) {
237 set(d);
238 X.SetLength(0);
239 return;
240 }
241
242 zz_pX t1, t2;
243
244 const zz_pXModulus& G = zz_pE::modulus();
245
246 Vec< Vec<zz_pX> > M;
247
248 M.SetLength(n);
249
250 for (long i = 0; i < n; i++) {
251 M[i].SetLength(n+1);
252 for (long j = 0; j < n; j++) M[i][j].SetMaxLength(2*deg(G)-1);
253
254 if (trans)
255 for (long j = 0; j < n; j++) M[i][j] = rep(A[j][i]);
256 else
257 for (long j = 0; j < n; j++) M[i][j] = rep(A[i][j]);
258
259 M[i][n] = rep(b[i]);
260 }
261
262 zz_pX det;
263 set(det);
264
265 zz_pContext zz_p_context;
266 zz_p_context.save();
267 double sz = zz_pE_SizeInWords();
268
269 for (long k = 0; k < n; k++) {
270 long pos = -1;
271 for (long i = k; i < n; i++) {
272 rem(t1, M[i][k], G);
273 M[i][k] = t1;
274 if (pos == -1 && !IsZero(t1)) {
275 pos = i;
276 }
277 }
278
279 if (pos != -1) {
280 if (k != pos) {
281 swap(M[pos], M[k]);
282 negate(det, det);
283 }
284
285 MulMod(det, det, M[k][k], G);
286
287 // make M[k, k] == -1 mod G, and make row k reduced
288
289 InvMod(t1, M[k][k], G);
290 negate(t1, t1);
291 for (long j = k+1; j <= n; j++) {
292 rem(t2, M[k][j], G);
293 MulMod(M[k][j], t2, t1, G);
294 }
295
296 bool seq =
297 double(n-(k+1))*(n-(k+1))*sz*sz < PAR_THRESH;
298
299 NTL_GEXEC_RANGE(seq, n-(k+1), first, last)
300 NTL_IMPORT(n)
301 NTL_IMPORT(k)
302
303 zz_p_context.restore();
304
305 zz_pX t1, t2;
306
307 for (long ii = first; ii < last; ii++) {
308 long i = ii + k+1;
309
310 // M[i] = M[i] + M[k]*M[i,k]
311
312 t1 = M[i][k]; // this is already reduced
313
314 zz_pX *x = M[i].elts() + (k+1);
315 zz_pX *y = M[k].elts() + (k+1);
316
317 for (long j = k+1; j <= n; j++, x++, y++) {
318 // *x = *x + (*y)*t1
319
320 mul(t2, *y, t1);
321 add(*x, *x, t2);
322 }
323 }
324
325 NTL_GEXEC_RANGE_END
326
327 }
328 else {
329 clear(d);
330 return;
331 }
332 }
333
334 X.SetLength(n);
335 for (long i = n-1; i >= 0; i--) {
336 clear(t1);
337 for (long j = i+1; j < n; j++) {
338 mul(t2, rep(X[j]), M[i][j]);
339 add(t1, t1, t2);
340 }
341 sub(t1, t1, M[i][n]);
342 conv(X[i], t1);
343 }
344
345 conv(d, det);
346 }
347
348
solve(zz_pE & d,Vec<zz_pE> & x,const Mat<zz_pE> & A,const Vec<zz_pE> & b)349 void solve(zz_pE& d, Vec<zz_pE>& x,
350 const Mat<zz_pE>& A, const Vec<zz_pE>& b)
351 {
352 solve_impl(d, x, A, b, true);
353 }
354
solve(zz_pE & d,const Mat<zz_pE> & A,Vec<zz_pE> & x,const Vec<zz_pE> & b)355 void solve(zz_pE& d, const Mat<zz_pE>& A,
356 Vec<zz_pE>& x, const Vec<zz_pE>& b)
357 {
358 solve_impl(d, x, A, b, false);
359 }
360
361
362
gauss(Mat<zz_pE> & M_in,long w)363 long gauss(Mat<zz_pE>& M_in, long w)
364 {
365 zz_pX t1, t2;
366 zz_pX piv;
367
368 long n = M_in.NumRows();
369 long m = M_in.NumCols();
370
371 if (w < 0 || w > m)
372 LogicError("gauss: bad args");
373
374 const zz_pXModulus& G = zz_pE::modulus();
375
376 Vec< Vec<zz_pX> > M;
377
378 M.SetLength(n);
379 for (long i = 0; i < n; i++) {
380 M[i].SetLength(m);
381 for (long j = 0; j < m; j++) {
382 M[i][j].SetLength(2*deg(G)-1);
383 M[i][j] = rep(M_in[i][j]);
384 }
385 }
386
387 zz_pContext zz_p_context;
388 zz_p_context.save();
389 double sz = zz_pE_SizeInWords();
390
391 long l = 0;
392 for (long k = 0; k < w && l < n; k++) {
393
394 long pos = -1;
395 for (long i = l; i < n; i++) {
396 rem(t1, M[i][k], G);
397 M[i][k] = t1;
398 if (pos == -1 && !IsZero(t1)) {
399 pos = i;
400 }
401 }
402
403 if (pos != -1) {
404 swap(M[pos], M[l]);
405
406 InvMod(piv, M[l][k], G);
407 negate(piv, piv);
408
409 for (long j = k+1; j < m; j++) {
410 rem(M[l][j], M[l][j], G);
411 }
412
413 bool seq =
414 double(n-(l+1))*double(m-(k+1))*sz*sz < PAR_THRESH;
415
416 NTL_GEXEC_RANGE(seq, n-(l+1), first, last)
417 NTL_IMPORT(m)
418 NTL_IMPORT(k)
419 NTL_IMPORT(l)
420
421 zz_p_context.restore();
422
423 zz_pX t1, t2;
424
425
426 for (long ii = first; ii < last; ii++) {
427 long i = ii + l+1;
428
429 // M[i] = M[i] + M[l]*M[i,k]*piv
430
431 MulMod(t1, M[i][k], piv, G);
432
433 clear(M[i][k]);
434
435 zz_pX *x = M[i].elts() + (k+1);
436 zz_pX *y = M[l].elts() + (k+1);
437
438 for (long j = k+1; j < m; j++, x++, y++) {
439 // *x = *x + (*y)*t1
440
441 mul(t2, *y, t1);
442 add(t2, t2, *x);
443 *x = t2;
444 }
445 }
446
447 NTL_GEXEC_RANGE_END
448
449 l++;
450 }
451 }
452
453 for (long i = 0; i < n; i++)
454 for (long j = 0; j < m; j++)
455 conv(M_in[i][j], M[i][j]);
456
457 return l;
458 }
459
460
gauss(Mat<zz_pE> & M)461 long gauss(Mat<zz_pE>& M)
462 {
463 return gauss(M, M.NumCols());
464 }
465
image(Mat<zz_pE> & X,const Mat<zz_pE> & A)466 void image(Mat<zz_pE>& X, const Mat<zz_pE>& A)
467 {
468 Mat<zz_pE> M;
469 M = A;
470 long r = gauss(M);
471 M.SetDims(r, M.NumCols());
472 X = M;
473 }
474
475
476
kernel(Mat<zz_pE> & X,const Mat<zz_pE> & A)477 void kernel(Mat<zz_pE>& X, const Mat<zz_pE>& A)
478 {
479 long m = A.NumRows();
480 long n = A.NumCols();
481
482 const zz_pXModulus& G = zz_pE::modulus();
483
484 Mat<zz_pE> M;
485
486 transpose(M, A);
487 long r = gauss(M);
488
489 if (r == 0) {
490 ident(X, m);
491 return;
492 }
493
494 X.SetDims(m-r, m);
495
496 if (m-r == 0 || m == 0) return;
497
498
499 Vec<long> D;
500 D.SetLength(m);
501 for (long j = 0; j < m; j++) D[j] = -1;
502
503 Vec<zz_pE> inverses;
504 inverses.SetLength(m);
505
506 for (long i = 0, j = -1; i < r; i++) {
507 do {
508 j++;
509 } while (IsZero(M[i][j]));
510
511 D[j] = i;
512 inv(inverses[j], M[i][j]);
513 }
514
515 zz_pEContext zz_pE_context;
516 zz_pE_context.save();
517 zz_pContext zz_p_context;
518 zz_p_context.save();
519 double sz = zz_pE_SizeInWords();
520
521 bool seq =
522 double(m-r)*double(r)*double(r)*sz*sz < PAR_THRESH;
523
524 NTL_GEXEC_RANGE(seq, m-r, first, last)
525 NTL_IMPORT(m)
526 NTL_IMPORT(r)
527
528 zz_p_context.restore();
529 zz_pE_context.restore();
530
531 zz_pX t1, t2;
532 zz_pE T3;
533
534 for (long k = first; k < last; k++) {
535 Vec<zz_pE>& v = X[k];
536 long pos = 0;
537 for (long j = m-1; j >= 0; j--) {
538 if (D[j] == -1) {
539 if (pos == k)
540 set(v[j]);
541 else
542 clear(v[j]);
543 pos++;
544 }
545 else {
546 long i = D[j];
547
548 clear(t1);
549
550 for (long s = j+1; s < m; s++) {
551 mul(t2, rep(v[s]), rep(M[i][s]));
552 add(t1, t1, t2);
553 }
554
555 conv(T3, t1);
556 mul(T3, T3, inverses[j]);
557 negate(v[j], T3);
558 }
559 }
560 }
561
562 NTL_GEXEC_RANGE_END
563 }
564
565
566
567
568
determinant(zz_pE & d,const Mat<zz_pE> & M_in)569 void determinant(zz_pE& d, const Mat<zz_pE>& M_in)
570 {
571 zz_pX t1, t2;
572
573 const zz_pXModulus& G = zz_pE::modulus();
574
575 long n = M_in.NumRows();
576
577 if (M_in.NumCols() != n)
578 LogicError("determinant: nonsquare matrix");
579
580 if (n == 0) {
581 set(d);
582 return;
583 }
584
585 Vec< Vec<zz_pX> > M;
586
587 M.SetLength(n);
588 for (long i = 0; i < n; i++) {
589 M[i].SetLength(n);
590 for (long j = 0; j < n; j++) {
591 M[i][j].SetMaxLength(2*deg(G)-1);
592 M[i][j] = rep(M_in[i][j]);
593 }
594 }
595
596 zz_pX det;
597 set(det);
598
599 zz_pContext zz_p_context;
600 zz_p_context.save();
601 double sz = zz_pE_SizeInWords();
602
603 for (long k = 0; k < n; k++) {
604 long pos = -1;
605 for (long i = k; i < n; i++) {
606 rem(t1, M[i][k], G);
607 M[i][k] = t1;
608 if (pos == -1 && !IsZero(t1))
609 pos = i;
610 }
611
612 if (pos != -1) {
613 if (k != pos) {
614 swap(M[pos], M[k]);
615 negate(det, det);
616 }
617
618 MulMod(det, det, M[k][k], G);
619
620 // make M[k, k] == -1 mod G, and make row k reduced
621
622 InvMod(t1, M[k][k], G);
623 negate(t1, t1);
624 for (long j = k+1; j < n; j++) {
625 rem(t2, M[k][j], G);
626 MulMod(M[k][j], t2, t1, G);
627 }
628
629
630 bool seq =
631 double(n-(k+1))*(n-(k+1))*sz*sz < PAR_THRESH;
632
633 NTL_GEXEC_RANGE(seq, n-(k+1), first, last)
634 NTL_IMPORT(n)
635 NTL_IMPORT(k)
636
637 zz_p_context.restore();
638
639 zz_pX t1, t2;
640
641 for (long ii = first; ii < last; ii++) {
642 long i = ii + k+1;
643
644 // M[i] = M[i] + M[k]*M[i,k]
645
646 t1 = M[i][k]; // this is already reduced
647
648 zz_pX *x = M[i].elts() + (k+1);
649 zz_pX *y = M[k].elts() + (k+1);
650
651 for (long j = k+1; j < n; j++, x++, y++) {
652 // *x = *x + (*y)*t1
653
654 mul(t2, *y, t1);
655 add(*x, *x, t2);
656 }
657 }
658
659 NTL_GEXEC_RANGE_END
660
661 }
662 else {
663 clear(d);
664 return;
665 }
666 }
667
668 conv(d, det);
669 }
670
671
672 // ==========================================
673
674
675
676
677
add(mat_zz_pE & X,const mat_zz_pE & A,const mat_zz_pE & B)678 void add(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B)
679 {
680 long n = A.NumRows();
681 long m = A.NumCols();
682
683 if (B.NumRows() != n || B.NumCols() != m)
684 LogicError("matrix add: dimension mismatch");
685
686 X.SetDims(n, m);
687
688 long i, j;
689 for (i = 1; i <= n; i++)
690 for (j = 1; j <= m; j++)
691 add(X(i,j), A(i,j), B(i,j));
692 }
693
sub(mat_zz_pE & X,const mat_zz_pE & A,const mat_zz_pE & B)694 void sub(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B)
695 {
696 long n = A.NumRows();
697 long m = A.NumCols();
698
699 if (B.NumRows() != n || B.NumCols() != m)
700 LogicError("matrix sub: dimension mismatch");
701
702 X.SetDims(n, m);
703
704 long i, j;
705 for (i = 1; i <= n; i++)
706 for (j = 1; j <= m; j++)
707 sub(X(i,j), A(i,j), B(i,j));
708 }
709
negate(mat_zz_pE & X,const mat_zz_pE & A)710 void negate(mat_zz_pE& X, const mat_zz_pE& A)
711 {
712 long n = A.NumRows();
713 long m = A.NumCols();
714
715
716 X.SetDims(n, m);
717
718 long i, j;
719 for (i = 1; i <= n; i++)
720 for (j = 1; j <= m; j++)
721 negate(X(i,j), A(i,j));
722 }
723
724
725
726 static
mul_aux(vec_zz_pE & x,const mat_zz_pE & A,const vec_zz_pE & b)727 void mul_aux(vec_zz_pE& x, const mat_zz_pE& A, const vec_zz_pE& b)
728 {
729 long n = A.NumRows();
730 long l = A.NumCols();
731
732 if (l != b.length())
733 LogicError("matrix mul: dimension mismatch");
734
735 x.SetLength(n);
736
737 long i, k;
738 zz_pX acc, tmp;
739
740 for (i = 1; i <= n; i++) {
741 clear(acc);
742 for (k = 1; k <= l; k++) {
743 mul(tmp, rep(A(i,k)), rep(b(k)));
744 add(acc, acc, tmp);
745 }
746 conv(x(i), acc);
747 }
748 }
749
750
mul(vec_zz_pE & x,const mat_zz_pE & A,const vec_zz_pE & b)751 void mul(vec_zz_pE& x, const mat_zz_pE& A, const vec_zz_pE& b)
752 {
753 if (&b == &x || A.alias(x)) {
754 vec_zz_pE tmp;
755 mul_aux(tmp, A, b);
756 x = tmp;
757 }
758 else
759 mul_aux(x, A, b);
760 }
761
762 static
mul_aux(vec_zz_pE & x,const vec_zz_pE & a,const mat_zz_pE & B)763 void mul_aux(vec_zz_pE& x, const vec_zz_pE& a, const mat_zz_pE& B)
764 {
765 long n = B.NumRows();
766 long l = B.NumCols();
767
768 if (n != a.length())
769 LogicError("matrix mul: dimension mismatch");
770
771 x.SetLength(l);
772
773 long i, k;
774 zz_pX acc, tmp;
775
776 for (i = 1; i <= l; i++) {
777 clear(acc);
778 for (k = 1; k <= n; k++) {
779 mul(tmp, rep(a(k)), rep(B(k,i)));
780 add(acc, acc, tmp);
781 }
782 conv(x(i), acc);
783 }
784 }
785
mul(vec_zz_pE & x,const vec_zz_pE & a,const mat_zz_pE & B)786 void mul(vec_zz_pE& x, const vec_zz_pE& a, const mat_zz_pE& B)
787 {
788 if (&a == &x) {
789 vec_zz_pE tmp;
790 mul_aux(tmp, a, B);
791 x = tmp;
792 }
793 else
794 mul_aux(x, a, B);
795
796 }
797
798
799
ident(mat_zz_pE & X,long n)800 void ident(mat_zz_pE& X, long n)
801 {
802 X.SetDims(n, n);
803 long i, j;
804
805 for (i = 1; i <= n; i++)
806 for (j = 1; j <= n; j++)
807 if (i == j)
808 set(X(i, j));
809 else
810 clear(X(i, j));
811 }
812
813
814
IsIdent(const mat_zz_pE & A,long n)815 long IsIdent(const mat_zz_pE& A, long n)
816 {
817 if (A.NumRows() != n || A.NumCols() != n)
818 return 0;
819
820 long i, j;
821
822 for (i = 1; i <= n; i++)
823 for (j = 1; j <= n; j++)
824 if (i != j) {
825 if (!IsZero(A(i, j))) return 0;
826 }
827 else {
828 if (!IsOne(A(i, j))) return 0;
829 }
830
831 return 1;
832 }
833
834
transpose(mat_zz_pE & X,const mat_zz_pE & A)835 void transpose(mat_zz_pE& X, const mat_zz_pE& A)
836 {
837 long n = A.NumRows();
838 long m = A.NumCols();
839
840 long i, j;
841
842 if (&X == & A) {
843 if (n == m)
844 for (i = 1; i <= n; i++)
845 for (j = i+1; j <= n; j++)
846 swap(X(i, j), X(j, i));
847 else {
848 mat_zz_pE tmp;
849 tmp.SetDims(m, n);
850 for (i = 1; i <= n; i++)
851 for (j = 1; j <= m; j++)
852 tmp(j, i) = A(i, j);
853 X.kill();
854 X = tmp;
855 }
856 }
857 else {
858 X.SetDims(m, n);
859 for (i = 1; i <= n; i++)
860 for (j = 1; j <= m; j++)
861 X(j, i) = A(i, j);
862 }
863 }
864
865
866
mul(mat_zz_pE & X,const mat_zz_pE & A,const zz_pE & b_in)867 void mul(mat_zz_pE& X, const mat_zz_pE& A, const zz_pE& b_in)
868 {
869 zz_pE b = b_in;
870 long n = A.NumRows();
871 long m = A.NumCols();
872
873 X.SetDims(n, m);
874
875 long i, j;
876 for (i = 0; i < n; i++)
877 for (j = 0; j < m; j++)
878 mul(X[i][j], A[i][j], b);
879 }
880
mul(mat_zz_pE & X,const mat_zz_pE & A,const zz_p & b_in)881 void mul(mat_zz_pE& X, const mat_zz_pE& A, const zz_p& b_in)
882 {
883 NTL_zz_pRegister(b);
884 b = b_in;
885 long n = A.NumRows();
886 long m = A.NumCols();
887
888 X.SetDims(n, m);
889
890 long i, j;
891 for (i = 0; i < n; i++)
892 for (j = 0; j < m; j++)
893 mul(X[i][j], A[i][j], b);
894 }
895
mul(mat_zz_pE & X,const mat_zz_pE & A,long b_in)896 void mul(mat_zz_pE& X, const mat_zz_pE& A, long b_in)
897 {
898 NTL_zz_pRegister(b);
899 b = b_in;
900 long n = A.NumRows();
901 long m = A.NumCols();
902
903 X.SetDims(n, m);
904
905 long i, j;
906 for (i = 0; i < n; i++)
907 for (j = 0; j < m; j++)
908 mul(X[i][j], A[i][j], b);
909 }
910
diag(mat_zz_pE & X,long n,const zz_pE & d_in)911 void diag(mat_zz_pE& X, long n, const zz_pE& d_in)
912 {
913 zz_pE d = d_in;
914 X.SetDims(n, n);
915 long i, j;
916
917 for (i = 1; i <= n; i++)
918 for (j = 1; j <= n; j++)
919 if (i == j)
920 X(i, j) = d;
921 else
922 clear(X(i, j));
923 }
924
IsDiag(const mat_zz_pE & A,long n,const zz_pE & d)925 long IsDiag(const mat_zz_pE& A, long n, const zz_pE& d)
926 {
927 if (A.NumRows() != n || A.NumCols() != n)
928 return 0;
929
930 long i, j;
931
932 for (i = 1; i <= n; i++)
933 for (j = 1; j <= n; j++)
934 if (i != j) {
935 if (!IsZero(A(i, j))) return 0;
936 }
937 else {
938 if (A(i, j) != d) return 0;
939 }
940
941 return 1;
942 }
943
944
IsZero(const mat_zz_pE & a)945 long IsZero(const mat_zz_pE& a)
946 {
947 long n = a.NumRows();
948 long i;
949
950 for (i = 0; i < n; i++)
951 if (!IsZero(a[i]))
952 return 0;
953
954 return 1;
955 }
956
clear(mat_zz_pE & x)957 void clear(mat_zz_pE& x)
958 {
959 long n = x.NumRows();
960 long i;
961 for (i = 0; i < n; i++)
962 clear(x[i]);
963 }
964
965
operator +(const mat_zz_pE & a,const mat_zz_pE & b)966 mat_zz_pE operator+(const mat_zz_pE& a, const mat_zz_pE& b)
967 {
968 mat_zz_pE res;
969 add(res, a, b);
970 NTL_OPT_RETURN(mat_zz_pE, res);
971 }
972
operator *(const mat_zz_pE & a,const mat_zz_pE & b)973 mat_zz_pE operator*(const mat_zz_pE& a, const mat_zz_pE& b)
974 {
975 mat_zz_pE res;
976 mul_aux(res, a, b);
977 NTL_OPT_RETURN(mat_zz_pE, res);
978 }
979
operator -(const mat_zz_pE & a,const mat_zz_pE & b)980 mat_zz_pE operator-(const mat_zz_pE& a, const mat_zz_pE& b)
981 {
982 mat_zz_pE res;
983 sub(res, a, b);
984 NTL_OPT_RETURN(mat_zz_pE, res);
985 }
986
987
operator -(const mat_zz_pE & a)988 mat_zz_pE operator-(const mat_zz_pE& a)
989 {
990 mat_zz_pE res;
991 negate(res, a);
992 NTL_OPT_RETURN(mat_zz_pE, res);
993 }
994
995
operator *(const mat_zz_pE & a,const vec_zz_pE & b)996 vec_zz_pE operator*(const mat_zz_pE& a, const vec_zz_pE& b)
997 {
998 vec_zz_pE res;
999 mul_aux(res, a, b);
1000 NTL_OPT_RETURN(vec_zz_pE, res);
1001 }
1002
operator *(const vec_zz_pE & a,const mat_zz_pE & b)1003 vec_zz_pE operator*(const vec_zz_pE& a, const mat_zz_pE& b)
1004 {
1005 vec_zz_pE res;
1006 mul_aux(res, a, b);
1007 NTL_OPT_RETURN(vec_zz_pE, res);
1008 }
1009
inv(mat_zz_pE & X,const mat_zz_pE & A)1010 void inv(mat_zz_pE& X, const mat_zz_pE& A)
1011 {
1012 zz_pE d;
1013 inv(d, X, A);
1014 if (d == 0) ArithmeticError("inv: non-invertible matrix");
1015 }
1016
power(mat_zz_pE & X,const mat_zz_pE & A,const ZZ & e)1017 void power(mat_zz_pE& X, const mat_zz_pE& A, const ZZ& e)
1018 {
1019 if (A.NumRows() != A.NumCols()) LogicError("power: non-square matrix");
1020
1021 if (e == 0) {
1022 ident(X, A.NumRows());
1023 return;
1024 }
1025
1026 mat_zz_pE T1, T2;
1027 long i, k;
1028
1029 k = NumBits(e);
1030 T1 = A;
1031
1032 for (i = k-2; i >= 0; i--) {
1033 sqr(T2, T1);
1034 if (bit(e, i))
1035 mul(T1, T2, A);
1036 else
1037 T1 = T2;
1038 }
1039
1040 if (e < 0)
1041 inv(X, T1);
1042 else
1043 X = T1;
1044 }
1045
random(mat_zz_pE & x,long n,long m)1046 void random(mat_zz_pE& x, long n, long m)
1047 {
1048 x.SetDims(n, m);
1049 for (long i = 0; i < n; i++) random(x[i], m);
1050 }
1051
1052 NTL_END_IMPL
1053