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