Program Listing for File generic_mixed_descent.cpp#

↰ Return to documentation for file (source/generic_mixed_descent.cpp)

#include "pele/generic_mixed_descent.hpp"
#include <lapack.h>
#include <ostream>
#include <pele/array.hpp>

using namespace std;
namespace pele {
bool GenericMixedDescent::x_in_convex_region() {
  x_.assign(opt_non_convex_->get_x());
  // Calculate hessian at x. Current version is hessian based.
  // Ideally you should be able to get the pointer to the hessian from the
  // optimizer.
  get_hess(hessian_);

  int N_int = x_.size();
  add_translation_offset_2d(hessian_, translation_offset_);

  hessian_copy_for_cholesky_ = hessian_;

  // pointer to t
  double *hessian_copy_for_cholesky_data;
  hessian_copy_for_cholesky_data = hessian_copy_for_cholesky_.data();
  int info = 0;
  dpotrf_(&uplo, &N_int, hessian_copy_for_cholesky_data, &N_int, &info
#ifdef LAPACK_FORTRAN_STRLEN_END  // 1 is the length of the uplo string,
                                  // necessary for current fortran
          ,
          1
#endif
  );

  if (info == 0) {
    // if positive definite, we are in the convex region.
    return true;
  }
  return false;
}

void GenericMixedDescent::get_hess(Eigen::MatrixXd &hessian) {
  // Does not allocate memory for hessian just wraps around the data
  Array<double> hessian_pele = Array<double>(hessian.data(), hessian.size());
  if (pot_extension_provided_) {
    extended_potential_->get_hessian(x_, hessian_pele);
  } else {
    potential_->get_hessian(x_, hessian_pele);
  }
  hessian_evaluations_ += 1;
}

void GenericMixedDescent::one_iteration() {
  if ((iter_number_ % steps_before_convex_check_ == 0 and iter_number_ > 0) and
      !in_convex_region_) {
    in_convex_region_ = x_in_convex_region();

    // if in convex region and non convex method is being used
    // switch to convex method
    if (in_convex_region_ and use_non_convex_method_) {
      use_non_convex_method_ = false;
      last_non_convex_x_.assign(x_);
      opt_convex_->set_x(x_);
    }
  }
  // take iteration
  if (use_non_convex_method_) {
    opt_non_convex_->one_iteration();
    n_phase_1_steps += 1;
    gradient_norm_ = opt_non_convex_->get_rms();

    // Debugging
#if OPTIMIZER_DEBUG_LEVEL > 2
    std::cout << "non convex step" << std::endl;
    std::cout << "rms" << gradient_norm_ << std::endl;
#endif

  } else {
    opt_convex_->one_iteration();
    gradient_norm_ = opt_convex_->get_rms();

    // Debugging
#if OPTIMIZER_DEBUG_LEVEL > 2
    std::cout << "convex step" << std::endl;
    std::cout << "rms" << gradient_norm_ << std::endl;
#endif
    if (opt_convex_->get_last_step_failed()) {
      use_non_convex_method_ = true;
      opt_non_convex_->set_x(last_non_convex_x_);
    }
  }
  // update all parameters from the optimizer
  nfev_ = opt_non_convex_->get_nfev() + opt_convex_->get_nfev();
  nhev_ = opt_non_convex_->get_nhev() + opt_convex_->get_nhev() +
          hessian_evaluations_;
  iter_number_ += 1;
}

void GenericMixedDescent::add_translation_offset_2d(Eigen::MatrixXd &hessian,
                                                    double offset) {
  // factor so that the added translation operators are unitary
  double factor = 2.0 / hessian.rows();
  offset = offset * factor;

  for (size_t i = 0; i < hessian.rows(); ++i) {
    for (size_t j = i + 1; j < hessian.cols(); ++j) {
      if ((i % 2 == 0 && j % 2 == 0) || (i % 2 == 1 && j % 2 == 1)) {
        hessian(i, j) += offset;
        hessian(j, i) += offset;
      }
    }
  }
  // add the diagonal elements that were missed by the previous loop
  hessian.diagonal().array() += offset;
}
}  // namespace pele