gosh_lbfgs/
lib.rs

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