10 #include "HLBFGS/HLBFGS.h"
25 struct gsHLBFGSObjective
28 typedef gsEigen::Matrix<T, gsEigen::Dynamic, 1> Vector;
31 gsHLBFGSObjective(gsOptProblem<T>* objective)
41 void operator() (
int N, real_t* x, real_t* prev_x, real_t* f, real_t* g)
const
43 gsAsConstVector<real_t> u(x,N);
46 gsAsVector<real_t> Gvec(g,N);
47 obj->gradObj_into(u,Gvec);
50 gsOptProblem<T> * obj;
54 class gsHLBFGS :
public gsOptimizer<T>
57 using Base = gsOptimizer<T>;
67 gsHLBFGS(gsOptProblem<T> * problem)
71 this->defaultOptions();
78 Base::defaultOptions();
81 m_options.
addInt(
"LBFGSUpdates",
"Number of LBFGS updates (typically 3-20, put to 0 for gradient descent)",20);
96 m_hlbfgs_info[4] =
static_cast<index_t>(m_maxIterations);
97 m_hlbfgs_info[5] =
static_cast<index_t>(m_verbose);
99 m_hlbfgs_pars[5] = m_minGradientLength;
100 m_hlbfgs_pars[6] = m_minStepLength;
105 static void static_func_grad(
int N, T* x, T* prev_x, T* f, T* g)
107 (*local_func_grad)(N, x, prev_x, f, g);
110 static void static_newiter_callback(
int iter,
int call_iter, T *x, T* f, T *g, T* gnorm)
112 (*local_newiter_callback)(iter, call_iter, x, f, g, gnorm);
117 void run(std::vector<T> & sol)
121 INIT_HLBFGS(m_hlbfgs_pars, m_hlbfgs_info);
125 const std::function<void(int N, real_t* x, real_t* prev_x, real_t* f, real_t* g)> wrapfunc =
126 [&](
int N, real_t* x, real_t*, real_t* f, real_t* g) {
127 std::vector<real_t> array_x(N), array_g(N);
129 gsAsConstVector<real_t> u(x,N);
130 *f = m_op->evalObj(u);
132 gsAsVector<real_t> Gvec(g,N);
133 m_op->gradObj_into(u,Gvec);
136 local_func_grad = &wrapfunc;
138 const std::function<void(int iter, int call_iter, T *x, T* f, T *g, T* gnorm)> wrapcallback =
139 [
this](
int iter,
int call_iter, T *x, T* f, T *g, T* gnorm)
143 gsInfo<<
"# iter "<< iter <<
": #func eval. " << call_iter <<
", f = " << *f <<
", ||g|| = " << *gnorm << std::endl;
146 local_newiter_callback = &wrapcallback;
156 HLBFGS_UPDATE_Hessian,
157 static_newiter_callback,
163 void solve(
const gsMatrix<T> & initialGuess)
165 GISMO_ASSERT(initialGuess.cols()==1,
"The initial guess should have vector format");
166 std::vector<T> sol(initialGuess.rows());
167 gsMatrix<T>::Map(sol.data(), initialGuess.rows(),1) = initialGuess;
170 m_curDesign = gsMatrix<T>::Map(sol.data(), sol.size(),1);
171 m_numIterations = m_hlbfgs_info[2];
175 gsInfo<<
"HLBFGS finished in "<<m_numIterations<<
" iterations, with final objective "<<m_finalObjective<<
"\n";
181 void gradientCheck(
const gsVector<T> &u) {
183 std::vector<T> sol(u.size());
184 gsAsVector<T> analyticGrad(sol);
185 std::copy(u.begin(), u.end(), sol.begin());
186 m_op->gradObj_into(sol, analyticGrad);
189 gsVector<T> numericalGrad(u.size());
190 T h = sqrt(std::numeric_limits<T>::epsilon()) * u.cwiseAbs().maxCoeff();
191 T forwardValue, backwardValue;
193 std::vector<T> solForNumericalGrad(u.size());
194 std::copy(u.begin(), u.end(), solForNumericalGrad.begin());
197 for (
int k = 0; k < u.size(); ++k) {
199 solForNumericalGrad[k] += h;
200 forwardValue = m_op->evalObj(solForNumericalGrad);
203 solForNumericalGrad[k] -= 2.0 * h;
204 backwardValue = m_op->evalObj(solForNumericalGrad);
207 numericalGrad(k) = (forwardValue - backwardValue) / (2.0 * h);
210 solForNumericalGrad[k] += h;
214 gsInfo <<
"Analytical gradient: Finite difference gradient: \n";
216 int numElementsToPrint = std::min(analyticGrad.size(), 30);
217 for (
int i = 0; i < numElementsToPrint; ++i) {
218 gsInfo << std::setw(5) << i << std::setw(20) << analyticGrad(i)
219 << std::setw(20) << numericalGrad(i) <<
"\n";
223 gsInfo <<
"(Displaying the first 30 components only)\n";
227 (analyticGrad - numericalGrad).norm() / analyticGrad.norm();
228 gsInfo <<
"The relative error between the analytic gradient and the "
229 "numerical gradient is: " << relativeError <<
"\n\n";
235 using Base::m_numIterations;
236 using Base::m_finalObjective;
239 using Base::m_verbose;
240 using Base::m_maxIterations;
242 using Base::defaultOptions;
243 using Base::getOptions;
247 T m_minGradientLength;
252 index_t m_hlbfgs_info[20] = {0};
253 T m_hlbfgs_pars[20] = {0};
256 static const std::function<void(int N, T* x, T* prev_x, T* f, T* g)> * local_func_grad;
257 static const std::function<void(int iter, int call_iter, T *x, T* f, T *g, T* gnorm)> * local_newiter_callback;
261 const std::function<void(int N, T* x, T* prev_x, T* f, T* g)> * gsHLBFGS<T>::local_func_grad =
nullptr;
263 const std::function<void(int iter, int call_iter, T *x, T* f, T *g, T* gnorm)> * gsHLBFGS<T>::local_newiter_callback =
nullptr;
gsOptionList m_options
Options.
Definition: gsOptimizer.h:108
#define index_t
Definition: gsConfig.h:32
const index_t & getInt(const std::string &label) const
Reads value for option label from options.
Definition: gsOptionList.cpp:37
This file is part of the G+Smo library.
#define GISMO_ASSERT(cond, message)
Definition: gsDebug.h:89
void addInt(const std::string &label, const std::string &desc, const index_t &value)
Adds a option named label, with description desc and value value.
Definition: gsOptionList.cpp:201
#define gsInfo
Definition: gsDebug.h:43
void addReal(const std::string &label, const std::string &desc, const Real &value)
Adds a option named label, with description desc and value value.
Definition: gsOptionList.cpp:211
This is the main header file that collects wrappers of Eigen for linear algebra.
gsMatrix< T > m_curDesign
Current design variables (and starting point )
Definition: gsOptimizer.h:105
Real getReal(const std::string &label) const
Reads value for option label from options.
Definition: gsOptionList.cpp:44
void copy(T begin, T end, U *result)
Small wrapper for std::copy mimicking std::copy for a raw pointer destination, copies n positions sta...
Definition: gsMemory.h:391