use argmin::core::observers::{ObserverMode, SlogLogger};
use argmin::core::{Error, Executor, Jacobian, Operator};
use argmin::solver::gaussnewton::GaussNewtonLS;
use argmin::solver::linesearch::MoreThuenteLineSearch;
use ndarray::{Array1, Array2};
type Rate = f64;
type S = f64;
type Measurement = (S, Rate);
struct Problem {
data: Vec<Measurement>,
}
impl Operator for Problem {
type Param = Array1<f64>;
type Output = Array1<f64>;
fn apply(&self, p: &Self::Param) -> Result<Self::Output, Error> {
Ok(self
.data
.iter()
.map(|(s, rate)| rate - (p[0] * s) / (p[1] + s))
.collect::<Array1<f64>>())
}
}
impl Jacobian for Problem {
type Param = Array1<f64>;
type Jacobian = Array2<f64>;
fn jacobian(&self, p: &Self::Param) -> Result<Self::Jacobian, Error> {
Ok(Array2::from_shape_fn((self.data.len(), 2), |(si, i)| {
if i == 0 {
-self.data[si].0 / (p[1] + self.data[si].0)
} else {
p[0] * self.data[si].0 / (p[1] + self.data[si].0).powi(2)
}
}))
}
}
fn run() -> Result<(), Error> {
let cost = Problem {
data: vec![
(0.038, 0.050),
(0.194, 0.127),
(0.425, 0.094),
(0.626, 0.2122),
(1.253, 0.2729),
(2.5, 0.2665),
(3.74, 0.3317),
],
};
let linesearch = MoreThuenteLineSearch::new().with_bounds(0.0, 1.0)?;
let init_param: Array1<f64> = Array1::from(vec![0.9, 0.2]);
let solver = GaussNewtonLS::new(linesearch);
let res = Executor::new(cost, solver)
.configure(|state| state.param(init_param).max_iters(10))
.add_observer(SlogLogger::term(), ObserverMode::Always)
.run()?;
std::thread::sleep(std::time::Duration::from_secs(1));
println!("{res}");
Ok(())
}
fn main() {
if let Err(ref e) = run() {
println!("{e}");
std::process::exit(1);
}
}