1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
// docs
//
// Copyright (c) 1990, Jorge Nocedal
// Copyright (c) 2007-2010 Naoaki Okazaki
// Copyright (c) 2018-2019 Wenping Guo
// All rights reserved.
//
//! Limited memory BFGS (L-BFGS) algorithm ported from liblbfgs
//!
//! # Example
//! ```
//! // 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);
//! ```
// [[file:../lbfgs.note::*imports][imports:1]]
use crate::core::*;
mod base;
mod lbfgs;
mod lbfgs_iter;
pub mod line;
pub mod line_new;
pub mod math;
pub use crate::lbfgs::*;
pub(crate) mod core {
pub use anyhow::*;
pub use log::{debug, error, info, trace, warn};
}
// imports:1 ends here
// [[file:../lbfgs.note::*exports][exports:1]]
use crate::lbfgs::Lbfgs;
pub fn lbfgs() -> Lbfgs {
Lbfgs::default()
}
use crate::lbfgs_iter::Lbfgs as LbfgsIter;
pub fn lbfgs_iter() -> LbfgsIter {
crate::lbfgs_iter::Lbfgs::default()
}
pub use crate::base::Output;
// exports:1 ends here
// [[file:../lbfgs.note::*tests][tests:1]]
/// Default test function (rosenbrock) adopted from liblbfgs sample.c
pub fn default_evaluate() -> impl FnMut(&[f64], &mut [f64]) -> Result<f64> {
move |arr_x: &[f64], gx: &mut [f64]| {
let n = arr_x.len();
let mut fx = 0.0;
for i in (0..n).step_by(2) {
let t1 = 1.0 - arr_x[i];
let t2 = 10.0 * (arr_x[i + 1] - arr_x[i] * arr_x[i]);
gx[i + 1] = 20.0 * t2;
gx[i] = -2.0 * (arr_x[i] * gx[i + 1] + t1);
fx += t1 * t1 + t2 * t2;
}
Ok(fx)
}
}
/// Default progress monitor adopted from liblbfgs sample.c
///
/// # Notes
///
/// * Returning true will cancel the optimization process.
///
pub fn default_progress() -> impl FnMut(&Progress) -> bool {
move |prgr| {
println!("Iteration {}, Evaluation {}:", prgr.niter, prgr.neval);
println!(
" fx = {:-12.6} xnorm = {:-12.6}, gnorm = {:-12.6}, ls = {}, step = {}",
prgr.fx, prgr.xnorm, prgr.gnorm, prgr.ncall, prgr.step
);
false
}
}
// tests:1 ends here