use crate::strategy::PopulationY;
use anyhow::Result;
use nalgebra::DVector;
#[derive(Debug, Clone)]
pub struct Fitness {
pub values: DVector<f32>, }
pub trait FitnessEvaluator {
type IndividualsEvaluated;
type ObjectiveDim;
fn evaluate(&self, pop: &PopulationY) -> Result<Self::IndividualsEvaluated>;
fn evaluator_dim(&self) -> Result<Self::ObjectiveDim>;
}
pub fn allow_objective_func<E: FitnessEvaluator>(
objective_function: E,
) -> Result<(E, E::ObjectiveDim)> {
let objective_dim = objective_function.evaluator_dim()?;
Ok((objective_function, objective_dim))
}
pub struct SquareAndSum {
pub obj_dim: usize,
}
impl SquareAndSum {
pub fn cost(&self, pop: &PopulationY) -> DVector<f32> {
pop.y
.row_iter()
.map(|row| row.iter().map(|x| x.powi(2)).sum())
.collect::<Vec<f32>>()
.into()
}
pub fn cost_dim(&self) -> usize {
self.obj_dim
}
}
impl FitnessEvaluator for SquareAndSum {
type IndividualsEvaluated = Fitness;
type ObjectiveDim = usize;
fn evaluate(&self, pop: &PopulationY) -> Result<Self::IndividualsEvaluated> {
let values = self.cost(pop);
let fitness = Fitness { values };
Ok(fitness)
}
fn evaluator_dim(&self) -> Result<Self::ObjectiveDim> {
Ok(self.cost_dim())
}
}
pub struct StdAndSum {
pub obj_dim: usize,
}
impl StdAndSum {
pub fn cost(&self, pop: &PopulationY) -> DVector<f32> {
pop.y
.row_iter()
.map(|row| {
let mean = row.mean();
let variance =
row.iter().map(|&x| (x - mean).powi(2)).sum::<f32>() / row.len() as f32;
variance.sqrt()
})
.collect::<Vec<f32>>()
.into()
}
pub fn cost_dim(&self) -> usize {
self.obj_dim
}
}
impl FitnessEvaluator for StdAndSum {
type IndividualsEvaluated = Fitness;
type ObjectiveDim = usize;
fn evaluate(&self, pop: &PopulationY) -> Result<Self::IndividualsEvaluated> {
let values = self.cost(pop);
let fitness = Fitness { values };
Ok(fitness)
}
fn evaluator_dim(&self) -> Result<Self::ObjectiveDim> {
Ok(self.cost_dim())
}
}
pub struct Rastrigin {
pub obj_dim: usize,
}
impl Rastrigin {
pub fn cost(&self, pop: &PopulationY) -> DVector<f32> {
let (a, pi) = (10.0, std::f32::consts::PI);
pop.y
.row_iter()
.map(|row| {
row.iter()
.map(|x| x.powi(2) - a * (2.0 * pi * x).cos() + a)
.sum()
})
.collect::<Vec<f32>>()
.into()
}
pub fn cost_dim(&self) -> usize {
self.obj_dim
}
}
impl FitnessEvaluator for Rastrigin {
type IndividualsEvaluated = Fitness;
type ObjectiveDim = usize;
fn evaluate(&self, pop: &PopulationY) -> Result<Self::IndividualsEvaluated> {
let values = self.cost(pop);
let fitness = Fitness { values };
Ok(fitness)
}
fn evaluator_dim(&self) -> Result<Self::ObjectiveDim> {
Ok(self.cost_dim())
}
}