Skip to content

Latest commit

 

History

History
100 lines (76 loc) · 2.95 KB

README.md

File metadata and controls

100 lines (76 loc) · 2.95 KB

L-BFGS-B C++ Wrapper

Overview

This is a thin wrapper around the original Fortran L-BFGS-B routine v3.0

  • Lightweight & flexible abstraction.
  • Provided interface follows SciPy convention.
  • Require C++11.

Install Using CMake

mkdir build
cd build
cmake ..
make install
  • -DCMAKE_INSTALL_PREFIX=/path/to/folder - Install to /path/to/folder instead of /usr/local.
  • -DCMAKE_BUILD_TYPE=Release - Fully optimized build.
  • -DBUILD_SHARED_LIBS=ON - Build a shared library instead (default is static with -fPIC).
  • -DBUILD_EXAMPLE=ON - Build example.
  • The underlying fortran subroutine is compiled with -frecursive to ensure thread-safety.

Quick Start

#include <lbfgsb_cpp/lbfgsb.hpp>
using namespace lbfgsb;

double get_objective(const std::array<double, 2>& x, std::array<double, 2>& grad) {
    grad[0] = 2 * (x[0] - 0.5);
    grad[1] = 2 * (x[1] - 1);
    return std::pow(x[0] - 0.5, 2) +  std::pow(x[1] - 1, 2);
}

int main() {
    const std::array<double, 2> lb{-2, -2};
    const std::array<double, 2> ub{2, 2};
    // 0 if unbounded,
    // 1 if only a lower bound,
    // 2 if both lower and upper bounds,
    // 3 if only an upper bound.
    const std::array<int, 2> bound_type{2, 2};

    Optimizer optimizer{lb.size()};
    // Can adjust many optimization configs.
    // E.g. `iprint`, `factr`, `pgtol`, `max_iter`, `max_fun`, `time_limit_sec`
    optimizer.iprint = 1;
    std::array<double, 2> x0{2, 3};
    auto result = optimizer.minimize(
        get_objective, x0, lb.data(), ub.data(), bound_type.data()
    );
    result.print();
    // (0.5, 1) => 0
    std::cout << "x0: (" << x0[0] << ", " << x0[1] << ")" << std::endl;

    return 0;
}

API

  • minimize(F& func, T& x0, const double* lb, const double* ub, const int* bound_type)
    • x0 will be updated with the optimal parameters.
  • func(const T& x0, T& grad) -> double fval
    • Aim to optimize the return value.
    • grad is required to be updated on each call.
  • Requirement from T
    • T grad(x0) must be able to initialize grad.
    • T.data() must return a pointer to the data.
    • So std::array & std::vector both work.

Differences with SciPy

  • All defaults are from SciPy except for max_iter.
  • Unlike SciPy, max_iter is defined by the fortran subroutine, not the number of times the subroutine is called.
    • The subroutine may be called multiple times for line searches in one iteration.
  • OptimizeResult.warn_flag returns 3 for ABNORMAL_TERMINATION_IN_LNSRCH instead of 2.
  • The Fortran subroutine SciPy uses has an additional parameter maxls.

References