use crate::point::*;
use ordered_float::OrderedFloat;
use num_traits::{Float, float::FloatCore};
pub struct SearchSpace<F, CoordFloat, ValueFloat>
where F: FnMut(&[CoordFloat]) -> ValueFloat,
CoordFloat: Float + FloatCore,
ValueFloat: Float
{
f: F,
hypercube: Vec<(CoordFloat, CoordFloat)>,
pub minimize: bool,
pub dimension: usize,
pub history: Vec<(Coordinates<CoordFloat>, ValueFloat)>
}
impl<F, CoordFloat, ValueFloat> SearchSpace<F, CoordFloat, ValueFloat>
where F: FnMut(&[CoordFloat]) -> ValueFloat,
CoordFloat: Float + FloatCore,
ValueFloat: Float
{
pub fn new(f: F, hypercube: &[(CoordFloat, CoordFloat)], minimize: bool) -> Self
{
let dimension = hypercube.len();
let history = Vec::new();
SearchSpace { f, hypercube: hypercube.to_vec(), minimize, dimension, history }
}
pub fn to_simplex(&self, c: &[CoordFloat]) -> Coordinates<CoordFloat>
{
let c: Coordinates<CoordFloat> =
c.iter().zip(self.hypercube.iter()).map(|(&x, &(inf, sup))| (x - inf) / (sup - inf)).collect();
let sum = c.iter().copied().fold(CoordFloat::zero(), ::std::ops::Add::add); let max = c.iter()
.copied()
.max_by_key(|&c| OrderedFloat(c))
.expect("You should have at least one coordinate.");
let ratio = if sum.is_zero() { CoordFloat::zero() } else { max / sum };
c.iter().map(|&x| x * ratio).collect()
}
pub fn to_hypercube(&self, c: &[CoordFloat]) -> Coordinates<CoordFloat>
{
let sum = c.iter().copied().fold(CoordFloat::zero(), ::std::ops::Add::add); let max = c.iter()
.copied()
.max_by_key(|&c| OrderedFloat(c))
.expect("You should have at least one coordinate.");
let ratio = if max.is_zero() { CoordFloat::zero() } else { sum / max };
c.iter().zip(self.hypercube.iter()).map(|(&x, &(inf, sup))| inf + x * ratio * (sup - inf)).collect()
}
pub fn evaluate(&mut self, c: &Coordinates<CoordFloat>) -> ValueFloat
{
let c_hypercube = self.to_hypercube(c);
let evaluation = (self.f)(&c_hypercube);
self.history.push((c_hypercube, evaluation));
if self.minimize { -evaluation } else { evaluation }
}
}