1 /* Copyright (C) 2005-2008 Damien Stehle.
2    Copyright (C) 2007 David Cade.
3    Copyright (C) 2011 Xavier Pujol.
4 
5    This file is part of fplll. fplll is free software: you
6    can redistribute it and/or modify it under the terms of the GNU Lesser
7    General Public License as published by the Free Software Foundation,
8    either version 2.1 of the License, or (at your option) any later version.
9 
10    fplll is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13    GNU Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public License
16    along with fplll. If not, see <http://www.gnu.org/licenses/>. */
17 
18 #ifndef FPLLL_MATRIX_CPP
19 #define FPLLL_MATRIX_CPP
20 
21 #include "matrix.h"
22 #include "../defs.h"
23 
24 FPLLL_BEGIN_NAMESPACE
25 
resize(int rows,int cols)26 template <class T> void Matrix<T>::resize(int rows, int cols)
27 {
28   int old_size = matrix.size();
29   if (old_size < rows)
30   {
31     vector<NumVect<T>> m2(max(old_size * 2, rows));
32     for (int i = 0; i < old_size; i++)
33     {
34       matrix[i].swap(m2[i]);
35     }
36     matrix.swap(m2);
37   }
38   for (int i = r; i < rows; i++)
39   {
40     matrix[i].resize(cols);
41   }
42   if (cols != c)
43   {
44     for (int i = min(r, rows) - 1; i >= 0; i--)
45     {
46       matrix[i].resize(cols);
47     }
48   }
49   r    = rows;
50   c    = cols;
51   cols = c;
52 }
53 
fill(U value)54 template <class T> template <class U> void Matrix<T>::fill(U value)
55 {
56   for (int i = 0; i < r; i++)
57   {
58     for (int j = 0; j < c; j++)
59     {
60       matrix[i][j] = value;
61     }
62   }
63 }
64 
rotate_gram_left(int first,int last,int n_valid_rows)65 template <class T> void Matrix<T>::rotate_gram_left(int first, int last, int n_valid_rows)
66 {
67   FPLLL_DEBUG_CHECK(0 <= first && first <= last && last < n_valid_rows && n_valid_rows <= r);
68   matrix[first][first].swap(matrix[first][last]);
69   for (int i = first; i < last; i++)
70   {
71     matrix[i + 1][first].swap(matrix[first][i]);
72   }
73   for (int i = first; i < n_valid_rows; i++)
74   {
75     matrix[i].rotate_left(first, min(last, i));  // most expensive step
76   }
77   rotate_left(first, last);
78 }
79 
rotate_gram_right(int first,int last,int n_valid_rows)80 template <class T> void Matrix<T>::rotate_gram_right(int first, int last, int n_valid_rows)
81 {
82   FPLLL_DEBUG_CHECK(0 <= first && first <= last && last < n_valid_rows && n_valid_rows <= r);
83   rotate_right(first, last);
84   for (int i = first; i < n_valid_rows; i++)
85   {
86     matrix[i].rotate_right(first, min(last, i));  // most expensive step
87   }
88   for (int i = first; i < last; i++)
89   {
90     matrix[i + 1][first].swap(matrix[first][i]);
91   }
92   matrix[first][first].swap(matrix[first][last]);
93 }
94 
transpose()95 template <class T> void Matrix<T>::transpose()
96 {
97   extend_vect(matrix, c);
98   for (int i = 0; i < c; i++)
99   {
100     matrix[i].extend(r);
101   }
102   for (int i = 0; i < min(r, c); i++)
103   {
104     for (int j = i + 1; j < max(r, c); j++)
105     {
106       matrix[i][j].swap(matrix[j][i]);
107     }
108     if (c > r)
109       matrix[i].resize(r);
110   }
111   std::swap(r, c);
112 }
113 
get_max()114 template <class T> T Matrix<T>::get_max()
115 {
116   T m, a;
117   m = 0.0;
118   for (int i = 0; i < r; i++)
119     for (int j = 0; j < c; j++)
120     {
121       a.abs(matrix[i][j]);
122       m = max(m, a);
123     }
124   return m;
125 }
126 
get_max_exp()127 template <class T> long Matrix<T>::get_max_exp()
128 {
129   long max_exp = 0;
130   for (int i = 0; i < r; i++)
131     for (int j = 0; j < c; j++)
132       max_exp = max(max_exp, matrix[i][j].exponent());
133   return max_exp;
134 }
135 
print(ostream & os,int nrows,int ncols) const136 template <class T> void Matrix<T>::print(ostream &os, int nrows, int ncols) const
137 {
138   if (nrows < 0 || nrows > r)
139     nrows = r;
140   if (ncols < 0 || ncols > c)
141     ncols = c;
142   os << '[';
143   for (int i = 0; i < nrows; i++)
144   {
145     if (i > 0)
146       os << '\n';
147     os << '[';
148     for (int j = 0; j < ncols; j++)
149     {
150       if (j > 0)
151         os << ' ';
152       os << matrix[i][j];
153     }
154     if (print_mode == MAT_PRINT_REGULAR && ncols > 0)
155       os << ' ';
156     os << ']';
157   }
158   if (print_mode == MAT_PRINT_REGULAR && nrows > 0)
159     os << '\n';
160   os << ']';
161 }
162 
read(istream & is)163 template <class T> void Matrix<T>::read(istream &is)
164 {
165   char ch;
166   matrix.clear();
167   if (!(is >> ch))
168     return;
169   if (ch != '[')
170   {
171     is.setstate(ios::failbit);
172     return;
173   }
174   while (is >> ch && ch != ']')
175   {
176     is.putback(ch);
177     matrix.resize(matrix.size() + 1);
178     if (!(is >> matrix.back()))
179     {
180       matrix.pop_back();
181       break;
182     }
183   }
184 
185   r = matrix.size();
186   c = 0;
187   for (int i = 0; i < r; i++)
188   {
189     c = max(c, matrix[i].size());
190   }
191   for (int i = 0; i < r; i++)
192   {
193     int old_c = matrix[i].size();
194     if (old_c < c)
195     {
196       matrix[i].resize(c);
197       for (int j = old_c; j < c; j++)
198       {
199         matrix[i][j] = 0;
200       }
201     }
202   }
203 }
204 
print_comma(ostream & os) const205 template <class T> ostream &Matrix<T>::print_comma(ostream &os) const
206 {
207   os << '[';
208   for (int i = 0; i < r - 1; i++)
209   {
210     os << '[';
211     for (int j = 0; j < c - 1; j++)
212     {
213       os << matrix[i][j] << ", ";
214     }
215     os << matrix[i][c - 1] << "],\n";
216   }
217   os << '[';
218   for (int j = 0; j < c - 1; j++)
219   {
220     os << matrix[r - 1][j] << ", ";
221   }
222   os << matrix[r - 1][c - 1] << "]]\n";
223 
224   return os;
225 }
226 
227 /* ZZ_mat */
228 
gen_intrel(int bits)229 template <class ZT> inline void ZZ_mat<ZT>::gen_intrel(int bits)
230 {
231   if (c != r + 1)
232   {
233     FPLLL_ABORT("gen_intrel called on an ill-formed matrix");
234     return;
235   }
236   int i, j;
237   for (i = 0; i < r; i++)
238   {
239     matrix[i][0].randb(bits);
240     for (j = 1; j <= i; j++)
241     {
242       matrix[i][j] = 0;
243     }
244     matrix[i][i + 1] = 1;
245     for (j = i + 2; j < c; j++)
246     {
247       matrix[i][j] = 0;
248     }
249   }
250 }
251 
gen_simdioph(int bits,int bits2)252 template <class ZT> inline void ZZ_mat<ZT>::gen_simdioph(int bits, int bits2)
253 {
254   if (c != r)
255   {
256     FPLLL_ABORT("gen_simdioph called on an ill-formed matrix");
257     return;
258   }
259   int i, j;
260 
261   matrix[0][0] = 1;
262   matrix[0][0].mul_2si(matrix[0][0], bits2);
263   for (i = 1; i < r; i++)
264     matrix[0][i].randb(bits);
265   for (i = 1; i < r; i++)
266   {
267     for (j = 1; j < i; j++)
268       matrix[j][i] = 0;
269     matrix[i][i] = 1;
270     matrix[i][i].mul_2si(matrix[i][i], bits);
271     for (j = i + 1; j < c; j++)
272       matrix[j][i] = 0;
273   }
274 }
275 
gen_uniform(int bits)276 template <class ZT> inline void ZZ_mat<ZT>::gen_uniform(int bits)
277 {
278   if (c != r)
279   {
280     FPLLL_ABORT("gen_uniform called on an ill-formed matrix");
281     return;
282   }
283   for (int i = 0; i < r; i++)
284     for (int j = 0; j < c; j++)
285       matrix[i][j].randb(bits);
286 }
287 
gen_ntrulike(int bits)288 template <class ZT> inline void ZZ_mat<ZT>::gen_ntrulike(int bits)
289 {
290   // [A00 A01]
291   // [A10 A11]
292 
293   int i, j, k;
294   int d = r / 2;
295   if (c != r || c != 2 * d)
296   {
297     FPLLL_ABORT("gen_ntrulike called on an ill-formed matrix");
298     return;
299   }
300   // clang-format off
301   Z_NR<ZT> *h = new Z_NR<ZT>[d];
302   // clang-format on
303   Z_NR<ZT> q;
304 
305   q.randb(bits);
306   if (q.sgn() == 0)
307     q = 1;
308   h[0] = 0;
309   for (i = 1; i < d; i++)
310   {
311     h[i].randm(q);
312     h[0].sub(h[0], h[i]);
313     if (h[0].sgn() < 0)
314       h[0].add(h[0], q);
315     // set h0 such that h(1) = 0 mod q.
316   }
317 
318   // I in A00
319   for (i = 0; i < d; i++)
320   {
321     for (j = 0; j < i; j++)
322       matrix[i][j] = 0;
323     matrix[i][i] = 1;
324     for (j = i + 1; j < d; j++)
325       matrix[i][j] = 0;
326   }
327 
328   // 0 in A10
329   for (i = d; i < r; i++)
330   {
331     for (j = 0; j < d; j++)
332       matrix[i][j] = 0;
333   }
334   // qI in A11
335   for (i = d; i < r; i++)
336   {
337     for (j = d; j < i; j++)
338       matrix[i][j] = 0;
339     matrix[i][i] = q;
340     for (j = i + 1; j < c; j++)
341       matrix[i][j] = 0;
342   }
343   // H in A01
344   for (i = 0; i < d; i++)
345     for (j = d; j < c; j++)
346     {
347       k = j - d - i;
348       while (k < 0)
349       {
350         k += d;
351       }
352       matrix[i][j] = h[k];
353     }
354 
355   delete[] h;
356 }
357 
gen_ntrulike_withq(int q)358 template <class ZT> inline void ZZ_mat<ZT>::gen_ntrulike_withq(int q)
359 {
360   // Same as above, except q is specified by the user rather than chosen
361   // randomly with a prescribed bit-length.
362 
363   int i, j, k;
364   int d = r / 2;
365   if (c != r || c != 2 * d)
366   {
367     FPLLL_ABORT("gen_ntrulike called on an ill-formed matrix");
368     return;
369   }
370   // clang-format off
371   Z_NR<ZT> *h = new Z_NR<ZT>[d];
372   // clang-format on
373   Z_NR<ZT> q2;
374 
375   q2   = q;
376   h[0] = 0;
377   for (i = 1; i < d; i++)
378   {
379     h[i].randm(q2);
380     h[0].sub(h[0], h[i]);
381     if (h[0].sgn() < 0)
382       h[0].add(h[0], q2);
383     // set h0 such that h(1) = 0 mod q.
384   }
385 
386   // I in A00
387   for (i = 0; i < d; i++)
388   {
389     for (j = 0; j < i; j++)
390       matrix[i][j] = 0;
391     matrix[i][i] = 1;
392     for (j = i + 1; j < d; j++)
393       matrix[i][j] = 0;
394   }
395 
396   // 0 in A10
397   for (i = d; i < r; i++)
398   {
399     for (j = 0; j < d; j++)
400       matrix[i][j] = 0;
401   }
402   // qI in A11
403   for (i = d; i < r; i++)
404   {
405     for (j = d; j < i; j++)
406       matrix[i][j] = 0;
407     matrix[i][i] = q2;
408     for (j = i + 1; j < c; j++)
409       matrix[i][j] = 0;
410   }
411   // H in A01
412   for (i = 0; i < d; i++)
413     for (j = d; j < c; j++)
414     {
415       k = j - d - i;
416       while (k < 0)
417       {
418         k += d;
419       }
420       matrix[i][j] = h[k];
421     }
422 
423   delete[] h;
424 }
425 
gen_ntrulike2(int bits)426 template <class ZT> inline void ZZ_mat<ZT>::gen_ntrulike2(int bits)
427 {
428 
429   int i, j, k;
430   int d = r / 2;
431   if (c != r || c != 2 * d)
432   {
433     FPLLL_ABORT("gen_ntrulike2 called on an ill-formed matrix");
434     return;
435   }
436   // clang-format off
437   Z_NR<ZT> *h = new Z_NR<ZT>[d];
438   Z_NR<ZT> q;
439   // clang-format on
440 
441   q.randb(bits);
442   h[0] = 0;
443   for (i = 1; i < d; i++)
444   {
445     h[i].randm(q);
446     h[0].sub(h[0], h[i]);
447     if (h[0].sgn() < 0)
448       h[0].add(h[0], q);
449     // set h0 such that h(1) = 0 mod q.
450   }
451 
452   for (i = 0; i < d; i++)
453   {
454     for (j = 0; j < c; j++)
455       matrix[i][j] = 0;
456   }
457 
458   for (i = 0; i < d; i++)
459     matrix[i][i] = q;
460   for (i = d; i < r; i++)
461     for (j = d; j < c; j++)
462       matrix[i][j] = 0;
463   for (i = d; i < c; i++)
464     matrix[i][i] = 1;
465 
466   for (i = d; i < r; i++)
467   {
468     for (j = 0; j < d; j++)
469     {
470       k = i - d - j;
471       while (k < 0)
472       {
473         k += d;
474       }
475       matrix[i][j] = h[k];
476     }
477   }
478 
479   delete[] h;
480 }
481 
gen_ntrulike2_withq(int q)482 template <class ZT> inline void ZZ_mat<ZT>::gen_ntrulike2_withq(int q)
483 {
484 
485   int i, j, k;
486   int d = r / 2;
487   if (c != r || c != 2 * d)
488   {
489     FPLLL_ABORT("gen_ntrulike2 called on an ill-formed matrix");
490     return;
491   }
492   // clang-format off
493   Z_NR<ZT> *h = new Z_NR<ZT>[d];
494   Z_NR<ZT> q2;
495   // clang-format on
496 
497   q2   = q;
498   h[0] = 0;
499   for (i = 1; i < d; i++)
500   {
501     h[i].randm(q2);
502     h[0].sub(h[0], h[i]);
503     if (h[0].sgn() < 0)
504       h[0].add(h[0], q2);
505     // set h0 such that h(1) = 0 mod q.
506   }
507 
508   for (i = 0; i < d; i++)
509   {
510     for (j = 0; j < c; j++)
511       matrix[i][j] = 0;
512   }
513 
514   for (i = 0; i < d; i++)
515     matrix[i][i] = q2;
516   for (i = d; i < r; i++)
517     for (j = d; j < c; j++)
518       matrix[i][j] = 0;
519   for (i = d; i < c; i++)
520     matrix[i][i] = 1;
521 
522   for (i = d; i < r; i++)
523   {
524     for (j = 0; j < d; j++)
525     {
526       k = i - d - j;
527       while (k < 0)
528       {
529         k += d;
530       }
531       matrix[i][j] = h[k];
532     }
533   }
534 
535   delete[] h;
536 }
537 
gen_qary(int k,Z_NR<ZT> & q)538 template <class ZT> inline void ZZ_mat<ZT>::gen_qary(int k, Z_NR<ZT> &q)
539 {
540   int i, j;
541   int d = r;
542   if (c != r || k > r)
543   {
544     FPLLL_ABORT("gen_qary called on an ill-formed matrix");
545     return;
546   }
547 
548   for (i = 0; i < d - k; i++)
549     for (j = 0; j < d - k; j++)
550       matrix[i][j] = 0;
551 
552   for (i = 0; i < d - k; i++)
553     matrix[i][i] = 1;
554 
555   for (i = 0; i < d - k; i++)
556     for (j = d - k; j < d; j++)
557       matrix[i][j].randm(q);
558 
559   for (i = d - k; i < d; i++)
560     for (j = 0; j < d; j++)
561       matrix[i][j] = 0;
562 
563   for (i = d - k; i < d; i++)
564     matrix[i][i] = q;
565 }
566 
gen_trg(double alpha)567 template <class ZT> inline void ZZ_mat<ZT>::gen_trg(double alpha)
568 {
569   int i, j, bits;
570   Z_NR<ZT> ztmp, ztmp2, zone, sign;
571 
572   ztmp2 = 0;
573   zone  = 1;
574 
575   int d = r;
576   if (c != r)
577   {
578     FPLLL_ABORT("gen_trg called on an ill-formed matrix");
579     return;
580   }
581 
582   for (i = 0; i < d; i++)
583   {
584     bits = (int)pow((double)(2 * d - i), alpha);
585     ztmp = 1;
586     ztmp.mul_2si(ztmp, bits);
587     ztmp.sub(ztmp, zone);
588     matrix[i][i].randm(ztmp);
589     matrix[i][i].add_ui(matrix[i][i], 2);
590     ztmp.div_2si(matrix[i][i], 1);
591     for (j = i + 1; j < d; j++)
592     {
593       matrix[j][i].randm(ztmp);
594       sign.randb(1);
595       if (sign == 1)
596         matrix[j][i].sub(ztmp2, matrix[j][i]);
597       matrix[i][j] = 0;
598     }
599   }
600 }
601 
gen_trg2(FP_NR<mpfr_t> * w)602 template <class ZT> inline void ZZ_mat<ZT>::gen_trg2(FP_NR<mpfr_t> *w)
603 {
604   int i, j;
605   Z_NR<ZT> ztmp, ztmp2;
606 
607   int d = r;
608   if (c != r)
609   {
610     FPLLL_ABORT("gen_trg2 called on an ill-formed matrix");
611     return;
612   }
613 
614   for (i = 0; i < d; i++)
615   {
616     matrix[i][i].set_f(w[i]);
617     ztmp.div_2si(matrix[i][i], 1);
618     ztmp2 = 1;
619     ztmp.add(ztmp, ztmp2);
620     for (j = i + 1; j < d; j++)
621     {
622       ztmp2 = 0;
623       matrix[j][i].randm(ztmp);
624       if (rand() % 2 == 1)
625         matrix[j][i].sub(ztmp2, matrix[j][i]);
626       matrix[i][j] = 0;
627     }
628   }
629 }
630 
631 template <class ZTto, class ZTfrom>
convert(ZZ_mat<ZTto> & Ato,const ZZ_mat<ZTfrom> & Afrom,int buffer)632 bool convert(ZZ_mat<ZTto> &Ato, const ZZ_mat<ZTfrom> &Afrom, int buffer)
633 {
634   Ato.clear();
635   int r = Afrom.get_rows();
636   int c = Afrom.get_cols();
637   Ato.resize(r, c);
638   long threshold = (1L << (numeric_limits<long>::digits - buffer - 1));
639   Z_NR<ZTfrom> ztmp;
640   for (int i = 0; i < r; ++i)
641   {
642     for (int j = 0; j < c; ++j)
643     {
644       ztmp.abs(Afrom[i][j]);
645       if (ztmp > threshold)
646       {
647         return false;
648       }
649       Ato[i][j] = Afrom[i][j].get_si();
650     }
651   }
652 
653   return true;
654 }
655 
656 FPLLL_END_NAMESPACE
657 
658 #endif
659