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_GSO_H
19 #define FPLLL_GSO_H
20
21 #include "gso_interface.h"
22 #include "nr/matrix.h"
23 #include "util.h"
24
25 FPLLL_BEGIN_NAMESPACE
26
27 /**
28 * MatGSO provides an interface for performing elementary operations on a basis
29 * and computing its Gram matrix and its Gram-Schmidt orthogonalization.
30 * The Gram-Schmidt coefficients are computed on demand. The object keeps track
31 * of which coefficients are valid after each row operation.
32 */
33 template <class ZT, class FT> class MatGSO : public MatGSOInterface<ZT, FT>
34 {
35 public:
36 using MatGSOInterface<ZT, FT>::d;
37 using MatGSOInterface<ZT, FT>::n_known_rows;
38 using MatGSOInterface<ZT, FT>::n_source_rows;
39 using MatGSOInterface<ZT, FT>::u;
40 using MatGSOInterface<ZT, FT>::enable_transform;
41 using MatGSOInterface<ZT, FT>::cols_locked; // maybe scratch.
42 using MatGSOInterface<ZT, FT>::enable_int_gram;
43 using MatGSOInterface<ZT, FT>::gso_valid_cols;
44 using MatGSOInterface<ZT, FT>::enable_inverse_transform;
45 using MatGSOInterface<ZT, FT>::u_inv_t;
46 using MatGSOInterface<ZT, FT>::sym_g;
47 using MatGSOInterface<ZT, FT>::mu;
48 using MatGSOInterface<ZT, FT>::r;
49 using MatGSOInterface<ZT, FT>::ztmp1;
50 using MatGSOInterface<ZT, FT>::ztmp2;
51 using MatGSOInterface<ZT, FT>::row_op_force_long;
52 using MatGSOInterface<ZT, FT>::alloc_dim;
53 using MatGSOInterface<ZT, FT>::get_mu;
54 using MatGSOInterface<ZT, FT>::get_r;
55 using MatGSOInterface<ZT, FT>::gptr;
56 using MatGSOInterface<ZT, FT>::invalidate_gso_row;
57 using MatGSOInterface<ZT, FT>::gf;
58 using MatGSOInterface<ZT, FT>::bf;
59 using MatGSOInterface<ZT, FT>::discover_all_rows;
60 using MatGSOInterface<ZT, FT>::init_row_size;
61 using MatGSOInterface<ZT, FT>::enable_row_expo;
62 using MatGSOInterface<ZT, FT>::row_expo;
63 using MatGSOInterface<ZT, FT>::n_known_cols;
64 using MatGSOInterface<ZT, FT>::tmp_col_expo;
65
66 using MatGSOInterface<ZT, FT>::remove_last_row;
67 using MatGSOInterface<ZT, FT>::print_mu_r_g;
68 using MatGSOInterface<ZT, FT>::update_gso;
69 using MatGSOInterface<ZT, FT>::update_gso_row;
70 using MatGSOInterface<ZT, FT>::row_addmul;
71 using MatGSOInterface<ZT, FT>::symmetrize_g;
72
73 #ifdef DEBUG
74 /* Used only in debug mode. */
75 using MatGSOInterface<ZT, FT>::row_op_first;
76 using MatGSOInterface<ZT, FT>::row_op_last;
77 using MatGSOInterface<ZT, FT>::in_row_op_range;
78 #endif
79
80 /**
81 * Constructor.
82 * The precision of FT must be defined before creating an instance of the
83 * class and must remain the same until the object is destroyed (or no longer
84 * needed).
85 * @param b
86 * The matrix on which row operations are performed. It must not be empty.
87 * @param u
88 * If u is not empty, operations on b are also done on u
89 * (in this case both must have the same number of rows).
90 * If u is initially the identity matrix, multiplying transform by the
91 * initial basis gives the current basis.
92 * @param u_inv_t
93 * Inverse transform (should be empty, which disables the computation, or
94 * initialized with identity matrix). It works only if u is not empty.
95 * @param enable_int_gram
96 * If true, coefficients of the Gram matrix are computed with exact integer
97 * arithmetic (type ZT). Otherwise, they are computed in floating-point
98 * (type FT). Note that when exact arithmetic is used, all coefficients of
99 * the first n_known_rows are continuously updated, whereas in floating-point,
100 * they are computed only on-demand. This option cannot be enabled if
101 * enable_row_expo=true.
102 * @param enable_row_expo
103 * If true, each row of b is normalized by a power of 2 before doing
104 * conversion to floating-point, which hopefully avoids some overflows.
105 * This option cannot be enabled if enable_int_gram=true and works only
106 * with FT=double and FT=long double. It is useless and MUST NOT be used
107 * for FT=dpe or FT=mpfr_t.
108 * @param row_op_force_long
109 * Affects the behaviour of row_addmul(_we).
110 * See the documentation of row_addmul.
111 */
MatGSO(Matrix<ZT> & arg_b,Matrix<ZT> & arg_u,Matrix<ZT> & arg_uinv_t,int flags)112 MatGSO(Matrix<ZT> &arg_b, Matrix<ZT> &arg_u, Matrix<ZT> &arg_uinv_t, int flags)
113 : MatGSOInterface<ZT, FT>(arg_u, arg_uinv_t, flags), b(arg_b)
114 {
115 FPLLL_DEBUG_CHECK(!(enable_int_gram && enable_row_expo));
116 d = b.get_rows();
117 if (enable_row_expo)
118 {
119 tmp_col_expo.resize(b.get_cols());
120 }
121 if (enable_int_gram)
122 {
123 gptr = &g;
124 }
125 size_increased();
126 #ifdef DEBUG
127 row_op_first = row_op_last = -1;
128 #endif
129 }
130
131 public:
132 /**
133 * Basis of the lattice
134 */
135 Matrix<ZT> &b;
136 /**
137 * Integer Gram matrix of the lattice
138 */
139 Matrix<ZT> g;
140
141 virtual inline ZT &sqnorm_coordinates(ZT &sqnorm, vector<ZT> coordinates);
142
143 virtual inline long get_max_exp_of_b();
144 virtual inline bool b_row_is_zero(int i);
145 virtual inline int get_cols_of_b();
146 virtual inline int get_rows_of_b();
147 virtual inline void negate_row_of_b(int i);
148
149 virtual inline void create_rows(int n_new_rows);
150 virtual inline void remove_last_rows(int n_removed_rows);
151
152 virtual void move_row(int old_r, int new_r);
153
154 /**
155 * b[i] := b[i] + x * b[j].
156 * After one or several calls to row_addmul, row_op_end must be called.
157 * Special cases |x| <= 1 and |x| <= LONG_MAX are optimized.
158 * x should be an integer.
159 * If row_op_force_long=true, x is always converted to (2^expo * long) instead
160 * of (2^expo * ZT), which is faster if ZT=mpz_t but might lead to a loss of
161 * precision (in LLL, more Babai iterations are needed).
162 */
163 // --> moved to interface
164 // virtual inline void row_addmul(int i, int j, const FT &x);
165
166 /**
167 * b[i] := b[i] + x * 2^expo_add * b[j].
168 * After one or several calls to row_addmul_we, row_op_end must be called.
169 * Special cases |x| <= 1 and |x| <= LONG_MAX are optimized.
170 * x should be an integer.
171 * If row_op_force_long=true, x is always converted to (2^expo * long) instead
172 * of (2^expo * ZT), which is faster if ZT=mpz_t but might lead to a loss of
173 * precision (in LLL, more Babai iterations are needed).
174 */
175 virtual void row_addmul_we(int i, int j, const FT &x, long expo_add);
176
177 // b[i] += b[j] / b[i] -= b[j] (i > j)
178 virtual void row_add(int i, int j);
179 virtual void row_sub(int i, int j);
180
181 // virtual inline void printparam(ostream &os);
182 virtual inline FT &get_gram(FT &f, int i, int j);
183
184 virtual inline ZT &get_int_gram(ZT &z, int i, int j);
185
186 // b[i] <-> b[j] (i < j)
187 virtual void row_swap(int i, int j);
188
189 private:
190 /* Allocates matrices and arrays whose size depends on d (all but tmp_col_expo).
191 When enable_int_gram=false, initializes bf. */
192 virtual void size_increased();
193
194 virtual void discover_row();
195
196 /* Upates the i-th row of bf. It does not invalidate anything, so the caller
197 must take into account that it might change row_expo. */
198 virtual void update_bf(int i);
199 /* Marks g(i, j) for all j <= i (but NOT for j > i) */
200 virtual void invalidate_gram_row(int i);
201
202 // b[i] <- b[i] + x * b[j] (i > j)
203 virtual void row_addmul_si(int i, int j, long x);
204 // b[i] <- b[i] + (2^expo * x) * b[j] (i > j)
205 virtual void row_addmul_si_2exp(int i, int j, long x, long expo);
206 virtual void row_addmul_2exp(int i, int j, const ZT &x, long expo);
207 };
208
209 template <class ZT, class FT>
sqnorm_coordinates(ZT & sqnorm,vector<ZT> coordinates)210 inline ZT &MatGSO<ZT, FT>::sqnorm_coordinates(ZT &sqnorm, vector<ZT> coordinates)
211 {
212 vector<ZT> tmpvec;
213 ZT tmp;
214 sqnorm = 0;
215 vector_matrix_product(tmpvec, coordinates, b);
216 for (int j = 0; j < b.get_rows(); j++)
217 {
218 tmp.mul(tmpvec[j], tmpvec[j]);
219 sqnorm.add(sqnorm, tmp);
220 }
221 return sqnorm;
222 }
223
get_max_exp_of_b()224 template <class ZT, class FT> inline long MatGSO<ZT, FT>::get_max_exp_of_b()
225 {
226 return b.get_max_exp();
227 }
228
b_row_is_zero(int i)229 template <class ZT, class FT> inline bool MatGSO<ZT, FT>::b_row_is_zero(int i)
230 {
231 return b[i].is_zero();
232 }
get_cols_of_b()233 template <class ZT, class FT> inline int MatGSO<ZT, FT>::get_cols_of_b() { return b.get_cols(); }
234
get_rows_of_b()235 template <class ZT, class FT> inline int MatGSO<ZT, FT>::get_rows_of_b() { return b.get_rows(); }
236
negate_row_of_b(int i)237 template <class ZT, class FT> inline void MatGSO<ZT, FT>::negate_row_of_b(int i)
238 {
239
240 for (int j = 0; j < get_cols_of_b(); j++)
241 {
242 b[i][j].neg(b[i][j]);
243 }
244 if (enable_int_gram)
245 {
246 for (int j = 0; j < get_rows_of_b(); j++)
247 {
248 if (j < i)
249 {
250 g(i, j).neg(g(i, j));
251 }
252 else if (j > i)
253 {
254 g(j, i).neg(g(j, i));
255 }
256 }
257 }
258 }
259
get_gram(FT & f,int i,int j)260 template <class ZT, class FT> inline FT &MatGSO<ZT, FT>::get_gram(FT &f, int i, int j)
261 {
262 FPLLL_DEBUG_CHECK(i >= 0 && i < n_known_rows && j >= 0 && j <= i && j < n_source_rows &&
263 !in_row_op_range(i));
264 if (enable_int_gram)
265 {
266 f.set_z(g(i, j));
267 }
268 else
269 {
270 if (gf(i, j).is_nan())
271 {
272 bf[i].dot_product(gf(i, j), bf[j], n_known_cols);
273 }
274 f = gf(i, j);
275 }
276 return f;
277 }
278
get_int_gram(ZT & z,int i,int j)279 template <class ZT, class FT> inline ZT &MatGSO<ZT, FT>::get_int_gram(ZT &z, int i, int j)
280 {
281 FPLLL_DEBUG_CHECK(i >= 0 && i < n_known_rows && j >= 0 && j <= i && j < n_source_rows &&
282 !in_row_op_range(i));
283 if (enable_int_gram)
284 {
285 z = g(i, j);
286 }
287 else
288 {
289
290 b[i].dot_product(z, b[j], n_known_cols);
291 }
292 return z;
293 }
294
create_rows(int n_new_rows)295 template <class ZT, class FT> inline void MatGSO<ZT, FT>::create_rows(int n_new_rows)
296 {
297 FPLLL_DEBUG_CHECK(!cols_locked);
298 int old_d = d;
299 d += n_new_rows;
300 b.set_rows(d);
301 for (int i = old_d; i < d; i++)
302 {
303 for (int j = 0; j < b.get_cols(); j++)
304 {
305 b[i][j] = 0;
306 }
307 }
308 if (enable_transform)
309 {
310 u.set_rows(d);
311 for (int i = old_d; i < d; i++)
312 for (int j = 0; j < u.get_cols(); j++)
313 u[i][j] = 0;
314 }
315 size_increased();
316 if (n_known_rows == old_d)
317 discover_all_rows();
318 }
319
remove_last_rows(int n_removed_rows)320 template <class ZT, class FT> inline void MatGSO<ZT, FT>::remove_last_rows(int n_removed_rows)
321 {
322 FPLLL_DEBUG_CHECK(!cols_locked && d >= n_removed_rows);
323 d -= n_removed_rows;
324 n_known_rows = min(n_known_rows, d);
325 n_source_rows = n_known_rows;
326 b.set_rows(d);
327 if (enable_transform)
328 u.set_rows(d);
329 }
330
331 FPLLL_END_NAMESPACE
332
333 #endif
334