use ndarray::{Array1, ArrayViewMut1, Axis, concatenate, s};
use crate::{operators::MutationOperator, random::RandomGenerator};
#[derive(Debug, Clone)]
pub struct DisplacementMutation {}
impl DisplacementMutation {
pub fn new() -> Self {
Self {}
}
}
impl MutationOperator for DisplacementMutation {
fn mutate<'a>(&self, mut individual: ArrayViewMut1<'a, f64>, rng: &mut impl RandomGenerator) {
let n = individual.len();
let idx1 = rng.gen_range_usize(0, n);
let idx2 = rng.gen_range_usize(0, n);
let (start, end) = if idx1 <= idx2 {
(idx1, idx2)
} else {
(idx2, idx1)
};
if start == end {
return;
}
let left: Array1<f64> = individual.slice(s![0..start]).to_owned();
let segment: Array1<f64> = individual.slice(s![start..end]).to_owned();
let right: Array1<f64> = individual.slice(s![end..]).to_owned();
let remainder = concatenate![Axis(0), left, right];
let remainder_len = remainder.len();
let new_index = rng.gen_range_usize(0, remainder_len + 1);
let remainder_left = remainder.slice(s![0..new_index]).to_owned();
let remainder_right = remainder.slice(s![new_index..]).to_owned();
let new_individual = concatenate![Axis(0), remainder_left, segment, remainder_right];
individual.assign(&new_individual);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::random::{RandomGenerator, TestDummyRng};
use ndarray::{Array1, array};
use rstest::rstest;
struct FakeRandomGeneratorDisplacement {
usize_values: Vec<usize>,
dummy: TestDummyRng,
}
impl FakeRandomGeneratorDisplacement {
fn new(usize_values: Vec<usize>) -> Self {
Self {
usize_values,
dummy: TestDummyRng,
}
}
}
impl RandomGenerator for FakeRandomGeneratorDisplacement {
type R = TestDummyRng;
fn rng(&mut self) -> &mut TestDummyRng {
&mut self.dummy
}
fn gen_range_usize(&mut self, _min: usize, _max: usize) -> usize {
self.usize_values.remove(0)
}
}
#[rstest(rng_values,
case(vec![2, 5, 1]),
case(vec![5, 2, 1])
)]
fn test_displacement_mutation(rng_values: Vec<usize>) {
let mut individual: Array1<f64> = array![0.0, 1.0, 2.0, 3.0, 4.0, 5.0];
{
let view = individual.view_mut();
let mut rng = FakeRandomGeneratorDisplacement::new(rng_values);
let mutation_operator = DisplacementMutation::new();
mutation_operator.mutate(view, &mut rng);
}
let expected: Array1<f64> = array![0.0, 2.0, 3.0, 4.0, 1.0, 5.0];
assert_eq!(individual, expected);
}
#[test]
fn test_displacement_mutation_same_idx() {
let mut individual: Array1<f64> = array![0.0, 1.0, 2.0, 3.0, 4.0, 5.0];
{
let view = individual.view_mut();
let mut rng = FakeRandomGeneratorDisplacement::new(vec![0, 0]);
let mutation_operator = DisplacementMutation::new();
mutation_operator.mutate(view, &mut rng);
}
let expected: Array1<f64> = array![0.0, 1.0, 2.0, 3.0, 4.0, 5.0];
assert_eq!(individual, expected);
}
}