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