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| &lt;= 1 and |x| &lt;= 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| &lt;= 1 and |x| &lt;= 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