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
// 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:~/Workspace/Programming/gosh-rs/lbfgs/lbfgs.note::*imports][imports:1]]
use crate::core::*;

mod lbfgs;
pub mod line;
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:~/Workspace/Programming/gosh-rs/lbfgs/lbfgs.note::*lbfgs][lbfgs:1]]
use crate::lbfgs::Lbfgs;

pub fn lbfgs() -> Lbfgs {
    Lbfgs::default()
}
// lbfgs:1 ends here

// [[file:~/Workspace/Programming/gosh-rs/lbfgs/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