template <typename FT> void EnumerationDyn<FT>::process_solution(enumf newmaxdist) { FPLLL_TRACE("Sol dist: " << newmaxdist << " (nodes:" << nodes << ")"); for (int j = 0; j < d; ++j) fx[j] = x[j]; _evaluator.eval_sol(fx, newmaxdist, maxdist); set_bounds(); }
template <bool dualenum, bool findsubsols, bool enable_reset> void EnumerationBase::enumerate_loop() { if (k >= k_end) return; for (int i = 0; i < k_end; ++i) { center_partsum_begin[i + 1] = k_end - 1; center_partsums[i][k_end] = center_partsum[i]; } partdist[k_end] = 0.0; // needed to make next_pos_up() work properly nodes -= k_end - k; k = k_end - 1; #ifdef FPLLL_WITH_RECURSIVE_ENUM enumerate_recursive_dispatch<dualenum, findsubsols, enable_reset>(k); return; #endif finished = false; while (!finished) { enumf alphak = x[k] - center[k]; enumf newdist = partdist[k] + alphak * alphak * rdiag[k]; FPLLL_TRACE("Level k=" << k << " dist_k=" << partdist[k] << " x_k=" << x[k] << " newdist=" << newdist << " partdistbounds_k=" << partdistbounds[k]); if (newdist <= partdistbounds[k]) { ++nodes; alpha[k] = alphak; if (findsubsols && newdist < subsoldists[k]) { subsoldists[k] = newdist; process_subsolution(k, newdist); } --k; if (k < 0) { if (newdist > 0.0 || !is_svp) process_solution(newdist); finished = !next_pos_up(); continue; } if (enable_reset && k < reset_depth) // in CVP, below the max GS vector, we reset the partial distance { reset(newdist, k); finished = !next_pos_up(); continue; } if (dualenum) { for (int j = center_partsum_begin[k + 1]; j > k; --j) center_partsums[k][j] = center_partsums[k][j + 1] - alpha[j] * mut[k][j]; } else { for (int j = center_partsum_begin[k + 1]; j > k; --j) center_partsums[k][j] = center_partsums[k][j + 1] - x[j] * mut[k][j]; } center_partsum_begin[k] = max(center_partsum_begin[k], center_partsum_begin[k + 1]); center_partsum_begin[k + 1] = k + 1; enumf newcenter = center_partsums[k][k + 1]; center[k] = newcenter; partdist[k] = newdist; roundto(x[k], newcenter); dx[k] = ddx[k] = (((int)(newcenter >= x[k]) & 1) << 1) - 1; } else { finished = !next_pos_up(); } } }
inline void EnumerationBase::enumerate_recursive( EnumerationBase::opts<kk, kk_start, dualenum, findsubsols, enable_reset>) { enumf alphak = x[kk] - center[kk]; enumf newdist = partdist[kk] + alphak * alphak * rdiag[kk]; if (!(newdist <= partdistbounds[kk])) return; ++nodes; alpha[kk] = alphak; if (findsubsols && newdist < subsoldists[kk]) { subsoldists[kk] = newdist; process_subsolution(kk, newdist); } if (kk == 0) { if (newdist > 0.0 || !is_svp) process_solution(newdist); } else if (enable_reset && kk < reset_depth) // in CVP, below the max GS vector, we reset the partial distance { reset(newdist, kk); return; } else { partdist[kk - 1] = newdist; if (dualenum) { for (int j = center_partsum_begin[kk]; j > kk - 1; --j) center_partsums[kk - 1][j] = center_partsums[kk - 1][j + 1] - alpha[j] * mut[kk - 1][j]; } else { for (int j = center_partsum_begin[kk]; j > kk - 1; --j) center_partsums[kk - 1][j] = center_partsums[kk - 1][j + 1] - x[j] * mut[kk - 1][j]; } if (center_partsum_begin[kk] > center_partsum_begin[kk - 1]) center_partsum_begin[kk - 1] = center_partsum_begin[kk]; center_partsum_begin[kk] = kk; center[kk - 1] = center_partsums[kk - 1][kk]; roundto(x[kk - 1], center[kk - 1]); dx[kk - 1] = ddx[kk - 1] = (((int)(center[kk - 1] >= x[kk - 1]) & 1) << 1) - 1; } while (true) { FPLLL_TRACE("Level k=" << kk << " dist_k=" << partdist[kk] << " x_k=" << x[kk] << " newdist=" << newdist << " partdistbounds_k=" << partdistbounds[kk]); enumerate_recursive(opts<kk - 1, kk_start, dualenum, findsubsols, enable_reset>()); if (partdist[kk] != 0.0) { x[kk] += dx[kk]; ddx[kk] = -ddx[kk]; dx[kk] = ddx[kk] - dx[kk]; enumf alphak2 = x[kk] - center[kk]; enumf newdist2 = partdist[kk] + alphak2 * alphak2 * rdiag[kk]; if (!(newdist2 <= partdistbounds[kk])) return; ++nodes; alpha[kk] = alphak2; if (kk == 0) { if (newdist2 > 0.0 || !is_svp) process_solution(newdist2); } else { partdist[kk - 1] = newdist2; if (dualenum) center_partsums[kk - 1][kk - 1 + 1] = center_partsums[kk - 1][kk - 1 + 1 + 1] - alpha[kk - 1 + 1] * mut[kk - 1][kk - 1 + 1]; else center_partsums[kk - 1][kk - 1 + 1] = center_partsums[kk - 1][kk - 1 + 1 + 1] - x[kk - 1 + 1] * mut[kk - 1][kk - 1 + 1]; if (kk > center_partsum_begin[kk - 1]) center_partsum_begin[kk - 1] = kk; center[kk - 1] = center_partsums[kk - 1][kk - 1 + 1]; roundto(x[kk - 1], center[kk - 1]); dx[kk - 1] = ddx[kk - 1] = (((int)(center[kk - 1] >= x[kk - 1]) & 1) << 1) - 1; } } else { ++x[kk]; enumf alphak2 = x[kk] - center[kk]; enumf newdist2 = partdist[kk] + alphak2 * alphak2 * rdiag[kk]; if (!(newdist2 <= partdistbounds[kk])) return; ++nodes; alpha[kk] = alphak2; if (kk == 0) { if (newdist2 > 0.0 || !is_svp) process_solution(newdist2); } else { partdist[kk - 1] = newdist2; if (dualenum) center_partsums[kk - 1][kk - 1 + 1] = center_partsums[kk - 1][kk - 1 + 1 + 1] - alpha[kk - 1 + 1] * mut[kk - 1][kk - 1 + 1]; else center_partsums[kk - 1][kk - 1 + 1] = center_partsums[kk - 1][kk - 1 + 1 + 1] - x[kk - 1 + 1] * mut[kk - 1][kk - 1 + 1]; if (kk > center_partsum_begin[kk - 1]) center_partsum_begin[kk - 1] = kk; center[kk - 1] = center_partsums[kk - 1][kk - 1 + 1]; roundto(x[kk - 1], center[kk - 1]); dx[kk - 1] = ddx[kk - 1] = (((int)(center[kk - 1] >= x[kk - 1]) & 1) << 1) - 1; } } } }
int closest_vector(IntMatrix &b, const IntVect &int_target, IntVect &sol_coord, int method, int flags) { // d = lattice dimension (note that it might decrease during preprocessing) int d = b.get_rows(); // n = dimension of the space int n = b.get_cols(); FPLLL_CHECK(d > 0 && n > 0, "closestVector: empty matrix"); FPLLL_CHECK(d <= n, "closestVector: number of vectors > size of the vectors"); // Sets the floating-point precision // Error bounds on GSO are valid if prec >= minprec double rho; int min_prec = gso_min_prec(rho, d, LLL_DEF_DELTA, LLL_DEF_ETA); int prec = max(53, min_prec + 10); int old_prec = Float::set_prec(prec); // Allocates space for vectors and matrices in constructors IntMatrix empty_mat; MatGSO<Integer, Float> gso(b, empty_mat, empty_mat, GSO_INT_GRAM); FloatVect target_coord; Float max_dist; Integer itmp1; // Computes the Gram-Schmidt orthogonalization in floating-point gso.update_gso(); gen_zero_vect(sol_coord, d); /* Applies Babai's algorithm. Because we use fp, it might be necessary to do it several times (if ||target|| >> ||b_i||) */ FloatMatrix float_matrix(d, n); FloatVect target(n), babai_sol; IntVect int_new_target = int_target; for (int i = 0; i < d; i++) for (int j = 0; j < n; j++) float_matrix(i, j).set_z(b(i, j)); for (int loop_idx = 0;; loop_idx++) { if (loop_idx >= 0x100 && ((loop_idx & (loop_idx - 1)) == 0)) FPLLL_INFO("warning: possible infinite loop in Babai's algorithm"); for (int i = 0; i < n; i++) { target[i].set_z(int_new_target[i]); } babai(float_matrix, gso.get_mu_matrix(), gso.get_r_matrix(), target, babai_sol); int idx; for (idx = 0; idx < d && babai_sol[idx] >= -1 && babai_sol[idx] <= 1; idx++) { } if (idx == d) break; for (int i = 0; i < d; i++) { itmp1.set_f(babai_sol[i]); sol_coord[i].add(sol_coord[i], itmp1); for (int j = 0; j < n; j++) int_new_target[j].submul(itmp1, b(i, j)); } } // FPLLL_TRACE("BabaiSol=" << sol_coord); get_gscoords(float_matrix, gso.get_mu_matrix(), gso.get_r_matrix(), target, target_coord); /* Computes a very large bound to make the algorithm work until the first solution is found */ max_dist = 0.0; for (int i = 1; i < d; i++) { // get_r_exp(i, i) = r(i, i) because gso is initialized without GSO_ROW_EXPO max_dist.add(max_dist, gso.get_r_exp(i, i)); } vector<int> max_indices; if (method & CVPM_PROVED) { // For Exact CVP, we need to reset enum below depth with maximal r_i max_indices = vector<int>(d); int cur, max_index, previous_max_index; previous_max_index = max_index = d-1; Float max_val; while (max_index > 0) { max_val = gso.get_r_exp(max_index, max_index); for (cur = previous_max_index - 1 ; cur >= 0 ; --cur) { if (max_val <= gso.get_r_exp(cur, cur)) { max_val = gso.get_r_exp(cur, cur); max_index = cur; } } for (cur = max_index ; cur < previous_max_index ; ++cur) max_indices[cur] = max_index; max_indices[previous_max_index] = previous_max_index; previous_max_index = max_index; --max_index; } } FPLLL_TRACE("max_indices " << max_indices); FastEvaluator<Float> evaluator(n, gso.get_mu_matrix(), gso.get_r_matrix(), EVALMODE_CV); // Main loop of the enumeration Enumeration<Float> enumobj(gso, evaluator, max_indices); enumobj.enumerate(0, d, max_dist, 0, target_coord); int result = RED_ENUM_FAILURE; if (!evaluator.sol_coord.empty()) { FPLLL_TRACE("evaluator.sol_coord=" << evaluator.sol_coord); if (flags & CVP_VERBOSE) FPLLL_INFO("max_dist=" << max_dist); for (int i = 0; i < d; i++) { itmp1.set_f(evaluator.sol_coord[i]); sol_coord[i].add(sol_coord[i], itmp1); } result = RED_SUCCESS; } Float::set_prec(old_prec); return result; }