123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773 |
- #ifndef LBFGS_HPP
- #define LBFGS_HPP
- #include <Eigen/Eigen>
- #include <cmath>
- #include <algorithm>
- #include <time.h>
- #include <chrono>
- namespace lbfgs
- {
-
-
- struct lbfgs_parameter_t
- {
-
- int mem_size = 8;
-
- double g_epsilon = 0.0;
-
- int past = 3;
-
- double delta = 1.0e-6;
-
- int max_iterations = 0;
-
- int max_linesearch = 64;
-
- double min_step = 1.0e-20;
-
- double max_step = 1.0e+20;
-
- double f_dec_coeff = 1.0e-4;
-
- double s_curv_coeff = 0.9;
-
- double cautious_factor = 1.0e-6;
-
- double machine_prec = 1.0e-16;
- };
-
- enum
- {
-
- LBFGS_CONVERGENCE = 0,
-
- LBFGS_STOP,
-
- LBFGS_CANCELED,
-
- LBFGSERR_UNKNOWNERROR = -1024,
-
- LBFGSERR_INVALID_N,
-
- LBFGSERR_INVALID_MEMSIZE,
-
- LBFGSERR_INVALID_GEPSILON,
-
- LBFGSERR_INVALID_TESTPERIOD,
-
- LBFGSERR_INVALID_DELTA,
-
- LBFGSERR_INVALID_MINSTEP,
-
- LBFGSERR_INVALID_MAXSTEP,
-
- LBFGSERR_INVALID_FDECCOEFF,
-
- LBFGSERR_INVALID_SCURVCOEFF,
-
- LBFGSERR_INVALID_MACHINEPREC,
-
- LBFGSERR_INVALID_MAXLINESEARCH,
-
- LBFGSERR_INVALID_FUNCVAL,
-
- LBFGSERR_MINIMUMSTEP,
-
- LBFGSERR_MAXIMUMSTEP,
-
-
- LBFGSERR_MAXIMUMLINESEARCH,
-
- LBFGSERR_MAXIMUMITERATION,
-
- LBFGSERR_WIDTHTOOSMALL,
-
- LBFGSERR_INVALIDPARAMETERS,
-
- LBFGSERR_INCREASEGRADIENT,
- };
-
- typedef double (*lbfgs_evaluate_t)(void *instance,
- const Eigen::VectorXd &x,
- Eigen::VectorXd &g);
-
- typedef int (*lbfgs_progress_t)(void *instance,
- const Eigen::VectorXd &x,
- const Eigen::VectorXd &g,
- const double fx,
- const double step,
- const int k,
- const int ls);
-
- struct callback_data_t
- {
- void *instance = nullptr;
- lbfgs_evaluate_t proc_evaluate = nullptr;
- lbfgs_progress_t proc_progress = nullptr;
- };
-
-
- inline int line_search_lewisoverton(Eigen::VectorXd &x,
- double &f,
- Eigen::VectorXd &g,
- double &stp,
- const Eigen::VectorXd &s,
- const Eigen::VectorXd &xp,
- const Eigen::VectorXd &gp,
- const double stpmin,
- const double stpmax,
- const callback_data_t &cd,
- const lbfgs_parameter_t ¶m)
- {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- int linesearch_cnt = 0;
- double step_l = 0.0;
- double step_u = stpmax;
- const double fp = cd.proc_evaluate(cd.instance, xp, g);
- const double d_delta = gp.dot(s);
- while (linesearch_cnt < param.max_linesearch)
- {
- ++linesearch_cnt;
-
-
-
-
-
- x = xp + stp * s;
-
-
- if (x.minCoeff() < 0)
- {
-
- x = xp;
-
- }
- f = cd.proc_evaluate(cd.instance, x, g);
- if (f > fp + param.f_dec_coeff * stp * d_delta)
- stp = stp / 2;
- else
- return linesearch_cnt;
- if (stp < 0.6)
- return linesearch_cnt;
- }
- return LBFGSERR_MAXIMUMLINESEARCH;
-
- }
-
- inline int lbfgs_optimize(Eigen::VectorXd &x,
- double &f,
- lbfgs_evaluate_t proc_evaluate,
- lbfgs_progress_t proc_progress,
- void *instance,
- const lbfgs_parameter_t ¶m)
- {
- int ret, i, j, k, ls, end, bound;
- double step, step_min, step_max, fx, ys, yy;
- double gnorm_inf, xnorm_inf, beta, rate, cau;
- const int n = x.size();
- const int m = param.mem_size;
-
- if (n <= 0)
- {
- return LBFGSERR_INVALID_N;
- }
- if (m <= 0)
- {
- return LBFGSERR_INVALID_MEMSIZE;
- }
- if (param.g_epsilon < 0.0)
- {
- return LBFGSERR_INVALID_GEPSILON;
- }
- if (param.past < 0)
- {
- return LBFGSERR_INVALID_TESTPERIOD;
- }
- if (param.delta < 0.0)
- {
- return LBFGSERR_INVALID_DELTA;
- }
- if (param.min_step < 0.0)
- {
- return LBFGSERR_INVALID_MINSTEP;
- }
- if (param.max_step < param.min_step)
- {
- return LBFGSERR_INVALID_MAXSTEP;
- }
- if (!(param.f_dec_coeff > 0.0 &&
- param.f_dec_coeff < 1.0))
- {
- return LBFGSERR_INVALID_FDECCOEFF;
- }
- if (!(param.s_curv_coeff < 1.0 &&
- param.s_curv_coeff > param.f_dec_coeff))
- {
- return LBFGSERR_INVALID_SCURVCOEFF;
- }
- if (!(param.machine_prec > 0.0))
- {
- return LBFGSERR_INVALID_MACHINEPREC;
- }
- if (param.max_linesearch <= 0)
- {
- return LBFGSERR_INVALID_MAXLINESEARCH;
- }
-
- Eigen::VectorXd xp(n);
- Eigen::VectorXd g(n);
- Eigen::VectorXd gp(n);
- Eigen::VectorXd d(n);
- Eigen::VectorXd pf(std::max(1, param.past));
-
- Eigen::VectorXd lm_alpha = Eigen::VectorXd::Zero(m);
- Eigen::MatrixXd lm_s = Eigen::MatrixXd::Zero(n, m);
- Eigen::MatrixXd lm_y = Eigen::MatrixXd::Zero(n, m);
- Eigen::VectorXd lm_ys = Eigen::VectorXd::Zero(m);
-
- callback_data_t cd;
- cd.instance = instance;
- cd.proc_evaluate = proc_evaluate;
- cd.proc_progress = proc_progress;
-
- fx = cd.proc_evaluate(cd.instance, x, g);
-
- pf(0) = fx;
-
- d = -g;
-
- gnorm_inf = g.cwiseAbs().maxCoeff();
- xnorm_inf = x.cwiseAbs().maxCoeff();
- if (gnorm_inf / std::max(1.0, xnorm_inf) < param.g_epsilon)
- {
-
- ret = LBFGS_CONVERGENCE;
- }
- else
- {
-
- step = 1.0 / d.norm();
- k = 1;
- end = 0;
- bound = 0;
- auto LBFGS_start = std::chrono::high_resolution_clock::now();
- auto LBFGS_NOW = std::chrono::high_resolution_clock::now();
- std::chrono::duration<double, std::milli> LBFGS_duration;
- while (true)
- {
- LBFGS_NOW = std::chrono::high_resolution_clock::now();
- LBFGS_duration = LBFGS_NOW - LBFGS_start;
- if(LBFGS_duration.count() > 30){
- ret = 95432;
- break;
- }
-
- xp = x;
- gp = g;
-
- step_min = param.min_step;
- step_max = param.max_step;
-
-
-
- ls = line_search_lewisoverton(x, fx, g, step, d, xp, gp, step_min, step_max, cd, param);
-
-
-
-
-
- if (ls < 0)
- {
-
- x = xp;
- g = gp;
- ret = ls;
- break;
- }
-
- if (cd.proc_progress)
- {
- if (cd.proc_progress(cd.instance, x, g, fx, step, k, ls))
- {
- ret = LBFGS_CANCELED;
- break;
- }
- }
-
- gnorm_inf = g.cwiseAbs().maxCoeff();
- xnorm_inf = x.cwiseAbs().maxCoeff();
- if (gnorm_inf / std::max(1.0, xnorm_inf) < param.g_epsilon)
- {
-
- ret = LBFGS_CONVERGENCE;
- break;
- }
-
- if (0 < param.past)
- {
-
- if (param.past <= k)
- {
-
- rate = std::fabs(pf(k % param.past) - fx) / std::max(1.0, std::fabs(fx));
- if (rate < param.delta)
- {
- ret = LBFGS_STOP;
- break;
- }
- }
-
- pf(k % param.past) = fx;
- }
- if (param.max_iterations != 0 && param.max_iterations <= k)
- {
-
- ret = LBFGSERR_MAXIMUMITERATION;
- break;
- }
-
- ++k;
-
-
- lm_s.col(end) = x - xp;
- lm_y.col(end) = g - gp;
-
- ys = lm_y.col(end).dot(lm_s.col(end));
- yy = lm_y.col(end).squaredNorm();
- lm_ys(end) = ys;
-
- d = -g;
-
- cau = lm_s.col(end).squaredNorm() * gp.norm() * param.cautious_factor;
- if (ys > cau)
- {
-
- ++bound;
- bound = m < bound ? m : bound;
- end = (end + 1) % m;
- j = end;
- for (i = 0; i < bound; ++i)
- {
- j = (j + m - 1) % m;
-
- lm_alpha(j) = lm_s.col(j).dot(d) / lm_ys(j);
-
- d += (-lm_alpha(j)) * lm_y.col(j);
- }
- d *= ys / yy;
- for (i = 0; i < bound; ++i)
- {
-
- beta = lm_y.col(j).dot(d) / lm_ys(j);
-
- d += (lm_alpha(j) - beta) * lm_s.col(j);
- j = (j + 1) % m;
- }
- }
-
- step = 1.0;
- }
- int asdfd = 0;
- }
-
- f = fx;
- return ret;
- }
-
- inline const char *lbfgs_strerror(const int err)
- {
- switch (err)
- {
- case LBFGS_CONVERGENCE:
- return "Success: reached convergence (g_epsilon).";
- case LBFGS_STOP:
- return "Success: met stopping criteria (past f decrease less than delta).";
- case LBFGS_CANCELED:
- return "The iteration has been canceled by the monitor callback.";
- case LBFGSERR_UNKNOWNERROR:
- return "Unknown error.";
- case LBFGSERR_INVALID_N:
- return "Invalid number of variables specified.";
- case LBFGSERR_INVALID_MEMSIZE:
- return "Invalid parameter lbfgs_parameter_t::mem_size specified.";
- case LBFGSERR_INVALID_GEPSILON:
- return "Invalid parameter lbfgs_parameter_t::g_epsilon specified.";
- case LBFGSERR_INVALID_TESTPERIOD:
- return "Invalid parameter lbfgs_parameter_t::past specified.";
- case LBFGSERR_INVALID_DELTA:
- return "Invalid parameter lbfgs_parameter_t::delta specified.";
- case LBFGSERR_INVALID_MINSTEP:
- return "Invalid parameter lbfgs_parameter_t::min_step specified.";
- case LBFGSERR_INVALID_MAXSTEP:
- return "Invalid parameter lbfgs_parameter_t::max_step specified.";
- case LBFGSERR_INVALID_FDECCOEFF:
- return "Invalid parameter lbfgs_parameter_t::f_dec_coeff specified.";
- case LBFGSERR_INVALID_SCURVCOEFF:
- return "Invalid parameter lbfgs_parameter_t::s_curv_coeff specified.";
- case LBFGSERR_INVALID_MACHINEPREC:
- return "Invalid parameter lbfgs_parameter_t::machine_prec specified.";
- case LBFGSERR_INVALID_MAXLINESEARCH:
- return "Invalid parameter lbfgs_parameter_t::max_linesearch specified.";
- case LBFGSERR_INVALID_FUNCVAL:
- return "The function value became NaN or Inf.";
- case LBFGSERR_MINIMUMSTEP:
- return "The line-search step became smaller than lbfgs_parameter_t::min_step.";
- case LBFGSERR_MAXIMUMSTEP:
- return "The line-search step became larger than lbfgs_parameter_t::max_step.";
- case LBFGSERR_MAXIMUMLINESEARCH:
- return "Line search reaches the maximum try number, assumptions not satisfied or precision not achievable.";
- case LBFGSERR_MAXIMUMITERATION:
- return "The algorithm routine reaches the maximum number of iterations.";
- case LBFGSERR_WIDTHTOOSMALL:
- return "Relative search interval width is at least lbfgs_parameter_t::machine_prec.";
- case LBFGSERR_INVALIDPARAMETERS:
- return "A logic error (negative line-search step) occurred.";
- case LBFGSERR_INCREASEGRADIENT:
- return "The current search direction increases the cost function value.";
- default:
- return "(unknown)";
- }
- }
- }
- #endif
|