householder.h
Go to the documentation of this file.
1/* Copyright (C) 2005-2008 Damien Stehle.
2 Copyright (C) 2007 David Cade.
3 Copyright (C) 2011 Xavier Pujol.
4 Copyright (C) 2017-1018 Laurent Grémy.
5
6 This file is part of fplll. fplll is free software: you
7 can redistribute it and/or modify it under the terms of the GNU Lesser
8 General Public License as published by the Free Software Foundation,
9 either version 2.1 of the License, or (at your option) any later version.
10
11 fplll is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with fplll. If not, see <http://www.gnu.org/licenses/>. */
18
19#ifndef FPLLL_HOUSEHOLDER_H
20#define FPLLL_HOUSEHOLDER_H
21
22#include "nr/matrix.h"
23
25
27{
29 // We consider that using ROW_EXPO is mandatory if FT in {double, long double, qd, dd}.
32};
33
38template <class ZT, class FT> class MatHouseholder
39{
40public:
70 MatHouseholder(Matrix<ZT> &arg_b, Matrix<ZT> &arg_u, Matrix<ZT> &arg_uinv_t, int flags)
71 : b(arg_b), enable_row_expo(flags & HOUSEHOLDER_ROW_EXPO),
72 enable_transform(arg_u.get_rows() > 0), u(arg_u),
73 enable_inverse_transform(arg_uinv_t.get_rows() > 0), u_inv_t(arg_uinv_t),
74 row_op_force_long(flags & HOUSEHOLDER_OP_FORCE_LONG)
75 {
76 // Get the dimensions of the lattice
77 d = b.get_rows();
78 n = b.get_cols();
79
80 // Any row are known
81 n_known_rows = 0;
82 n_known_cols = 0;
83
84 // Initialize sigma and V used to compute R
85 sigma.resize(d);
86 R.resize(d, n);
87 // TODO: V does not need to be a matrix, since V is a list of vector of different length
88 V.resize(d, n);
89
90 // Initialize bf
91 bf.resize(d, n);
92
93 // Initialize row_expo.
94 row_expo.resize(d);
95 fill(row_expo.begin(), row_expo.end(), 0);
96 // Initialize row_size
97 init_row_size.resize(d);
98 for (int i = 0; i < d; i++)
99 // Capture the shape of b
100 init_row_size[i] = max(b[i].size_nz(), 1);
101
102 // Initialize R_history and update_R
103 R_history.resize(d);
104 for (int i = 0; i < d; i++)
105 {
106 R_history[i].resize(n);
107 for (int j = 0; j < n; j++)
108 R_history[i][j].resize(n);
109 }
110 updated_R = false;
111
112 // Initialize norm_square_b
113 norm_square_b.resize(d);
114 expo_norm_square_b.resize(d);
115 /* fill row_expo with 0, since if enable_row_expo, it will be filled by real value, and
116 * otherwise, we essentially 0 - 0 */
117 fill(expo_norm_square_b.begin(), expo_norm_square_b.end(), 0);
118
119#ifdef HOUSEHOLDER_PRECOMPUTE_INVERSE
120 // Initialize R_inverse_diag
121 R_inverse_diag.resize(d);
122#endif // HOUSEHOLDER_PRECOMPUTE_INVERSE
123
124 if (enable_row_expo)
125 // Initialize tmp_col_expo
126 tmp_col_expo.resize(n);
127
128#ifdef DEBUG
129 col_kept.resize(d);
130 fill(col_kept.begin(), col_kept.end(), false);
131#endif // DEBUG
132
133 /* Initialize values for naively part of the computation
134 * Used in is_hlll_reduced at least */
135 n_known_rows_naively = 0;
136 sigma_naively.resize(d);
137 R_naively.resize(d, n);
138 V_naively.resize(d, n);
139 row_expo_naively.resize(d);
140 fill(row_expo_naively.begin(), row_expo_naively.end(), 0);
141
142#ifdef DEBUG
143 for (int i = 0; i < d; i++)
144 {
145 for (int j = 0; j < n; j++)
146 {
147 V(i, j).set_nan();
148 V_naively(i, j).set_nan();
149 }
150 }
151#endif // DEBUG
152 }
153
155
161 inline void get_R(FT &f, int i, int j, long &expo);
162
168 inline void get_R(FT &f, int i, int j);
169
173 inline MatrixRow<FT> get_R(int i, long &expo);
174
179 const Matrix<FT> &get_R(vector<long> &expo)
180 {
181 expo = row_expo;
182 return R;
183 }
184
188 MatrixRow<ZT> get_b(int i);
189
193 const Matrix<ZT> &get_b() { return b; }
194
199 void update_R(int i, bool last_j);
200
204 void update_R(int i);
205
209 void update_R_last(int i);
210
214 inline void update_R();
215
219 inline int get_d() { return d; }
220 inline int get_n() { return n; }
221
225 inline void norm_square_b_row(FT &f, int k, long &expo);
226
230 inline void norm_square_R_row(FT &f, int k, int beg, int end, long &expo);
231
235 inline void norm_R_row(FT &f, int k, int beg, int end, long &expo);
236
237 // Size reduce b[k] with b[size_reduction_start..size_reduction_end-1].
238 // Not necessary to make transformation on bf, since basically, after each size_reduce, we call
239 // refresh_R_bf, which set bf to the correct value from b directly.
240 bool size_reduce(int k, int size_reduction_end, int size_reduction_start = 0);
241
247 void swap(int i, int j);
248
252 inline void invalidate_row(int k);
253
257 inline bool is_enable_row_expo() { return enable_row_expo; }
258
262 inline bool get_updated_R() { return updated_R; }
267 inline void set_updated_R_false() { updated_R = false; }
268
272 inline FT get_R_inverse_diag(int i) { return R_inverse_diag[i]; }
273
274 /*
275 * Recover R[i] from the precomputed values of R stored in R_history, i.e., R[i] is correct for
276 * the coefficients [0,
277 * i) and a call to update_R_last(i) will fully compute R[i].
278 */
279 inline void recover_R(int i);
280
284 inline long get_row_expo(int i) { return row_expo[i]; }
285
289 inline bool is_row_op_force_long() { return row_op_force_long; }
290
295 void refresh_R_bf(int i);
300 inline void refresh_R_bf();
301
305 void refresh_R(int i);
309 inline void refresh_R();
310
315 inline void get_norm_square_b(FT &f, int i, long &expo);
316
317private:
321 int d;
322
326 int n;
327
331 Matrix<ZT> &b;
332
337 Matrix<FT> R;
338
342 Matrix<FT> V;
343
347 vector<FT> sigma;
348
352 int n_known_rows;
353
355 const bool enable_row_expo;
356
361 vector<long> row_expo;
362
363 /* Used by update_R. Temporary variable. */
364 vector<long> tmp_col_expo;
365
366 // Temporary variables
367 FT ftmp0, ftmp1, ftmp2, ftmp3;
368 ZT ztmp0, ztmp1;
369
370 // init_row_size[i] = (last non-zero column in the i-th row of b) + 1
371 vector<int> init_row_size;
372 // n_known_cols (last non-zero column of the discovered rows) + 1
373 int n_known_cols;
374
384 void row_addmul_we(int i, int j, const FT &x, long expo_add);
388 void row_add(int i, int j);
389 void row_sub(int i, int j);
390 void row_addmul_si(int i, int j, long x);
391 void row_addmul_si_2exp(int i, int j, long x, long expo);
392 void row_addmul_2exp(int i, int j, const ZT &x, long expo);
393
397 Matrix<FT> bf;
398
403 vector<vector<vector<FT>>> R_history;
404
405 // If updated_R, R[n_known_rows][0] to R[n_known_rows][n_known_rows - 1] is valid
406 bool updated_R;
407
408 // Stores at index i the inverse of R(i, i)
409 vector<FT> R_inverse_diag;
410
411 // Compute the unimodular matrix u
412 const bool enable_transform;
413
414 Matrix<ZT> &u; // Transform
415
421 const bool enable_inverse_transform;
422
423 Matrix<ZT> &u_inv_t; // Transposed inverse transform
424
429 const bool row_op_force_long;
430
431 // Store the approximate norm of b[i].
432 vector<FT> norm_square_b;
433 // If enable_row_expo, ||b[i]||^2 = norm_square_b[i] * 2^{expo_norm_square_b}
434 vector<long> expo_norm_square_b;
435
436 // As in hplll. This variable is only used for check with DEBUG.
437 // If col_kept[k] = true, b[k] has not changed since last time we use it.
438 vector<bool> col_kept;
439
440 /* Objects and methods for the naive computation of the R factor using Householder. */
441
442public:
446 void update_R_naively();
447
451 void update_R_naively(int i);
452
456 inline void get_R_naively(FT &f, int i, int j, long &expo);
457
463 inline void norm_square_b_row_naively(FT &f, int k, long &expo);
464
468 inline void norm_square_R_row_naively(FT &f, int k, int end, long &expo);
469
470private:
475 Matrix<FT> R_naively;
476
480 Matrix<FT> V_naively;
481
485 vector<FT> sigma_naively;
486
491 vector<long> row_expo_naively;
492
496 int n_known_rows_naively;
497};
498
499template <class ZT, class FT>
500inline void MatHouseholder<ZT, FT>::get_R(FT &f, int i, int j, long &expo)
501{
502 get_R(f, i, j);
503 expo = row_expo[i];
504}
505
506template <class ZT, class FT> inline void MatHouseholder<ZT, FT>::get_R(FT &f, int i, int j)
507{
508 FPLLL_DEBUG_CHECK(i >= 0 && i < d && j >= 0 && j <= i);
509 f = R(i, j);
510}
511
512template <class ZT, class FT> inline MatrixRow<FT> MatHouseholder<ZT, FT>::get_R(int i, long &expo)
513{
514 FPLLL_DEBUG_CHECK(i >= 0 && i < d);
515 expo = row_expo[i];
516
517 return R[i];
518}
519
520template <class ZT, class FT> MatrixRow<ZT> MatHouseholder<ZT, FT>::get_b(int i)
521{
522 FPLLL_DEBUG_CHECK(i >= 0 && i < d);
523 return b[i];
524}
525
526template <class ZT, class FT> inline void MatHouseholder<ZT, FT>::update_R(int i)
527{
528 // last_j = true since we want the full computation of R[i]
529 update_R(i, true);
530}
531
532template <class ZT, class FT> inline void MatHouseholder<ZT, FT>::update_R()
533{
534 for (int i = 0; i < d; i++)
535 update_R(i);
536}
537
538template <class ZT, class FT>
539inline void MatHouseholder<ZT, FT>::norm_square_b_row(FT &f, int k, long &expo)
540{
541 FPLLL_DEBUG_CHECK(k >= 0 && k < d);
542
543 // TODO: maybe can be only dot_product(f, bf[k], n_known_rows). However, since the
544 // FPLLL_DEBUG_CHECK is more constraint, fall back to this version of dot_product
545 bf[k].dot_product(f, bf[k], 0, n_known_cols);
546
547 if (enable_row_expo)
548 expo = 2 * row_expo[k];
549 else
550 expo = 0;
551}
552
553template <class ZT, class FT>
554inline void MatHouseholder<ZT, FT>::norm_square_R_row(FT &f, int k, int beg, int end, long &expo)
555{
556 FPLLL_DEBUG_CHECK(k >= 0 && k < d);
557 FPLLL_DEBUG_CHECK(beg <= end);
558 FPLLL_DEBUG_CHECK(end <= k);
559 if (end == beg)
560 f = 0.0;
561 else
562 R[k].dot_product(f, R[k], beg, end);
563
564 if (enable_row_expo)
565 expo = 2 * row_expo[k];
566 else
567 expo = 0;
568}
569
570// TODO: maybe can merge some part of the code with norm_square_R_row?
571template <class ZT, class FT>
572inline void MatHouseholder<ZT, FT>::norm_R_row(FT &f, int k, int beg, int end, long &expo)
573{
574 FPLLL_DEBUG_CHECK(k >= 0 && k < d);
575 FPLLL_DEBUG_CHECK(beg <= end);
576 if (end == beg)
577 f = 0.0;
578 else
579 {
580 R[k].dot_product(f, R[k], beg, end);
581 f.sqrt(f);
582 }
583
584 if (enable_row_expo)
585 expo = row_expo[k];
586 else
587 expo = 0;
588}
589
590// TODO: test seems to be strange
591template <class ZT, class FT> inline void MatHouseholder<ZT, FT>::invalidate_row(int k)
592{
593 if (k < n_known_rows)
594 n_known_rows = k;
595}
596
597template <class ZT, class FT> inline void MatHouseholder<ZT, FT>::recover_R(int i)
598{
599 FPLLL_DEBUG_CHECK(col_kept[i] == true);
600
601 // TODO: these are row operations.
602 for (int k = 0; k < i - 1; k++)
603 R(i, k) = R_history[i][k][k];
604 for (int k = i - 1; k < n; k++)
605 R(i, k) = R_history[i][i - 1][k];
606
607 updated_R = true;
608}
609
610template <class ZT, class FT> inline void MatHouseholder<ZT, FT>::refresh_R_bf()
611{
612 for (int i = 0; i < d; i++)
613 refresh_R_bf(i);
614}
615
616template <class ZT, class FT> inline void MatHouseholder<ZT, FT>::refresh_R()
617{
618 for (int i = 0; i < d; i++)
619 refresh_R(i);
620}
621
622template <class ZT, class FT>
623inline void MatHouseholder<ZT, FT>::get_norm_square_b(FT &f, int i, long &expo)
624{
625 FPLLL_DEBUG_CHECK(i >= 0 && i < d);
626 expo = expo_norm_square_b[i];
627 f = norm_square_b[i];
628}
629
630/* Objects and methods for the naive computation of the R factor using Householder. */
631
632template <class ZT, class FT> inline void MatHouseholder<ZT, FT>::update_R_naively()
633{
634 for (int i = 0; i < d; i++)
635 update_R_naively(i);
636}
637
638template <class ZT, class FT>
639inline void MatHouseholder<ZT, FT>::get_R_naively(FT &f, int i, int j, long &expo)
640{
641 FPLLL_DEBUG_CHECK(i >= 0 && i < d && j >= 0 && j <= i);
642 f = R_naively(i, j);
643 expo = row_expo_naively[i];
644}
645
646template <class ZT, class FT>
647inline void MatHouseholder<ZT, FT>::norm_square_R_row_naively(FT &f, int k, int end, long &expo)
648{
649 FPLLL_DEBUG_CHECK(k >= 0 && k < d);
650 FPLLL_DEBUG_CHECK(0 <= end && end <= k);
651 if (end == 0)
652 f = 0.0;
653 else
654 // TODO: maybe can be only dot_product(f, R_naively[k], end). However, since the
655 // FPLLL_DEBUG_CHECK is more constraint, fall back to this version of dot_product
656 R_naively[k].dot_product(f, R_naively[k], 0, end);
657
658 if (enable_row_expo)
659 expo = 2 * row_expo_naively[k];
660 else
661 expo = 0;
662}
663
664template <class ZT, class FT>
665inline void MatHouseholder<ZT, FT>::norm_square_b_row_naively(FT &f, int k, long &expo)
666{
667 FPLLL_DEBUG_CHECK(k >= 0 && k < d);
668 if (enable_row_expo)
669 {
670 // TODO: maybe can be only dot_product(ztmp0, b[k], n). However, since the FPLLL_DEBUG_CHECK
671 // is more constraint, fall back to this version of dot_product. However, since it is n here,
672 // a problem with the check will probably not appear.
673 b[k].dot_product(ztmp0, b[k], 0, n);
674 ztmp0.get_f_exp(f, expo);
675 }
676 else
677 {
678 expo = 0;
679 // TODO: maybe can be only dot_product(ztmp0, b[k], n). However, since the FPLLL_DEBUG_CHECK
680 // is more constraint, fall back to this version of dot_product. However, since it is n here,
681 // a problem with the check will probably not appear.
682 b[k].dot_product(ztmp0, b[k], 0, n);
683 f.set_z(ztmp0);
684 }
685}
686
688
689#endif // FPLLL_HOUSEHOLDER_H
Definition: householder.h:39
bool get_updated_R()
Definition: householder.h:262
void update_R()
Definition: householder.h:532
bool size_reduce(int k, int size_reduction_end, int size_reduction_start=0)
Definition: householder.cpp:403
FT get_R_inverse_diag(int i)
Definition: householder.h:272
const Matrix< FT > & get_R(vector< long > &expo)
Definition: householder.h:179
void get_R(FT &f, int i, int j, long &expo)
Definition: householder.h:500
void norm_R_row(FT &f, int k, int beg, int end, long &expo)
Definition: householder.h:572
void norm_square_R_row_naively(FT &f, int k, int end, long &expo)
Definition: householder.h:647
void norm_square_R_row(FT &f, int k, int beg, int end, long &expo)
Definition: householder.h:554
void set_updated_R_false()
Definition: householder.h:267
int get_n()
Definition: householder.h:220
void get_norm_square_b(FT &f, int i, long &expo)
Definition: householder.h:623
void invalidate_row(int k)
Definition: householder.h:591
void swap(int i, int j)
Definition: householder.cpp:372
void recover_R(int i)
Definition: householder.h:597
bool is_row_op_force_long()
Definition: householder.h:289
~MatHouseholder()
Definition: householder.h:154
MatHouseholder(Matrix< ZT > &arg_b, Matrix< ZT > &arg_u, Matrix< ZT > &arg_uinv_t, int flags)
Definition: householder.h:70
int get_d()
Definition: householder.h:219
void norm_square_b_row(FT &f, int k, long &expo)
Definition: householder.h:539
void refresh_R()
Definition: householder.h:616
void refresh_R_bf()
Definition: householder.h:610
const Matrix< ZT > & get_b()
Definition: householder.h:193
void update_R_last(int i)
Definition: householder.cpp:27
long get_row_expo(int i)
Definition: householder.h:284
bool is_enable_row_expo()
Definition: householder.h:257
void get_R_naively(FT &f, int i, int j, long &expo)
Definition: householder.h:639
void update_R_naively()
Definition: householder.h:632
void norm_square_b_row_naively(FT &f, int k, long &expo)
Definition: householder.h:665
Definition: matrix.h:36
int get_cols() const
Definition: matrix.h:156
int get_rows() const
Definition: matrix.h:154
void resize(int rows, int cols)
Definition: matrix.cpp:26
#define FPLLL_END_NAMESPACE
Definition: defs.h:117
#define FPLLL_DEBUG_CHECK(x)
Definition: defs.h:109
#define FPLLL_BEGIN_NAMESPACE
Definition: defs.h:114
MatHouseholderFlags
Definition: householder.h:27
@ HOUSEHOLDER_OP_FORCE_LONG
Definition: householder.h:31
@ HOUSEHOLDER_DEFAULT
Definition: householder.h:28
@ HOUSEHOLDER_ROW_EXPO
Definition: householder.h:30