use crate::point::*;
use ordered_float::OrderedFloat;
use num_traits::Float;
pub struct SearchSpace<'f_lifetime, CoordFloat: Float, ValueFloat: Float>
{
f: &'f_lifetime dyn Fn(&[CoordFloat]) -> ValueFloat,
hypercube: Vec<(CoordFloat, CoordFloat)>,
pub minimize: bool,
pub dimension: usize
}
impl<'f_lifetime, CoordFloat: Float, ValueFloat: Float> SearchSpace<'f_lifetime, CoordFloat, ValueFloat>
{
pub fn new(f: &'f_lifetime impl Fn(&[CoordFloat]) -> ValueFloat,
hypercube: &[(CoordFloat, CoordFloat)],
minimize: bool)
-> Self
{
let dimension = hypercube.len();
SearchSpace { f, hypercube: hypercube.to_vec(), minimize, dimension }
}
#[allow(dead_code)]
pub fn to_simplex(&self, c: Coordinates<CoordFloat>) -> Coordinates<CoordFloat>
{
let c: Coordinates<CoordFloat> =
c.into_iter().zip(self.hypercube.iter()).map(|(&x, &(inf, sup))| (x - inf) / (sup - inf)).collect();
let sum = c.iter().map(|&c| c).fold(CoordFloat::zero(), ::std::ops::Add::add); let max = c.iter()
.map(|&c| c)
.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.into_iter().map(|&x| x * ratio).collect()
}
pub fn to_hypercube(&self, c: Coordinates<CoordFloat>) -> Coordinates<CoordFloat>
{
let sum = c.iter().map(|&c| c).fold(CoordFloat::zero(), ::std::ops::Add::add); let max = c.iter()
.map(|&c| c)
.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.into_iter()
.zip(self.hypercube.iter())
.map(|(&x, &(inf, sup))| inf + x * ratio * (sup - inf))
.collect()
}
pub fn evaluate(&self, c: &Coordinates<CoordFloat>) -> ValueFloat
{
let c_hypercube = self.to_hypercube(c.clone());
let evaluation = (self.f)(&c_hypercube);
if self.minimize
{
-evaluation
}
else
{
evaluation
}
}
}