项目作者: yixuan

项目描述 :
A header-only C++ library for L-BFGS and L-BFGS-B algorithms
高级语言: C++
项目地址: git://github.com/yixuan/LBFGSpp.git
创建时间: 2016-08-05T00:40:07Z
项目社区:https://github.com/yixuan/LBFGSpp

开源协议:MIT License

下载


" class="reference-link">LBFGS++ LBFGS++

UPDATE on 2020-03-06: LBFGS++ now includes a new L-BFGS-B solver for
box-constrained optimization problems. Check the example below for its usage.

LBFGS++ is a header-only C++ library that implements the Limited-memory
BFGS algorithm (L-BFGS) for unconstrained minimization problems, and a modified
version of the L-BFGS-B algorithm for box-constrained ones.

The code for the L-BFGS solver is derived and modified from the
libLBFGS
library developed by Naoaki Okazaki.

LBFGS++ is implemented as a header-only C++ library, whose only dependency,
Eigen, is also header-only.

A Quick Example

To use LBFGS++, one needs to first define a functor to represent the
multivariate function to be minimized. It should return the objective function
value on a vector x and overwrite the vector grad with the gradient
evaluated on x. For example we could define the
Rosenbrock function in the
following way:

  1. #include <Eigen/Core>
  2. #include <iostream>
  3. #include <LBFGS.h>
  4. using Eigen::VectorXd;
  5. using namespace LBFGSpp;
  6. class Rosenbrock
  7. {
  8. private:
  9. int n;
  10. public:
  11. Rosenbrock(int n_) : n(n_) {}
  12. double operator()(const VectorXd& x, VectorXd& grad)
  13. {
  14. double fx = 0.0;
  15. for(int i = 0; i < n; i += 2)
  16. {
  17. double t1 = 1.0 - x[i];
  18. double t2 = 10 * (x[i + 1] - x[i] * x[i]);
  19. grad[i + 1] = 20 * t2;
  20. grad[i] = -2.0 * (x[i] * grad[i + 1] + t1);
  21. fx += t1 * t1 + t2 * t2;
  22. }
  23. return fx;
  24. }
  25. };

Then we just need to set up parameters, create solver object,
provide initial guess, and then run the minimization function.

  1. int main()
  2. {
  3. const int n = 10;
  4. // Set up parameters
  5. LBFGSParam<double> param;
  6. param.epsilon = 1e-6;
  7. param.max_iterations = 100;
  8. // Create solver and function object
  9. LBFGSSolver<double> solver(param);
  10. Rosenbrock fun(n);
  11. // Initial guess
  12. VectorXd x = VectorXd::Zero(n);
  13. // x will be overwritten to be the best point found
  14. double fx;
  15. int niter = solver.minimize(fun, x, fx);
  16. std::cout << niter << " iterations" << std::endl;
  17. std::cout << "x = \n" << x.transpose() << std::endl;
  18. std::cout << "f(x) = " << fx << std::endl;
  19. return 0;
  20. }

The example can then be compiled and run.

  1. $ g++ -I/path/to/eigen -I/path/to/lbfgspp/include -O2 example.cpp
  2. $ ./a.out
  3. 23 iterations
  4. x =
  5. 1 1 1 1 1 1 1 1 1 1
  6. f(x) = 1.87948e-19

You can also use a different line search algorithm by providing a second template parameter
to LBFGSSolver. For example, the code below illustrates the bracketing line search algorithm
(contributed by @DirkToewe).

  1. int main()
  2. {
  3. const int n = 10;
  4. // Set up parameters
  5. LBFGSParam<double> param;
  6. param.epsilon = 1e-6;
  7. param.max_iterations = 100;
  8. // Create solver and function object
  9. LBFGSSolver<double, LineSearchBracketing> solver(param);
  10. Rosenbrock fun(n);
  11. // Initial guess
  12. VectorXd x = VectorXd::Zero(n);
  13. // x will be overwritten to be the best point found
  14. double fx;
  15. int niter = solver.minimize(fun, x, fx);
  16. std::cout << niter << " iterations" << std::endl;
  17. std::cout << "x = \n" << x.transpose() << std::endl;
  18. std::cout << "f(x) = " << fx << std::endl;
  19. return 0;
  20. }

Box-constrained Problem

If the parameters to be optimized have simple bounds, then the
L-BFGS-B solver class LBFGSBSolver can be used.
The code is very similar to that of LBFGSSolver. Below is the same Rosenbrock
example, but we require that all variables should be between 2 and 4.

  1. #include <Eigen/Core>
  2. #include <iostream>
  3. #include <LBFGSB.h> // Note the different header file
  4. using Eigen::VectorXd;
  5. using namespace LBFGSpp;
  6. class Rosenbrock
  7. {
  8. private:
  9. int n;
  10. public:
  11. Rosenbrock(int n_) : n(n_) {}
  12. double operator()(const VectorXd& x, VectorXd& grad)
  13. {
  14. double fx = 0.0;
  15. for(int i = 0; i < n; i += 2)
  16. {
  17. double t1 = 1.0 - x[i];
  18. double t2 = 10 * (x[i + 1] - x[i] * x[i]);
  19. grad[i + 1] = 20 * t2;
  20. grad[i] = -2.0 * (x[i] * grad[i + 1] + t1);
  21. fx += t1 * t1 + t2 * t2;
  22. }
  23. return fx;
  24. }
  25. };
  26. int main()
  27. {
  28. const int n = 10;
  29. // Set up parameters
  30. LBFGSBParam<double> param; // New parameter class
  31. param.epsilon = 1e-6;
  32. param.max_iterations = 100;
  33. // Create solver and function object
  34. LBFGSBSolver<double> solver(param); // New solver class
  35. Rosenbrock fun(n);
  36. // Bounds
  37. VectorXd lb = VectorXd::Constant(n, 2.0);
  38. VectorXd ub = VectorXd::Constant(n, 4.0);
  39. // Initial guess
  40. VectorXd x = VectorXd::Constant(n, 3.0);
  41. // x will be overwritten to be the best point found
  42. double fx;
  43. int niter = solver.minimize(fun, x, fx, lb, ub);
  44. std::cout << niter << " iterations" << std::endl;
  45. std::cout << "x = \n" << x.transpose() << std::endl;
  46. std::cout << "f(x) = " << fx << std::endl;
  47. return 0;
  48. }

Note that we also allow infinite values for the lower and upper bounds.
In such cases one can define ub[i] = std::numeric_limits<double>::infinity(),
for example.

Documentation

The API reference page contains the documentation
of LBFGS++ generated by Doxygen.

License

LBFGS++ is an open source project under the MIT license.