use optirs_core::optimizers::{Adam, Optimizer, LBFGS, SGD};
use scirs2_core::ndarray::Array1;
#[allow(dead_code)]
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("L-BFGS Optimizer Example");
println!("=======================");
let rosenbrock_fn = |x: &Array1<f64>| -> f64 {
let a = 1.0;
let b = 100.0;
let x_val = x[0];
let y_val = x[1];
(a - x_val).powi(2) + b * (y_val - x_val.powi(2)).powi(2)
};
let rosenbrock_grad = |x: &Array1<f64>| -> Array1<f64> {
let a = 1.0;
let b = 100.0;
let x_val = x[0];
let y_val = x[1];
let dx = -2.0 * (a - x_val) - 4.0 * b * x_val * (y_val - x_val.powi(2));
let dy = 2.0 * b * (y_val - x_val.powi(2));
Array1::from_vec(vec![dx, dy])
};
let initial_params = Array1::from_vec(vec![-1.5, 1.5]);
println!("Minimizing Rosenbrock function");
println!(
"Initial point: [{}, {}]",
initial_params[0], initial_params[1]
);
println!("Target minimum: [1.0, 1.0]");
println!();
let optimizers = vec![
(
"L-BFGS",
Box::new(LBFGS::new(0.1)) as Box<dyn Optimizer<f64, scirs2_core::ndarray::Ix1>>,
),
(
"Adam",
Box::new(Adam::new(0.01)) as Box<dyn Optimizer<f64, scirs2_core::ndarray::Ix1>>,
),
(
"SGD",
Box::new(SGD::new(0.001)) as Box<dyn Optimizer<f64, scirs2_core::ndarray::Ix1>>,
),
];
for (name, mut optimizer) in optimizers {
println!("Running {} optimizer:", name);
let mut params = initial_params.clone();
let initial_value = rosenbrock_fn(¶ms);
println!("Initial function value: {:.6}", initial_value);
let num_iterations = if name == "L-BFGS" { 50 } else { 200 };
for i in 0..num_iterations {
let gradients = rosenbrock_grad(¶ms);
params = optimizer.step(¶ms, &gradients)?;
if i % 10 == 0 || i == num_iterations - 1 {
let value = rosenbrock_fn(¶ms);
println!(
" Iteration {:3}: x = [{:7.4}, {:7.4}], f(x) = {:.6}",
i + 1,
params[0],
params[1],
value
);
}
}
let final_value = rosenbrock_fn(¶ms);
println!("Final point: [{:.6}, {:.6}]", params[0], params[1]);
println!("Final function value: {:.6}", final_value);
println!(
"Distance from optimum: {:.6}",
((params[0] - 1.0).powi(2) + (params[1] - 1.0).powi(2)).sqrt()
);
println!();
}
Ok(())
}
#[test]
#[allow(dead_code)]
fn test_lbfgs_on_rosenbrock() {
let mut optimizer = LBFGS::new(0.5);
let mut params = Array1::from_vec(vec![0.0, 0.0]);
let rosenbrock_grad = |x: &Array1<f64>| -> Array1<f64> {
let x_val = x[0];
let y_val = x[1];
let dx = -2.0 * (1.0 - x_val) - 400.0 * x_val * (y_val - x_val.powi(2));
let dy = 200.0 * (y_val - x_val.powi(2));
Array1::from_vec(vec![dx, dy])
};
for _ in 0..200 {
let gradients = rosenbrock_grad(¶ms);
params = optimizer.step(¶ms, &gradients).expect("unwrap failed");
}
assert!((params[0] - 1.0).abs() < 0.2);
assert!((params[1] - 1.0).abs() < 0.2);
}