#![cfg(feature = "problems")]
use basin::problems::Sphere;
use basin::{
BasicState, Executor, FiniteDiff, GradientDescent, GradientTolerance, TerminationReason,
};
#[test]
fn gradient_descent_on_finite_diff_sphere_converges() {
let problem = FiniteDiff::new(Sphere::<Vec<f64>>::new());
let initial = vec![1.5, -2.0, 0.75, 3.0];
let result = Executor::new(problem, GradientDescent::new(0.2), BasicState::new(initial))
.max_iter(500)
.terminate_on(GradientTolerance(1e-9))
.run();
assert_eq!(result.reason, TerminationReason::GradientTolerance);
assert!(result.cost() < 1e-12, "cost = {}", result.cost());
for (i, &xi) in result.param().iter().enumerate() {
assert!(xi.abs() < 1e-6, "x[{i}] = {xi} (expected near 0)");
}
}
#[cfg(feature = "nalgebra")]
mod nalgebra {
use basin::problems::RosenbrockResiduals;
use basin::{BasicState, Executor, FiniteDiff, LevenbergMarquardt, TerminationReason};
use nalgebra::DVector;
#[test]
fn levenberg_marquardt_on_finite_diff_jacobian_matches_analytic() {
let initial = DVector::from_vec(vec![-1.2, 1.0]);
let analytic = Executor::new(
RosenbrockResiduals::<DVector<f64>>::new(),
LevenbergMarquardt::new(),
BasicState::new(initial.clone()),
)
.max_iter(100)
.run();
let fd = Executor::new(
FiniteDiff::new(RosenbrockResiduals::<DVector<f64>>::new()),
LevenbergMarquardt::new(),
BasicState::new(initial),
)
.max_iter(100)
.run();
assert_eq!(fd.reason, TerminationReason::SolverConverged);
assert!(fd.cost() < 1e-12, "fd cost = {}", fd.cost());
assert!(
(fd.param()[0] - 1.0).abs() < 1e-6,
"x[0] = {}",
fd.param()[0]
);
assert!(
(fd.param()[1] - 1.0).abs() < 1e-6,
"x[1] = {}",
fd.param()[1]
);
assert!((fd.param()[0] - analytic.param()[0]).abs() < 1e-5);
assert!((fd.param()[1] - analytic.param()[1]).abs() < 1e-5);
}
}
#[cfg(feature = "faer")]
mod faer {
use basin::problems::RosenbrockResiduals;
use basin::{BasicState, Executor, FiniteDiff, LevenbergMarquardt, TerminationReason};
use faer::Col;
#[test]
fn levenberg_marquardt_on_finite_diff_jacobian_matches_analytic() {
let initial = Col::<f64>::from_fn(2, |i| [-1.2, 1.0][i]);
let fd = Executor::new(
FiniteDiff::new(RosenbrockResiduals::<Col<f64>>::new()),
LevenbergMarquardt::new(),
BasicState::new(initial),
)
.max_iter(100)
.run();
assert_eq!(fd.reason, TerminationReason::SolverConverged);
assert!(fd.cost() < 1e-12, "fd cost = {}", fd.cost());
assert!(
(fd.param()[0] - 1.0).abs() < 1e-6,
"x[0] = {}",
fd.param()[0]
);
assert!(
(fd.param()[1] - 1.0).abs() < 1e-6,
"x[1] = {}",
fd.param()[1]
);
}
}