Program Listing for File backtracking.cpp#
↰ Return to documentation for file (source/backtracking.cpp)
#include "pele/backtracking.hpp"
#include <cmath>
#include <complex>
#include <iomanip>
#include <iostream>
#include <pele/eigen_interface.hpp>
#include <stdexcept>
#include "pele/array.hpp"
#include "pele/base_potential.hpp"
#include "pele/lsparameters.hpp"
using namespace std;
namespace pele {
double BacktrackingLineSearch::line_search(Array<double> &x,
Array<double> step) {
eig_eq_pele(xoldvec, xold_);
eig_eq_pele(gradvec, gold_);
Scalar stpsize = initial_stpsize;
// absolute original stepnorm
double absolute_step_norm = norm(step);
// if (absolute_step_norm*initial_stpsize>0.3) {
// stpsize *= 0.3/absolute_step_norm;
// #if OPTIMIZER_DEBUG_LEVEL >= 1
// std::cout << stpsize << " step size rescaled \n";
// #endif
// }
eig_eq_pele(step_direction, step);
Scalar f = opt_->get_f();
// start with the initial stepsize
step_moving_away_from_min =
false; // only true when step is opposite to gradient
LSFunc(f, xvec, gradvec, stpsize, step_direction, xoldvec, params);
if (step_moving_away_from_min) {
return 0; // Line search will not work
}
pele_eq_eig(x, xvec);
pele_eq_eig(g_, gradvec);
step = xold_ - x;
opt_->set_f(f);
opt_->set_rms(norm(g_) / sqrt(x.size()));
pele_eq_eig(step, step_direction);
#if OPTIMIZER_DEBUG_LEVEL >= 1
std::cout << stpsize << " stepsize final \n";
std::cout << opt_->compute_pot_norm(step) << " step norm \n";
std::cout << stpsize * opt_->compute_pot_norm(step)
<< "absolute step size \n";
#endif
double step_norm;
step_norm = norm(step);
if (step_norm == 0) {
throw std::runtime_error("step norm is zero");
}
return step_norm;
};
double BacktrackingLineSearch::func_grad_wrapper(Vector &x, Vector &grad) {
pele_eq_eig(xdum, x);
pele_eq_eig(gdum, grad);
double f;
opt_->compute_func_gradient(xdum, f, gdum);
eig_eq_pele(grad, gdum);
return f;
}
void BacktrackingLineSearch::LSFunc(Scalar &fx, Vector &x, Vector &grad,
Scalar &step, const Vector &drt,
const Vector &xp, const LBFGSParam ¶m) {
// Decreasing and increasing factors
const Scalar dec = 0.5;
const Scalar inc = 2.1;
// Check the value of step
if (step <= Scalar(0)) std::invalid_argument("'step' must be positive");
// Save the function value at the current x
const Scalar fx_init = fx;
// Projection of gradient on the search direction
Vector gradinit = grad;
const Scalar dg_init = grad.dot(drt);
#if OPTIMIZER_DEBUG_LEVEL >= 3
std::cout << dg_init << "dginit must be less than 0 \n";
#endif
// Make sure d points to a descent direction
if (dg_init > 0) {
step_moving_away_from_min = true; // step points away from minimum
return;
}
const Scalar test_decr = param.ftol * dg_init;
Scalar width;
int iter;
for (iter = 0; iter < param.max_linesearch; iter++) {
// x_{k+1} = x_k + step * d_k
x.noalias() = xp + step * drt;
// Evaluate this candidate
fx = func_grad_wrapper(x, grad);
if (fx > fx_init + step * test_decr) {
width = dec;
} else {
break;
}
if (iter >= param.max_linesearch)
throw std::runtime_error(
"the line search routine reached the maximum number of iterations");
if (step < param.min_step)
throw std::runtime_error(
"the line search step became smaller than the minimum value allowed");
if (step > param.max_step)
throw std::runtime_error(
"the line search step became larger than the maximum value allowed");
step *= width;
}
}
} // namespace pele