use num::Zero;
use crate::vector::Vector;
pub fn golden_section(f: fn(f32) -> f32, a: f32, c: f32, tol: f32) -> f32 {
let phi = 1.618033988749894848204586834365638118_f32;
let mut a = a;
let mut b = c;
while (b - a).abs() > tol {
let c = b - (b - a) / phi;
let d = a + (b - a) / phi;
if f(c) < f(d) {
b = d;
} else {
a = c;
}
}
(b + a) / 2.0
}
fn co_sort<O: PartialOrd, T>(arr: &mut [O], co_arr: &mut [T]) {
for i in 1..arr.len() {
let mut j = i;
while j > 0 && arr[j] < arr[j - 1] {
arr.swap(j, j - 1);
co_arr.swap(j, j - 1);
j -= 1;
}
}
}
pub fn nelder_mead<const N: usize>(
f: fn(Vector<N>) -> f64,
p0: &Vector<N>,
max_iter: usize,
) -> Vector<N> {
let alpha = 1.0;
let gamma = 2.0;
let rho = 0.5;
let sigma = 0.5;
let mut xs: Vec<Vector<N>> = vec![*p0];
for i in 0..N {
let mut coeffs = p0.coeff;
coeffs[i] += 1.0;
xs.push(Vector { coeff: coeffs });
}
for _ in 0..max_iter {
let mut fs: Vec<f64> = xs.iter().map(|x| f(*x)).collect();
co_sort(&mut fs, &mut xs);
let mut x0 = Vector::zero();
for i in 0..N {
x0 = x0 + xs[i];
}
x0 = x0 / N as f64;
let xr = x0 + (x0 - xs[N]) * alpha;
let fr = f(xr);
if fs[0] <= fr && fr <= fs[N - 1] {
xs[N] = xr;
continue;
}
if fr < fs[0] {
let xe = x0 + (xr - x0) * gamma;
let fe = f(xe);
if fe < fr {
xs[N] = xe;
} else {
xs[N] = xr;
}
continue;
}
if fr < fs[N] {
let xc = x0 + (xr - x0) * rho;
let fc = f(xc);
if fc < fr {
xs[N] = xc;
continue;
}
} else {
let xc = x0 + (xs[N] - x0) * rho;
let fc = f(xc);
if fc < fs[N] {
xs[N] = xc;
continue;
}
}
for i in 0..xs.len() {
xs[i] = xs[0] + (xs[i] - xs[0]) * sigma;
}
}
let mut x0 = Vector::zero();
for i in 0..N {
x0 = x0 + xs[i];
}
x0 / N as f64
}