Beispiel #1
0
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;
      }
    }
  }
}
Beispiel #4
0
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;
}