use ffi::FFI;
use sys;
ffi_wrapper!(
Minimizer<'a>,
*mut sys::gsl_min_fminimizer,
gsl_min_fminimizer_free
;inner_call: sys::gsl_function_struct => sys::gsl_function_struct { function: None, params: std::ptr::null_mut() };
;inner_closure: Option<Box<dyn Fn(f64) -> f64 + 'a>> => None;
);
impl<'a> Minimizer<'a> {
#[doc(alias = "gsl_min_fminimizer_alloc")]
pub fn new(t: MinimizerType) -> Option<Minimizer<'a>> {
let ptr = unsafe { sys::gsl_min_fminimizer_alloc(t.unwrap_shared()) };
if ptr.is_null() {
None
} else {
Some(Self::wrap(ptr))
}
}
#[doc(alias = "gsl_min_fminimizer_set")]
pub fn set<F: Fn(f64) -> f64 + 'a>(
&mut self,
f: F,
x_minimum: f64,
x_lower: f64,
x_upper: f64,
) -> ::Value {
self.inner_call = wrap_callback!(f, F + 'a);
self.inner_closure = Some(Box::new(f));
::Value::from(unsafe {
sys::gsl_min_fminimizer_set(
self.unwrap_unique(),
&mut self.inner_call,
x_minimum,
x_lower,
x_upper,
)
})
}
#[doc(alias = "gsl_min_fminimizer_set_with_values")]
pub fn set_with_values<F: Fn(f64) -> f64 + 'a>(
&mut self,
f: F,
x_minimum: f64,
f_minimum: f64,
x_lower: f64,
f_lower: f64,
x_upper: f64,
f_upper: f64,
) -> ::Value {
self.inner_call = wrap_callback!(f, F + 'a);
self.inner_closure = Some(Box::new(f));
::Value::from(unsafe {
sys::gsl_min_fminimizer_set_with_values(
self.unwrap_unique(),
&mut self.inner_call,
x_minimum,
f_minimum,
x_lower,
f_lower,
x_upper,
f_upper,
)
})
}
#[doc(alias = "gsl_min_fminimizer_name")]
pub fn name(&self) -> Option<String> {
let n = unsafe { sys::gsl_min_fminimizer_name(self.unwrap_shared()) };
if n.is_null() {
return None;
}
let mut len = 0;
loop {
if unsafe { *n.offset(len) } == 0 {
break;
}
len += 1;
}
let slice = unsafe { ::std::slice::from_raw_parts(n as _, len as _) };
::std::str::from_utf8(slice).ok().map(|x| x.to_owned())
}
#[doc(alias = "gsl_min_fminimizer_x_minimum")]
pub fn x_minimum(&self) -> f64 {
unsafe { sys::gsl_min_fminimizer_x_minimum(self.unwrap_shared()) }
}
#[doc(alias = "gsl_min_fminimizer_x_lower")]
pub fn x_lower(&self) -> f64 {
unsafe { sys::gsl_min_fminimizer_x_lower(self.unwrap_shared()) }
}
#[doc(alias = "gsl_min_fminimizer_x_upper")]
pub fn x_upper(&self) -> f64 {
unsafe { sys::gsl_min_fminimizer_x_upper(self.unwrap_shared()) }
}
#[doc(alias = "gsl_min_fminimizer_f_minimum")]
pub fn f_minimum(&self) -> f64 {
unsafe { sys::gsl_min_fminimizer_f_minimum(self.unwrap_shared()) }
}
#[doc(alias = "gsl_min_fminimizer_f_lower")]
pub fn f_lower(&self) -> f64 {
unsafe { sys::gsl_min_fminimizer_f_lower(self.unwrap_shared()) }
}
#[doc(alias = "gsl_min_fminimizer_f_upper")]
pub fn f_upper(&self) -> f64 {
unsafe { sys::gsl_min_fminimizer_f_upper(self.unwrap_shared()) }
}
#[doc(alias = "gsl_min_fminimizer_minimum")]
pub fn minimum(&self) -> f64 {
unsafe { sys::gsl_min_fminimizer_minimum(self.unwrap_shared()) }
}
#[doc(alias = "gsl_min_fminimizer_iterate")]
pub fn iterate(&mut self) -> ::Value {
::Value::from(unsafe { sys::gsl_min_fminimizer_iterate(self.unwrap_unique()) })
}
}
ffi_wrapper!(MinimizerType, *const sys::gsl_min_fminimizer_type);
impl MinimizerType {
#[doc(alias = "gsl_min_fminimizer_goldensection")]
pub fn goldensection() -> Self {
ffi_wrap!(gsl_min_fminimizer_goldensection)
}
#[doc(alias = "gsl_min_fminimizer_brent")]
pub fn brent() -> Self {
ffi_wrap!(gsl_min_fminimizer_brent)
}
#[doc(alias = "gsl_min_fminimizer_quad_golden")]
pub fn quad_golden() -> Self {
ffi_wrap!(gsl_min_fminimizer_quad_golden)
}
}
#[cfg(any(test, doctest))]
mod test {
use super::*;
use minimizer::test_interval;
fn quadratic_test_fn(x: f64) -> f64 {
x.powf(2.0) - 5.0
}
#[test]
fn test_min() {
let mut min = Minimizer::new(MinimizerType::brent()).unwrap();
min.set(&quadratic_test_fn, 1.0, -5.0, 5.0);
let max_iter = 5_usize;
let eps_abs = 0.0001;
let eps_rel = 0.0000001;
let mut status = ::Value::Continue;
let mut iter = 0_usize;
while matches!(status, ::Value::Continue) && iter < max_iter {
status = min.iterate();
let r = min.minimum();
let x_lo = min.x_lower();
let x_hi = min.x_upper();
status = test_interval(x_lo, x_hi, eps_abs, eps_rel);
if matches!(status, ::Value::Success) {
println!("Converged");
}
println!("{} [{}, {}] {} {}", iter, x_lo, x_hi, r, x_hi - x_lo);
iter += 1;
}
}
}