Program Listing for File more_thuente.cpp#
↰ Return to documentation for file (source/more_thuente.cpp)
#include "pele/more_thuente.hpp"
namespace pele {
int MoreThuente::cvsrch(vector_t &x, scalar_t f, vector_t &g, scalar_t &stp,
vector_t &s) {
// we rewrite this from MIN-LAPACK and some MATLAB code
int nfev = 0;
// internal values
int info = 0;
int infoc = 1;
scalar_t stpmax = 1e15;
scalar_t stpmin = 0.0;
desdir = false;
// std::cout << dot(g, s) << " dot(g, s) \n";
// if (dot(g, s) >= 0) {
// // we''re here?
// for (int i = 0; i<s.size(); i++) {
// s[i] = -s[i];
// }
// desdir = true;
// }
// std::cout << dot(g, s) << " dot(g, s) \n";
scalar_t dginit = dot(g, s);
std::cout << dginit << "\n";
if (dginit >= 0.0) {
throw std::logic_error(
"the moving direction increases the objective function value");
}
bool brackt = false;
bool stage1 = true;
scalar_t finit = f;
scalar_t dgtest = ftol * dginit;
scalar_t width = stpmax - stpmin;
scalar_t width1 = 2 * width;
vector_t wa = x;
scalar_t stx = 0.0;
scalar_t fx = finit;
scalar_t dgx = dginit;
scalar_t sty = 0.0;
scalar_t fy = finit;
scalar_t dgy = dginit;
scalar_t stmin;
scalar_t stmax;
while (true) {
// make sure we stay in the interval when setting min/max-step-width
if (brackt) {
stmin = std::min<scalar_t>(stx, sty);
stmax = std::max<scalar_t>(stx, sty);
} else {
stmin = stx;
stmax = stp + xtrapf * (stp - stx);
}
// Force the step to be within the bounds stpmax and stpmin.
stp = std::max<scalar_t>(stp, stpmin);
stp = std::min<scalar_t>(stp, stpmax);
// Oops, let us return the last reliable values
// DEBUG
// std::cout << (brackt && ((stp <= stmin) || (stp >= stmax))) << " case 1
// \n"; std::cout << (nfev >= maxfev-1) << " case 2\n"; std::cout << nfev <<
// "---- nfeev inside\n"; std::cout << maxfev-1 << " --- maxfeev inside\n";
// std::cout << infoc << " infoc value \n";
// std::cout << (brackt && ((stmax - stmin) <= (xtol * stmax))) << " case 3
// \n";
if ((brackt && ((stp <= stmin) || (stp >= stmax))) ||
(nfev >= maxfev - 1) || (infoc == 0) ||
(brackt && ((stmax - stmin) <= (xtol * stmax)))) {
stp = stx;
}
// test new point
for (size_t i = 0; i < x.size(); ++i) {
x[i] = wa[i] + stp * s[i];
}
// f = function(x);
// function.Gradient(x, &g);
opt_->compute_func_gradient(x, f, g);
nfev++;
scalar_t dg = dot(g, s);
scalar_t ftest1 = finit + stp * dgtest;
// all possible convergence tests
if ((brackt & ((stp <= stmin) | (stp >= stmax))) | (infoc == 0)) info = 6;
if ((stp == stpmax) & (f <= ftest1) & (dg <= dgtest)) info = 5;
if ((stp == stpmin) & ((f > ftest1) | (dg >= dgtest))) info = 4;
if (nfev >= maxfev) info = 3;
if (brackt & (stmax - stmin <= xtol * stmax)) info = 2;
if ((f <= ftest1) & (fabs(dg) <= gtol * (-dginit))) info = 1;
// terminate when convergence reached
if (info != 0) return -1;
if (stage1 & (f <= ftest1) &
(dg >= std::min<scalar_t>(ftol, gtol) * dginit))
stage1 = false;
if (stage1 & (f <= fx) & (f > ftest1)) {
scalar_t fm = f - stp * dgtest;
scalar_t fxm = fx - stx * dgtest;
scalar_t fym = fy - sty * dgtest;
scalar_t dgm = dg - dgtest;
scalar_t dgxm = dgx - dgtest;
scalar_t dgym = dgy - dgtest;
cstep(stx, fxm, dgxm, sty, fym, dgym, stp, fm, dgm, brackt, stmin, stmax,
infoc);
fx = fxm + stx * dgtest;
fy = fym + sty * dgtest;
dgx = dgxm + dgtest;
dgy = dgym + dgtest;
} else {
// this is ugly and some variables should be moved to the class scope
cstep(stx, fx, dgx, sty, fy, dgy, stp, f, dg, brackt, stmin, stmax,
infoc);
}
if (brackt) {
if (fabs(sty - stx) >= 0.66 * width1) stp = stx + 0.5 * (sty - stx);
width1 = width;
width = fabs(sty - stx);
}
}
return 0.;
}
int MoreThuente::cstep(scalar_t &stx, scalar_t &fx, scalar_t &dx, scalar_t &sty,
scalar_t &fy, scalar_t &dy, scalar_t &stp, scalar_t &fp,
scalar_t &dp, bool &brackt, scalar_t &stpmin,
scalar_t &stpmax, int &info) {
info = 0;
bool bound = false;
// Check the input parameters for errors.
if ((brackt & ((stp <= std::min<scalar_t>(stx, sty)) |
(stp >= std::max<scalar_t>(stx, sty)))) |
(dx * (stp - stx) >= 0.0) | (stpmax < stpmin)) {
return -1;
}
scalar_t sgnd = dp * (dx / fabs(dx));
scalar_t stpf = 0;
scalar_t stpc = 0;
scalar_t stpq = 0;
if (fp > fx) {
info = 1;
bound = true;
scalar_t theta = 3. * (fx - fp) / (stp - stx) + dx + dp;
scalar_t s = std::max<scalar_t>(theta, std::max<scalar_t>(dx, dp));
scalar_t gamma = s * sqrt((theta / s) * (theta / s) - (dx / s) * (dp / s));
if (stp < stx) gamma = -gamma;
scalar_t p = (gamma - dx) + theta;
scalar_t q = ((gamma - dx) + gamma) + dp;
scalar_t r = p / q;
stpc = stx + r * (stp - stx);
stpq = stx + ((dx / ((fx - fp) / (stp - stx) + dx)) / 2.) * (stp - stx);
if (fabs(stpc - stx) < fabs(stpq - stx))
stpf = stpc;
else
stpf = stpc + (stpq - stpc) / 2;
brackt = true;
} else if (sgnd < 0.0) {
info = 2;
bound = false;
scalar_t theta = 3 * (fx - fp) / (stp - stx) + dx + dp;
scalar_t s = std::max<scalar_t>(theta, std::max<scalar_t>(dx, dp));
scalar_t gamma = s * sqrt((theta / s) * (theta / s) - (dx / s) * (dp / s));
if (stp > stx) gamma = -gamma;
scalar_t p = (gamma - dp) + theta;
scalar_t q = ((gamma - dp) + gamma) + dx;
scalar_t r = p / q;
stpc = stp + r * (stx - stp);
stpq = stp + (dp / (dp - dx)) * (stx - stp);
if (fabs(stpc - stp) > fabs(stpq - stp))
stpf = stpc;
else
stpf = stpq;
brackt = true;
} else if (fabs(dp) < fabs(dx)) {
info = 3;
bound = 1;
scalar_t theta = 3 * (fx - fp) / (stp - stx) + dx + dp;
scalar_t s = std::max<scalar_t>(theta, std::max<scalar_t>(dx, dp));
scalar_t gamma = s * sqrt(std::max<scalar_t>(
static_cast<scalar_t>(0.),
(theta / s) * (theta / s) - (dx / s) * (dp / s)));
if (stp > stx) gamma = -gamma;
scalar_t p = (gamma - dp) + theta;
scalar_t q = (gamma + (dx - dp)) + gamma;
scalar_t r = p / q;
if ((r < 0.0) & (gamma != 0.0)) {
stpc = stp + r * (stx - stp);
} else if (stp > stx) {
stpc = stpmax;
} else {
stpc = stpmin;
}
stpq = stp + (dp / (dp - dx)) * (stx - stp);
if (brackt) {
if (fabs(stp - stpc) < fabs(stp - stpq)) {
stpf = stpc;
} else {
stpf = stpq;
}
} else {
if (fabs(stp - stpc) > fabs(stp - stpq)) {
stpf = stpc;
} else {
stpf = stpq;
}
}
} else {
info = 4;
bound = false;
if (brackt) {
scalar_t theta = 3 * (fp - fy) / (sty - stp) + dy + dp;
scalar_t s = std::max<scalar_t>(theta, std::max<scalar_t>(dy, dp));
scalar_t gamma =
s * sqrt((theta / s) * (theta / s) - (dy / s) * (dp / s));
if (stp > sty) gamma = -gamma;
scalar_t p = (gamma - dp) + theta;
scalar_t q = ((gamma - dp) + gamma) + dy;
scalar_t r = p / q;
stpc = stp + r * (sty - stp);
stpf = stpc;
} else if (stp > stx)
stpf = stpmax;
else {
stpf = stpmin;
}
}
if (fp > fx) {
sty = stp;
fy = fp;
dy = dp;
} else {
if (sgnd < 0.0) {
sty = stx;
fy = fx;
dy = dx;
}
stx = stp;
fx = fp;
dx = dp;
}
stpf = std::min<scalar_t>(stpmax, stpf);
stpf = std::max<scalar_t>(stpmin, stpf);
stp = stpf;
if (brackt & bound) {
if (sty > stx) {
stp = std::min<scalar_t>(stx + static_cast<scalar_t>(0.66) * (sty - stx),
stp);
} else {
stp = std::max<scalar_t>(stx + static_cast<scalar_t>(0.66) * (sty - stx),
stp);
}
}
return 0;
}
double MoreThuente::line_search(Array<double> &x, Array<double> step) {
// assumes xold is set TODO : rewrite interface
double alpha = MoreThuente::search(xold_, step);
x_ = x;
for (size_t i = 0; i < xold_.size(); ++i) {
x_[i] = xold_[i] + alpha * step[i];
}
double fend;
opt_->compute_func_gradient(x_, fend, g_);
opt_->set_f(fend);
opt_->set_rms(norm(g_) / sqrt(g_.size()));
return alpha * opt_->compute_pot_norm(step);
}
} // namespace pele