pruner.h
Go to the documentation of this file.
1/* Copyright (C) 2015-2017 Martin Albrecht, Leo Ducas.
2 Copyright (C) 2018 Shi Bai
3
4 This file is part of fplll. fplll is free software: you
5 can redistribute it and/or modify it under the terms of the GNU Lesser
6 General Public License as published by the Free Software Foundation,
7 either version 2.1 of the License, or (at your option) any later version.
8
9 fplll is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTAbILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with fplll. If not, see <http://www.gnu.org/licenses/>. */
16
17#ifndef FPLLL_PRUNER_H
18#define FPLLL_PRUNER_H
19
20#include "fplll/defs.h"
21#include "fplll/lll.h"
22#include <vector>
23
25
26#define PRUNER_MAX_N 2047
27
32{
33
34public:
35 double gh_factor; //< radius^2/Gaussian heuristic^2
36 std::vector<double> coefficients; //< pruning coefficients
37 double expectation; //< either expected success probability or number of solutions
42 std::vector<double> detailed_cost; //< Expected nodes per level
43
48
55 static PruningParams LinearPruningParams(int block_size, int level);
56};
57
84template <class FT>
85int run_pruner_f(ZZ_mat<mpz_t> &B, int sel_ft, int precision = 0, int prune_start = 0,
86 int prune_end = 1, double prune_pre_nodes = 1e6, double prune_min_prob = -1,
87 double gh_factor = 1.0);
88
119int run_pruner(ZZ_mat<mpz_t> &B, FloatType float_type = FT_DEFAULT, int precision = 0,
120 int prune_start = 0, int prune_end = 1, double prune_pre_nodes = 1e6,
121 double prune_min_prob = -1, double gh_factor = 1.0);
122
187template <class FT>
188void prune(/*(input)output*/ PruningParams &pruning,
189 /*inputs*/
190 const double enumeration_radius, const double preproc_cost, const vector<double> &gso_r,
191 const double target = .9,
193 const int flags = PRUNER_GRADIENT);
194
214template <class FT>
215void prune(/*output*/ PruningParams &pruning,
216 /*inputs*/
217 double enumeration_radius, const double preproc_cost,
218 const vector<vector<double>> &gso_rs, const double target = .9,
220 const int flags = PRUNER_GRADIENT);
221
233template <class FT> FT svp_probability(const PruningParams &pruning);
234
243template <class FT> FT svp_probability(const vector<double> &pr);
244
272template <class FT> class Pruner
273{
274public:
275 class TestPruner;
276 friend class TestPruner;
277
282 explicit Pruner(const int n) : metric(PRUNER_METRIC_PROBABILITY_OF_SHORTEST), flags(0), n(n)
283 {
284 verbosity = flags & PRUNER_VERBOSE;
285 set_tabulated_consts();
286 d = n / 2;
287 min_pruning_coefficients.resize(d);
288 btmp.resize(d);
289 bftmp.resize(n);
290 fill(min_pruning_coefficients.begin(), min_pruning_coefficients.end(), 0.);
291 }
292
307 Pruner(const FT enumeration_radius, const FT preproc_cost, const vector<double> &gso_r,
308 const FT target = 0.9, const PrunerMetric metric = PRUNER_METRIC_PROBABILITY_OF_SHORTEST,
309 int flags = PRUNER_GRADIENT)
310 : enumeration_radius(enumeration_radius), preproc_cost(preproc_cost), target(target),
311 metric(metric), flags(flags)
312 {
313 verbosity = flags & PRUNER_VERBOSE;
314
315 n = gso_r.size();
316 d = n / 2;
317 if (flags & PRUNER_CVP)
318 {
319 symmetry_factor = 1;
320 }
321 min_pruning_coefficients.resize(d);
322 btmp.resize(d);
323 bftmp.resize(n);
324 fill(min_pruning_coefficients.begin(), min_pruning_coefficients.end(), 0.);
325 set_tabulated_consts();
326
327 // optimize overall cost, use
328 if (flags & PRUNER_SINGLE)
329 {
330 opt_single = true;
331 if (flags & PRUNER_HALF)
332 {
333 throw std::invalid_argument(
334 "Error: flags PRUNER_HALF and PRUNER_SINGLE are mutually exclusive.");
335 }
336 }
337
338 // need to fix target if possible
340 {
341 // check if the target is reasonable; otherwise set it to 0.99.
342 // note the target may affect the cost in target_function().
343 if (this->target >= 1.0 || this->target <= 0.0)
344 {
345 throw std::invalid_argument("Invalid value for target with metric "
346 "PRUNER_METRIC_PROBABILITY_OF_SHORTEST (need 0 < target < 1).");
347 }
348 }
349 else if (metric == PRUNER_METRIC_EXPECTED_SOLUTIONS)
350 {
351 // check if the target is reasonable; otherwise set it to 0.99.
352 // note the target is allowed to be larger than 1 in this case.
353 // Also the target may affect the cost in target_function().
354 if (this->target <= 0.0)
355 {
356 throw std::invalid_argument("Invalid value for target with metric "
357 "PRUNER_METRIC_EXPECTED_SOLUTIONS (need 0 < target).");
358 }
359 }
360 else
361 {
362 throw std::invalid_argument("Pruner was set to an unknown metric");
363 }
364 // normalization on |b_i^*|
365 load_basis_shape(gso_r);
366 }
367
385 Pruner(const FT enumeration_radius, const FT preproc_cost, const vector<vector<double>> &gso_rs,
386 const FT target = 0.9, const PrunerMetric metric = PRUNER_METRIC_PROBABILITY_OF_SHORTEST,
387 int flags = PRUNER_GRADIENT)
388 : enumeration_radius(enumeration_radius), preproc_cost(preproc_cost), target(target),
389 metric(metric), flags(flags)
390 {
391 verbosity = flags & PRUNER_VERBOSE;
392 n = gso_rs[0].size();
393 d = n / 2;
394 if (flags & PRUNER_CVP)
395 {
396 symmetry_factor = 1;
397 }
398 min_pruning_coefficients.resize(d);
399 btmp.resize(d);
400 bftmp.resize(n);
401 fill(min_pruning_coefficients.begin(), min_pruning_coefficients.end(), 0.);
402 set_tabulated_consts();
403
404 // optimize overall cost, use
405 if (flags & PRUNER_SINGLE)
406 {
407 opt_single = true;
408 if (flags & PRUNER_HALF)
409 {
410 throw std::invalid_argument(
411 "Error: flags PRUNER_HALF and PRUNER_SINGLE are mutually exclusive.");
412 }
413 }
414
415 // need to fix target if possible
417 {
418 // check if the target is reasonable; otherwise set it to 0.99.
419 // note the target may affect the cost in target_function().
420 if (this->target >= 1.0 || this->target <= 0.0)
421 {
422 throw std::invalid_argument("Invalid value for target with metric "
423 "PRUNER_METRIC_PROBABILITY_OF_SHORTEST (0 < target < 1).");
424 }
425 }
426 else if (metric == PRUNER_METRIC_EXPECTED_SOLUTIONS)
427 {
428 // check if the target is reasonable; otherwise set it to 0.99.
429 // note the target is allowed to be larger than 1 in this case.
430 // Also the target may affect the cost in target_function().
431 if (this->target <= 0.0)
432 {
433 throw std::invalid_argument(
434 "Invalid value for target with metric PRUNER_METRIC_EXPECTED_SOLUTIONS (0 < target).");
435 }
436 }
437 else
438 {
439 throw std::invalid_argument("Pruner was set to an unknown metric");
440 }
441 load_basis_shapes(gso_rs);
442 }
443
461 void optimize_coefficients(/*io*/ vector<double> &pr);
462
486 void optimize_coefficients_cost_vary_prob(/*io*/ vector<double> &pr);
487
510 void optimize_coefficients_cost_fixed_prob(/*io*/ vector<double> &pr);
511
529 void optimize_coefficients_evec(/*io*/ vector<double> &pr);
530
547 void optimize_coefficients_full(/*io*/ vector<double> &pr);
548
552 double single_enum_cost(/*i*/ const vector<double> &pr, vector<double> *detailed_cost = nullptr)
553 {
554 // cout << "# pr is --> " << pr[0] << endl;
555 evec b(d);
556 load_coefficients(b, pr);
557
558 return single_enum_cost(b, detailed_cost).get_d();
559 }
560
568 double repeated_enum_cost(/*i*/ const vector<double> &pr)
569 {
570 vec b(n);
571 load_coefficients(b, pr);
572 return repeated_enum_cost(b).get_d();
573 }
574
578 double measure_metric(/*i*/ const vector<double> &pr)
579 {
580 vec b(n);
581 load_coefficients(b, pr);
582 return measure_metric(b).get_d();
583 }
584
591
592private:
593 FT enumeration_radius;
594 FT preproc_cost;
595 FT target;
596 PrunerMetric metric;
597 bool shape_loaded = false;
599 int flags;
600 int n;
601 int d;
603 vector<FT> min_pruning_coefficients;
604 bool opt_single = false;
605
606 double descent_starting_clock;
607 static bool tabulated_values_imported;
608 static FT tabulated_factorial[PRUNER_MAX_N];
609 static FT tabulated_ball_vol[PRUNER_MAX_N];
610
611 FT epsilon = std::pow(2., -7);
612 FT min_step = std::pow(2., -6);
613 FT min_cf_decrease =
614 .995; //< Maximal ratio of two consectuive cost_factor in the descent before stopping
615 FT step_factor = std::pow(2, .5);
616 FT shell_ratio = .995;
617 FT symmetry_factor = .5;
618
619 // Following typedefs are given for readability
620 using vec = vector<FT>;
621 using evec = vector<FT>;
622 using poly = vector<FT>;
623
624 /* normalised by 1/det^(1/n) */
625 vec r;
626 vec ipv;
627 FT normalization_factor;
628 FT normalized_radius;
629 int verbosity = 0;
630 vec r_old;
631 FT logvol;
632
633 /* temp. variables used internally */
634 vector<FT> btmp;
635 vector<FT> bftmp;
636
638 void set_tabulated_consts();
639
644 void load_basis_shape(const vector<double> &gso_r, bool reset_normalization = true);
645
653 void load_basis_shapes(const vector<vector<double>> &gso_rs);
654
663 void load_coefficients(/*o*/ evec &b, /*i*/ const vector<double> &pr);
664
668 void print_coefficients(/*i*/ const vector<double> &pr);
669
673 void print_coefficients(/*i*/ const evec &pr);
674
683 void save_coefficients(/*o*/ vector<double> &pr, /*i*/ const evec &b);
684
695 inline bool enforce(/*io*/ vec &b, /*opt i*/ const int j = 0);
696
704 inline FT eval_poly(const int ld, /*i*/ const poly &p, const FT x);
705
712 inline void integrate_poly(const int ld, /*io*/ poly &p);
713
722 inline FT relative_volume(/*i*/ const int rd, const evec &b);
723
737 FT single_enum_cost(/*i*/ const vec &b, vector<double> *detailed_cost = nullptr);
738 FT single_enum_cost_evec(/*i*/ const evec &b, vector<double> *detailed_cost = nullptr);
739 FT single_enum_cost_lower(/*i*/ const vec &b, vector<double> *detailed_cost = nullptr);
740 FT single_enum_cost_upper(/*i*/ const vec &b, vector<double> *detailed_cost = nullptr);
741
754 FT svp_probability(/*i*/ const vec &b);
755 FT svp_probability_evec(/*i*/ const evec &b);
756 FT svp_probability_lower(/*i*/ const vec &b);
757 FT svp_probability_upper(/*i*/ const vec &b);
758
766 FT expected_solutions(/*i*/ const vec &b);
767 FT expected_solutions_evec(/*i*/ const evec &b);
768 FT expected_solutions_lower(/*i*/ const vec &b);
769 FT expected_solutions_upper(/*i*/ const vec &b);
770
776 FT measure_metric(/*i*/ const vec &b);
777
815 FT target_function(/*i*/ const evec &b);
816
823 void target_function_gradient(/*i*/ const vec &b, /*o*/ vec &res);
824
832 FT repeated_enum_cost(/*i*/ const evec &b);
833
847 void optimize_coefficients_preparation(/*io*/ vector<double> &pr);
848
869 void optimize_coefficients_evec_core(/*io*/ vector<double> &pr);
870
890 void optimize_coefficients_full_core(/*io*/ vector<double> &pr);
891
898 void greedy(evec &b);
899
904 int gradient_descent_step(/*io*/ vec &b);
905
911 int gradient_descent(/*io*/ vec &b);
912
918 int nelder_mead_step(/*io*/ evec &b);
919
930 void optimize_coefficients_local_adjust_decr_single(/*io*/ vector<double> &pr);
931
941 void optimize_coefficients_local_adjust_incr_prob(/*io*/ vector<double> &pr);
942
951 void optimize_coefficients_local_adjust_smooth(/*io*/ vector<double> &pr);
952
969 void optimize_coefficients_incr_prob(/*io*/ vector<double> &pr);
970
983 void optimize_coefficients_decr_prob(/*io*/ vector<double> &pr);
984
1001 void optimize_coefficients_local_adjust_prob(/*io*/ vector<double> &pr);
1002};
1003
1004template <class FT>
1006template <class FT> FT Pruner<FT>::tabulated_factorial[PRUNER_MAX_N];
1007template <class FT> FT Pruner<FT>::tabulated_ball_vol[PRUNER_MAX_N];
1008
1012template <class FT> inline bool Pruner<FT>::enforce(/*io*/ vec &b, /*opt i*/ const int j)
1013{
1014 int dn = b.size();
1015 int c = (dn == d) ? 1 : 2;
1016 bool status = false;
1017
1018 // the last coefficient being 1
1019 if ((b[dn - 1] < .999) & (j != dn - 1))
1020 {
1021 status = 1;
1022 b[dn - 1] = 1.;
1023 }
1024
1025 for (int i = 0; i < dn; ++i)
1026 {
1027 status |= (b[i] > 1.0001);
1028 b[i] = b[i] > 1 ? 1. : b[i];
1029
1030 // note min_pruning_coefficients always has length d
1031 if (i / c < d && b[i] <= min_pruning_coefficients[i / c])
1032 b[i] = min_pruning_coefficients[i / c];
1033 }
1034
1035 for (int i = j; i < dn - 1; ++i)
1036 {
1037 if (b[i + 1] < b[i])
1038 {
1039 status |= (b[i + 1] + .000001 < b[i]);
1040 b[i + 1] = b[i];
1041 }
1042 }
1043
1044 for (int i = std::min(j - 1, dn - 2); i >= 0; --i)
1045 {
1046 if (b[i + 1] < b[i])
1047 {
1048 status |= (b[i + 1] + .000001 < b[i]);
1049 b[i] = b[i + 1];
1050 }
1051 }
1052 return status;
1053}
1054
1055// put here to avoid warnings on inlines function should be in the header.
1056#include "pruner_simplex.h"
1057
1059
1060#endif /* FPLLL_PRUNER_H */
Definition: test_pruner.cpp:50
Pruner class, to compute and optimize cost and success probability of pruned enumeration.
Definition: pruner.h:273
FT gaussian_heuristic()
gaussian heuristic for the shortest vector length of the loaded basis.
Definition: pruner_util.cpp:93
void optimize_coefficients_cost_vary_prob(vector< double > &pr)
Main interface for optimizing the pruning coefficients with respect to the overall enumeration time.
Definition: pruner_optimize.cpp:8
void optimize_coefficients_cost_fixed_prob(vector< double > &pr)
Main interface to optimize the pruning coefficients with respect to the single enumeration.
Definition: pruner_optimize.cpp:102
Pruner(const FT enumeration_radius, const FT preproc_cost, const vector< double > &gso_r, const FT target=0.9, const PrunerMetric metric=PRUNER_METRIC_PROBABILITY_OF_SHORTEST, int flags=PRUNER_GRADIENT)
Constructor for Pruner.
Definition: pruner.h:307
Pruner(const FT enumeration_radius, const FT preproc_cost, const vector< vector< double > > &gso_rs, const FT target=0.9, const PrunerMetric metric=PRUNER_METRIC_PROBABILITY_OF_SHORTEST, int flags=PRUNER_GRADIENT)
Constructor for Pruner with multiple basis (averaging the cost function over all of them)
Definition: pruner.h:385
double repeated_enum_cost(const vector< double > &pr)
cost of repeating enumeration and preprocessing
Definition: pruner.h:568
void optimize_coefficients_evec(vector< double > &pr)
Run the optimization process using 'even' coefficients.
Definition: pruner_optimize_tc.cpp:65
void optimize_coefficients_full(vector< double > &pr)
Run the optimization process using all the coefficients.
Definition: pruner_optimize_tc.cpp:122
double measure_metric(const vector< double > &pr)
Return either SVP probability or expected number of solution depending on metric.
Definition: pruner.h:578
void optimize_coefficients(vector< double > &pr)
Main interface for optimizing pruning coefficients.
Definition: pruner_optimize.cpp:150
Pruner(const int n)
(limited) Constructor for Pruner. Only for svp_probability.
Definition: pruner.h:282
double single_enum_cost(const vector< double > &pr, vector< double > *detailed_cost=nullptr)
Compute the cost of a single enumeration.
Definition: pruner.h:552
Definition: pruner.h:32
PrunerMetric metric
Definition: pruner.h:41
static PruningParams LinearPruningParams(int block_size, int level)
Definition: bkz_param.cpp:11
PruningParams()
Definition: pruner.h:47
std::vector< double > detailed_cost
Definition: pruner.h:42
std::vector< double > coefficients
Definition: pruner.h:36
double gh_factor
Definition: pruner.h:35
double expectation
Definition: pruner.h:37
#define FPLLL_END_NAMESPACE
Definition: defs.h:117
FloatType
Definition: defs.h:210
@ FT_DEFAULT
Definition: defs.h:211
PrunerMetric
Definition: defs.h:292
@ PRUNER_METRIC_PROBABILITY_OF_SHORTEST
Definition: defs.h:293
@ PRUNER_METRIC_EXPECTED_SOLUTIONS
Definition: defs.h:294
#define FPLLL_BEGIN_NAMESPACE
Definition: defs.h:114
@ PRUNER_SINGLE
Definition: defs.h:312
@ PRUNER_VERBOSE
Definition: defs.h:306
@ PRUNER_GRADIENT
Definition: defs.h:303
@ PRUNER_CVP
Definition: defs.h:299
@ PRUNER_HALF
Definition: defs.h:309
fplll_float float_type
Definition: enumeration.h:61
void prune(PruningParams &pruning, const double enumeration_radius, const double preproc_cost, const vector< double > &gso_r, const double target=.9, const PrunerMetric metric=PRUNER_METRIC_PROBABILITY_OF_SHORTEST, const int flags=PRUNER_GRADIENT)
Search for optimal pruning parameters.
Definition: pruner.cpp:204
FT svp_probability(const PruningParams &pruning)
Probability that a pruned enumeration indeed returns the shortest vector.
Definition: pruner.cpp:178
#define PRUNER_MAX_N
Definition: pruner.h:26
int run_pruner_f(ZZ_mat< mpz_t > &B, int sel_ft, int precision=0, int prune_start=0, int prune_end=1, double prune_pre_nodes=1e6, double prune_min_prob=-1, double gh_factor=1.0)
Run pruner on B.
int run_pruner(ZZ_mat< mpz_t > &B, FloatType float_type=FT_DEFAULT, int precision=0, int prune_start=0, int prune_end=1, double prune_pre_nodes=1e6, double prune_min_prob=-1, double gh_factor=1.0)
Run pruner on B.
Definition: pruner.cpp:116