/usr/include/fplll/pruner.h is in libfplll-dev 5.0.3-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 | #ifndef FPLLL_PRUNER_H
#define FPLLL_PRUNER_H
/* Copyright (C) 2015-2016 Martin Albrecht, Leo Ducas.
This file is part of fplll. fplll is free software: you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation,
either version 2.1 of the License, or (at your option) any later version.
fplll is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTAbILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with fplll. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "gso.h"
#include "bkz_param.h"
#include <array>
FPLLL_BEGIN_NAMESPACE
/**
This file provides an implementation of the numerically optimized pruning
strategy of [GNR10].
Many details for implementation follows from the thesis [Chen13] Some
simplifications have been made, for example we restrict ourselves to ``even
vector bounds'' i.e., the bound at indices 2i and 2i+1 are kept equal, as to
allow volume estimation by pure integration (see [GNR10,Chen13])
The current descent method use gradients, but alternative algorithms
(Nelder-Mead) May be added soon.
naming conventions:
- b is for bound (squared)
- ipv is for inverse partial volumes (NOT squared)
- r is for gram schmidt length (squared). Automatically renormalized to avoid
overflowing partial volumes
- p is for polynomial
inside this code, b,pv,and R are in reversed order as to conform with the
algorithm desciption of [Chen13] reversing the order is handled by the load
and save methods.
- n is for the dimension of the basis to prune
- d is for degrees of polynomials. md is for max_degree
- d is floor(n/2 at most). Odd n are dealt with by ignoring the first component
*/
#define PRUNER_MAX_PREC 1000
#define PRUNER_MAX_D 1023
#define PRUNER_MAX_N 2047
/**
@brief prune function, hiding the Pruner class
@param pr store pruning coefficients here
@param probability store success probability here
@param enumeration_radius target enumeration radius
@param preproc_cost cost of preprocessing
@param target_probability overall target success probability
@param m GSO matrix
@param method for the descent (gradient, NM, both)
@param start_row start enumeration here
@param end_row stop enumeration here
*/
template <class FT, class GSO_ZT, class GSO_FT>
void prune(/*output*/ vector<double> &pr, double &probability,
/*inputs*/ const double enumeration_radius, const double preproc_cost,
const double target_probability, const MatGSO<GSO_ZT, GSO_FT> &m,
const int descent_method = PRUNER_METHOD_HYBRID, int start_row = 0, int end_row = 0);
/**
@brief prune function, hiding the Pruner class
@param pruning store pruning structure
@param probability store success probability here
@param enumeration_radius target enumeration radius
@param preproc_cost cost of preprocessing
@param target_probability overall target success probability
@param m GSO matrix
@param method for the descent (gradient, NM, both)
@param start_row start enumeration here
@param end_row stop enumeration here
@return Pruning object.
*/
template <class FT, class GSO_ZT, class GSO_FT>
Pruning prune(/*inputs*/ const double enumeration_radius, const double preproc_cost,
const double target_probability, MatGSO<GSO_ZT, GSO_FT> &m,
const int descent_method = PRUNER_METHOD_HYBRID, int start_row = 0, int end_row = 0);
/**
@brief prune function averaging over several bases
@param probability store success probability here
@param enumeration_radius target enumeration radius
@param preproc_cost cost of preprocessing
@param target_probability overall target success probability
@param m GSO matrices
@param start_row start enumeration here
@param end_row stop enumeration here
@return Pruning object.
*/
template <class FT, class GSO_ZT, class GSO_FT>
Pruning prune(/*inputs*/ const double enumeration_radius, const double preproc_cost,
const double target_probability, vector<MatGSO<GSO_ZT, GSO_FT> > &m,
const int descent_method = PRUNER_METHOD_HYBRID, int start_row = 0, int end_row = 0);
/**
@brief svp_probability function, hiding the Pruner class
@param pruning
@return pruning probability
*/
template <class FT>
double svp_probability(const Pruning &pruning);
template <class FT>
double svp_probability(const vector<double> &pr);
template <class FT> class Pruner
{
public:
class TestPruner;
friend class TestPruner;
/** @brief enumeration radius (squared) */
FT enumeration_radius;
/** @brief cost of pre-processing a basis for a retrial
This cost should be expressed in terms of ``nodes'' in an enumeration.
Roughly, a node is equivalent to 100 CPU cycles.
*/
FT preproc_cost;
/** @brief desired success probability after several retrial
@note one can try to force probability >= target_probability by setting
a prohibitive preproc_cost. But beware: this may induces numerical
stability issue, especially with the gradient method.
*/
FT target_probability;
int verbosity = 0;
int descent_method;
Pruner(FT enumeration_radius=0.0, FT preproc_cost=0.0, FT target_probability=0.9, int descent_method = PRUNER_METHOD_HYBRID, size_t n=0, size_t d=0):
enumeration_radius(enumeration_radius),
preproc_cost(preproc_cost),
target_probability(target_probability),
descent_method(descent_method),
n(n),
d(d)
{
set_tabulated_consts();
epsilon = std::pow(2., -13); // Guesswork. Will become obsolete with Nelder-Mead
min_step = std::pow(2., -12); // Guesswork. Will become obsolete with Nelder-Mead
step_factor = std::pow(2, .5); // Guesswork. Will become obsolete with Nelder-Mead
shell_ratio = .995; // This approximation means that SVP will in fact be approx-SVP with factor 1/.995. Sounds fair.
min_cf_decrease = .9999; // We really want the gradient descent to reach the minima
symmetry_factor = 2; // For now, we are just considering SVP
}
/** @brief load the shape of a basis from a MatGSO object. Can select a
projected sub-lattice [start_row,end_row-1]
*/
template <class GSO_ZT, class GSO_FT>
void load_basis_shape(MatGSO<GSO_ZT, GSO_FT> &gso, int start_row = 0, int end_row = 0, int reset_renorm = 1);
/** @brief load the shapes of several bases from a MatGSO object. Can select a
projected sub-lattice [start_row,end_row-1]
*/
template <class GSO_ZT, class GSO_FT>
void load_basis_shapes(vector<MatGSO<GSO_ZT, GSO_FT> > &gsos, int start_row = 0, int end_row = 0);
/** @brief load the shape of a basis from vector<double>. Mostly for testing purposes */
void load_basis_shape(const vector<double> &gso_sq_norms, int reset_renorm = 1);
/** @brief load the shapes of may bases from vector<vector<double>> . Cost are average over all bases. Mostly for testing purposes */
void load_basis_shapes(const vector<vector<double> > &gso_sq_norms_vec);
/** @brief optimize pruning coefficients
@note Basis Shape and other parameters must have been set beforehand. See
auto_prune for an example of proper usage.
*/
void optimize_coefficients(/*io*/ vector<double> &pr, /*i*/ const int reset = 1);
/** @brief Compute the cost of a single enumeration */
double single_enum_cost(/*i*/ const vector<double> &pr) {
evec b;
load_coefficients(b, pr);
return single_enum_cost(b).get_d();
}
/** @brief Compute the cost of r enumeration and (r-1) preprocessing, where r
is the required number of retrials to reach target_probability
*/
double repeated_enum_cost(/*i*/ const vector<double> &pr) {
evec b;
load_coefficients(b, pr);
return repeated_enum_cost(b).get_d();
}
/**
@brief Compute the success proba of a single enumeration
*/
double svp_probability(/*i*/ const vector<double> &pr) {
if (!n){ // Can be called even if no basis has been loaded. In that case, set the dims
n = pr.size();
d = n / 2;
}
evec b;
load_coefficients(b, pr);
return svp_probability(b).get_d();
}
private:
using vec = array<FT, PRUNER_MAX_N>;
using evec = array<FT, PRUNER_MAX_D>;
// Even vectors, i.e. only one every two entry is stored: V[2i] = V[2i+1] =E[i]
using poly = array<FT, PRUNER_MAX_D + 1>;
// Load the constants for factorial and ball-volumes
void set_tabulated_consts();
size_t n; // Dimension of the (sub)-basis
size_t d; // Degree d = floor(n/2)
vec r; // Gram-Schmidt length (squared, inverted ordering)
vec ipv; // Partial volumes (inverted ordering)
FT renormalization_factor; // internal renormalization factor to avoid over/underflows
// Sanity check: has a basis indeed been loaded ?
int check_basis_loaded();
// Initialize pruning coefficients (linear pruning)
void init_coefficients(evec &b);
// Load pruning coefficient from double*
void load_coefficients(/*o*/ evec &b, /*i*/ const vector<double> &pr);
// Save pruning coefficients to double*
void save_coefficients(/*o*/ vector<double> &pr, /*i*/ const evec &b);
// Enforce reasonable contraints on pruning bounds (inside [0,1], increasing).
// Keeps index j unchanged when possible
int enforce_bounds(/*io*/ evec &b, /*opt i*/ const int j = 0);
// Evaluate a polynomial
FT eval_poly(const int ld, /*i*/ const poly &p, const FT x);
// Integrate a polynomial
void integrate_poly(const int ld, /*io*/ poly &p);
// Compute the relative volume of a cylinder interesection of dim rd, and bounds b[0:rd]
FT relative_volume(/*i*/ const int rd, const evec &b);
// Compute the cost of a single enumeration
FT single_enum_cost(/*i*/ const evec &b);
// Compute the success probability of a single enumeration
FT svp_probability(/*i*/ const evec &b);
// Compute the cost of r enumeration and (r-1) preprocessing,
// where r is the required number of retrials to reach target_probability
FT repeated_enum_cost(/*i*/ const evec &b);
// Compute the gradient of the above function
void repeated_enum_cost_gradient(/*i*/ const evec &b, /*o*/ evec &res);
// Improve the pruning bounds a bit, using one gradient step
int improve(/*io*/ evec &b);
// Improve the pruning bounds substantially, using Nelder-Mead method
int nelder_mead(/*io*/ evec &b);
// Run the whole escent to optimize pruning bounds
void descent(/*io*/ evec &b);
FT tabulated_factorial[PRUNER_MAX_N];
FT tabulated_ball_vol[PRUNER_MAX_N];
FT epsilon; //< Epsilon to use for numerical differentiation
FT min_step; //< Minimal step in a given direction
FT min_cf_decrease; //< Maximal ratio of two consectuive cf in the descent before stopping
FT step_factor; //< Increment factor for steps in a given direction
FT shell_ratio; //< Shell thickness Ratio when evaluating svp proba
FT symmetry_factor; //< Set at 2 for SVP enumeration assuming the implem only explore half the
//< space
};
FPLLL_END_NAMESPACE
#endif /* FPLLL_PRUNER_H */
|