Program Listing for File generic_mixed_descent.hpp#

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

#ifndef PELE_MIXED_DESCENT_WITH_FIRE_HPP
#define PELE_MIXED_DESCENT_WITH_FIRE_HPP

#include <Eigen/Dense>
#include <cstddef>
#include <iostream>
#include <memory>
#include <pele/array.hpp>
#include <pele/base_potential.hpp>
#include <pele/optimizer.hpp>

#include "pele/combine_potentials.hpp"

namespace pele {

class GenericMixedDescent : public GradientOptimizer {
 public:
  GenericMixedDescent(std::shared_ptr<BasePotential> pot, Array<double> x,
                      double tol,
                      std::shared_ptr<GradientOptimizer> opt_non_convex,
                      std::shared_ptr<GradientOptimizer> opt_convex,
                      double translation_offset, int steps_before_convex_check,
                      std::shared_ptr<BasePotential> pot_extension = nullptr)
      : GradientOptimizer(pot, x, tol),
        opt_non_convex_(opt_non_convex),
        opt_convex_(opt_convex),
        hessian_(x.size(), x.size()),
        hessian_copy_for_cholesky_(x.size(), x.size()),
        hessian_evaluations_(0),
        translation_offset_(translation_offset),
        steps_before_convex_check_(steps_before_convex_check),
        in_convex_region_(false),
        use_non_convex_method_(true),
        last_non_convex_x_(x.size()),
        hessian_calculated_(false),
        n_phase_1_steps(0) {
    // Ensure that both optimizers have the same potential
    // There is redundancy because we add the potential to each optimizer
    // but this overrides the potential in the optimizer.
    opt_non_convex_->set_potential(pot);
    opt_convex_->set_potential(pot);
    opt_convex_->set_tolerance(tol);
    opt_non_convex_->set_x(x);
    opt_non_convex_->set_tolerance(tol);

    if (pot_extension != nullptr) {
      extended_potential_ =
          std::make_shared<ExtendedPotential>(pot, pot_extension);
      extended_potential_->switch_on_extended_potential();
      pot_extension_provided_ = true;
    } else {
      extended_potential_ = nullptr;
      pot_extension_provided_ = false;
    }

#if OPTIMIZER_DEBUG_LEVEL > 0
    std::cout << "GenericMixedDescent: Constructed with parameters"
              << std::endl;
    std::cout << "x: " << x << std::endl;
    std::cout << "tol: " << tol << std::endl;
    std::cout << "translation_offset: " << translation_offset << std::endl;
    std::cout << "steps_before_convex_check: " << steps_before_convex_check
              << std::endl;
#endif
    uplo = 'U';
  }

  void one_iteration();
  int get_n_phase_1_steps() { return n_phase_1_steps; }
  int get_n_phase_2_steps() { return iter_number_ - n_phase_1_steps; }
  bool stop_criterion_satisfied() {
    if (!func_initialized_) {
      initialize_func_gradient();
    }
    if (use_non_convex_method_) {
      x_.assign(opt_non_convex_->get_x());
      g_.assign(opt_non_convex_->get_g());
    } else {
      x_.assign(opt_convex_->get_x());
      g_.assign(opt_convex_->get_g());
    }
    if (gradient_norm_ <= tol_) {
      return true;
    }
    return false;
  }

  Array<double> get_x() {
    if (use_non_convex_method_) {
#if OPTIMIZER_DEBUG_LEVEL > 3
      std::cout << "Using non convex method" << std::endl;
      std::cout << "x_ = " << opt_non_convex_->get_x() << std::endl;
      return opt_non_convex_->get_x();
#endif
    } else {
#if OPTIMIZER_DEBUG_LEVEL > 3
      std::cout << "Using convex method" << std::endl;
      std::cout << "x_ = " << opt_non_convex_->get_x() << std::endl;
#endif
      return opt_convex_->get_x();
    }
  }

 private:
  std::shared_ptr<pele::GradientOptimizer> opt_non_convex_;
  std::shared_ptr<pele::GradientOptimizer> opt_convex_;
  bool x_in_convex_region();

  void get_hess(Eigen::MatrixXd &hessian);

  void add_translation_offset_2d(Eigen::MatrixXd &hessian, double offset);

  size_t hessian_evaluations_;

  double translation_offset_;
  Eigen::MatrixXd hessian_;

  // Space allocated for a copy of the hessian, this will be
  // rewritten with the Cholesky factorization of the hessian.
  Eigen::MatrixXd hessian_copy_for_cholesky_;

  char uplo;

  size_t steps_before_convex_check_;

  bool in_convex_region_;

  // you would also use this method if you're in a convex
  // region but not close to the minima just to make sure
  // that we end up in the convex region.
  bool use_non_convex_method_;

  Array<double> last_non_convex_x_;

  bool hessian_calculated_;

  size_t n_failed_phase_2_steps;

  int n_phase_1_steps;

  std::shared_ptr<ExtendedPotential> extended_potential_;
  bool pot_extension_provided_;
};
}  // namespace pele

#endif  // !1