#optimization #lbfgs #ported #safe #how #computational #owl-qn

liblbfgs

Fast and safe Rust implementation of LBFGS and OWL-QN algorithms ported from Naoaki Okazaki's C library libLBFGS

3 unstable releases

0.1.0 Aug 8, 2022
0.0.16 Nov 13, 2020
0.0.15 Feb 10, 2020

#514 in Algorithms

Download history 3/week @ 2024-07-19 7/week @ 2024-07-26 3/week @ 2024-08-02 1/week @ 2024-08-09 23/week @ 2024-08-16 44/week @ 2024-08-23 54/week @ 2024-08-30 35/week @ 2024-09-06 12/week @ 2024-09-13 33/week @ 2024-09-20 44/week @ 2024-09-27 20/week @ 2024-10-04 42/week @ 2024-10-11 14/week @ 2024-10-18 28/week @ 2024-10-25 51/week @ 2024-11-01

137 downloads per month
Used in 2 crates

MIT license

77KB
1K SLoC

LBFGS

Build Status GPL3 licensed

Fast and safe Rust implementation of LBFGS and OWL-QN algorithms ported from Naoaki Okazaki's C library libLBFGS.

Check rust-liblbfgs for a working wrapper around the original C codes.

Motivation

  • Bring native LBFGS implementation to Rust community.
  • Learn how a great optimization algorithm is implemented in real world.
  • Learn how to "replace the jet engine while still flying" URL
  • Make it more maintainable with Rust high level abstraction.
  • Improve it to meet my needs for computational chemistry.

Todo

  • Parallel with rayon
  • SIMD support
  • add option to disable line search for gradient only optimization
  • Fix issues inherited from liblbfgs URL

Features

  • Clean and safe Rust implementation.
  • OWL-QN algorithm.
  • Closure based callback interfaces.
  • Damped L-BFGS algorithm.

Usage

// 0. Import the lib
use liblbfgs::lbfgs;

const N: usize = 100;

// 1. Initialize data
let mut x = [0.0 as f64; N];
for i in (0..N).step_by(2) {
    x[i] = -1.2;
    x[i + 1] = 1.0;
}

// 2. Defining how to evaluate function and gradient
let evaluate = |x: &[f64], gx: &mut [f64]| {
    let n = x.len();

    let mut fx = 0.0;
    for i in (0..n).step_by(2) {
        let t1 = 1.0 - x[i];
        let t2 = 10.0 * (x[i + 1] - x[i] * x[i]);
        gx[i + 1] = 20.0 * t2;
        gx[i] = -2.0 * (x[i] * gx[i + 1] + t1);
        fx += t1 * t1 + t2 * t2;
    }

    Ok(fx)
};

let prb = lbfgs()
    .with_max_iterations(5)
    .with_orthantwise(1.0, 0, 99) // enable OWL-QN
    .minimize(
        &mut x,                   // input variables
        evaluate,                 // define how to evaluate function
        |prgr| {                  // define progress monitor
            println!("iter: {:}", prgr.niter);
            false                 // returning true will cancel optimization
        }
    )
    .expect("lbfgs owlqn minimize");

println!("fx = {:}", prb.fx);

The callback functions are native Rust FnMut closures, possible to capture/change variables in the environment.

Full codes with comments are available in examples/sample.rs.

Run the example:

cargo run --example sample

Dependencies

~220KB