use ndarray::{Array2, ArrayViewMut1};
pub trait RepairOperator: std::fmt::Debug {
fn repair(&self, individual: ArrayViewMut1<f64>);
fn operate(&self, population: &mut Array2<f64>) {
for individual in population.outer_iter_mut() {
self.repair(individual);
}
}
}
#[derive(Debug, Clone, Default)]
pub struct NoRepair;
impl RepairOperator for NoRepair {
#[inline]
fn repair(&self, _individual: ArrayViewMut1<f64>) {}
#[inline]
fn operate(&self, _population: &mut Array2<f64>) {}
}
#[cfg(test)]
mod tests {
use super::*;
use ndarray::{Array2, array};
#[derive(Debug)]
struct ClampRepair {
min: f64,
max: f64,
}
impl RepairOperator for ClampRepair {
fn repair(&self, mut individual: ArrayViewMut1<f64>) {
individual.mapv_inplace(|g| g.clamp(self.min, self.max));
}
}
#[test]
fn no_repair_leaves_individual_unchanged() {
let original = array![1.5, -0.3, 99.0];
let mut individual = original.clone();
NoRepair.repair(individual.view_mut());
assert_eq!(individual, original);
}
#[test]
fn no_repair_leaves_population_unchanged() {
let original = array![[1.5, -0.3], [99.0, 0.5]];
let mut pop = original.clone();
NoRepair.operate(&mut pop);
assert_eq!(pop, original);
}
#[test]
fn clamp_repair_fixes_out_of_bounds_individual() {
let repair = ClampRepair { min: 0.0, max: 1.0 };
let mut individual = array![-0.5, 0.5, 1.5];
repair.repair(individual.view_mut());
assert_eq!(individual, array![0.0, 0.5, 1.0]);
}
#[test]
fn operate_default_applies_repair_to_all_rows() {
let repair = ClampRepair { min: 0.0, max: 1.0 };
let mut pop = array![[-1.0, 0.5], [0.3, 2.0]];
repair.operate(&mut pop);
assert_eq!(pop, array![[0.0, 0.5], [0.3, 1.0]]);
}
#[test]
fn operate_on_empty_population_does_not_panic() {
let repair = ClampRepair { min: 0.0, max: 1.0 };
let mut pop = Array2::<f64>::zeros((0, 3));
repair.operate(&mut pop);
assert_eq!(pop.nrows(), 0);
}
}