4#ifndef LBFGSPP_LBFGSB_H
5#define LBFGSPP_LBFGSB_H
10#include "LBFGSpp/Param.h"
11#include "LBFGSpp/BFGSMat.h"
12#include "LBFGSpp/Cauchy.h"
13#include "LBFGSpp/SubspaceMin.h"
14#include "LBFGSpp/LineSearchMoreThuente.h"
21template <
typename Scalar,
22 template <
class>
class LineSearch = LineSearchMoreThuente>
26 using Vector = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
27 using Matrix = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;
28 using MapVec = Eigen::Map<Vector>;
29 using IndexSet = std::vector<int>;
32 BFGSMat<Scalar, true> m_bfgs;
42 inline void reset(
int n)
44 const int m = m_param.
m;
51 m_fx.resize(m_param.
past);
55 static void force_bounds(Vector& x,
const Vector& lb,
const Vector& ub)
57 x.noalias() = x.cwiseMax(lb).cwiseMin(ub);
62 static Scalar proj_grad_norm(
const Vector& x,
const Vector& g,
const Vector& lb,
const Vector& ub)
64 return ((x - g).cwiseMax(lb).cwiseMin(ub) - x).cwiseAbs().maxCoeff();
68 static Scalar max_step_size(
const Vector& x0,
const Vector& drt,
const Vector& lb,
const Vector& ub)
70 const int n = x0.size();
71 Scalar step = std::numeric_limits<Scalar>::infinity();
73 for (
int i = 0; i < n; i++)
75 if (drt[i] > Scalar(0))
77 step = std::min(step, (ub[i] - x0[i]) / drt[i]);
79 else if (drt[i] < Scalar(0))
81 step = std::min(step, (lb[i] - x0[i]) / drt[i]);
116 template <
typename Foo>
117 inline int minimize(Foo& f, Vector& x, Scalar& fx,
const Vector& lb,
const Vector& ub)
122 const int n = x.size();
123 if (lb.size() != n || ub.size() != n)
124 throw std::invalid_argument(
"'lb' and 'ub' must have the same size as 'x'");
128 force_bounds(x, lb, ub);
134 const int fpast = m_param.
past;
138 m_projgnorm = proj_grad_norm(x, m_grad, lb, ub);
153 IndexSet newact_set, fv_set;
154 Cauchy<Scalar>::get_cauchy_point(m_bfgs, x, m_grad, lb, ub, xcp, vecc, newact_set, fv_set);
163 m_drt.noalias() = xcp - x;
166 constexpr Scalar eps = std::numeric_limits<Scalar>::epsilon();
168 Vector vecs(n), vecy(n);
175 m_gradp.noalias() = m_grad;
176 Scalar dg = m_grad.dot(m_drt);
179 Scalar step_max = max_step_size(x, m_drt, lb, ub);
188 if (dg >= Scalar(0) || step_max <= m_param.
min_step)
191 m_drt.noalias() = xcp - x;
193 m_bfgs.reset(n, m_param.
m);
195 dg = m_grad.dot(m_drt);
196 step_max = max_step_size(x, m_drt, lb, ub);
200 step_max = std::min(m_param.
max_step, step_max);
201 Scalar step = Scalar(1);
202 step = std::min(step, step_max);
203 LineSearch<Scalar>::LineSearch(f, m_param, m_xp, m_drt, step_max, step, fx, m_grad, dg, x);
206 m_projgnorm = proj_grad_norm(x, m_grad, lb, ub);
220 const Scalar fxd = m_fx[k % fpast];
221 if (k >= fpast && abs(fxd - fx) <= m_param.
delta * std::max(std::max(abs(fx), abs(fxd)), Scalar(1)))
224 m_fx[k % fpast] = fx;
235 vecs.noalias() = x - m_xp;
236 vecy.noalias() = m_grad - m_gradp;
237 if (vecs.dot(vecy) > eps * vecy.squaredNorm())
238 m_bfgs.add_correction(vecs, vecy);
240 force_bounds(x, lb, ub);
241 Cauchy<Scalar>::get_cauchy_point(m_bfgs, x, m_grad, lb, ub, xcp, vecc, newact_set, fv_set);
249 SubspaceMin<Scalar>::subspace_minimize(m_bfgs, x, xcp, m_grad, lb, ub,
250 vecc, newact_set, fv_set, m_param.
max_submin, m_drt);
const Vector & final_grad() const
int minimize(Foo &f, Vector &x, Scalar &fx, const Vector &lb, const Vector &ub)
Scalar final_grad_norm() const
LBFGSBSolver(const LBFGSBParam< Scalar > ¶m)