use ndarray::ArrayViewMut1;
use crate::{operators::MutationOperator, random::RandomGenerator};
#[derive(Debug, Clone)]
pub struct InversionMutation;
impl MutationOperator for InversionMutation {
fn mutate<'a>(&self, mut individual: ArrayViewMut1<'a, f64>, rng: &mut impl RandomGenerator) {
let len = individual.len();
let mut start = rng.gen_range_usize(0, len);
let mut end = rng.gen_range_usize(0, len);
if start > end {
std::mem::swap(&mut start, &mut end);
}
for k in 0..((end - start + 1) / 2) {
let i = start + k;
let j = end - k;
let tmp = individual[i];
individual[i] = individual[j];
individual[j] = tmp;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::random::{RandomGenerator, TestDummyRng};
use ndarray::array;
struct FakeRandomGeneratorInversion {
dummy: TestDummyRng,
counter: usize,
}
impl FakeRandomGeneratorInversion {
fn new() -> Self {
Self {
dummy: TestDummyRng,
counter: 0,
}
}
}
impl RandomGenerator for FakeRandomGeneratorInversion {
type R = TestDummyRng;
fn rng(&mut self) -> &mut TestDummyRng {
&mut self.dummy
}
fn gen_range_usize(&mut self, low: usize, high: usize) -> usize {
let result = if self.counter == 0 { low + 1 } else { high - 2 };
self.counter += 1;
result
}
}
#[test]
fn test_inversion_mutation_controlled() {
let mut pop = array![[0.0, 1.0, 1.0, 0.0, 0.0, 1.0]];
let mutation_operator = InversionMutation;
let mut rng = FakeRandomGeneratorInversion::new();
mutation_operator.mutate(pop.row_mut(0), &mut rng);
let expected = array![0.0, 0.0, 0.0, 1.0, 1.0, 1.0];
assert_eq!(expected, pop.row(0));
}
}