use ndarray::{ArrayViewMut1, s};
use crate::{operators::MutationOperator, random::RandomGenerator};
#[derive(Debug, Clone)]
pub struct ScrambleMutation {}
impl ScrambleMutation {
pub fn new() -> Self {
Self {}
}
}
impl MutationOperator for ScrambleMutation {
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 mut segment = individual.slice(s![start..end]).to_vec();
rng.shuffle_vec(&mut segment);
for (i, &value) in segment.iter().enumerate() {
individual[start + i] = value;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::random::{RandomGenerator, TestDummyRng};
use ndarray::{Array1, array};
use rstest::rstest;
struct FakeRandomGeneratorScramble {
usize_values: Vec<usize>,
fake_rng: TestDummyRng,
}
impl FakeRandomGeneratorScramble {
fn new(usize_values: Vec<usize>) -> Self {
Self {
usize_values,
fake_rng: TestDummyRng,
}
}
}
impl RandomGenerator for FakeRandomGeneratorScramble {
type R = TestDummyRng;
fn rng(&mut self) -> &mut TestDummyRng {
&mut self.fake_rng
}
fn gen_range_usize(&mut self, _min: usize, _max: usize) -> usize {
self.usize_values.remove(0)
}
fn shuffle_vec(&mut self, vector: &mut Vec<f64>) {
let vector_clone = vector.clone();
vector[0] = vector_clone[1];
vector[1] = vector_clone[0];
vector[2] = vector_clone[3];
vector[3] = vector_clone[2];
}
}
#[rstest(rng_boundaries,
case(vec![0, 4]),
case(vec![4, 0])
)]
fn test_scramble_mutation(rng_boundaries: Vec<usize>) {
let mut individual: Array1<f64> = array![0.0, 1.0, 2.0, 3.0, 4.0, 5.0];
let mut rng = FakeRandomGeneratorScramble::new(rng_boundaries);
let mutation_operator = ScrambleMutation::new();
{
let view = individual.view_mut();
mutation_operator.mutate(view, &mut rng);
}
let expected: Array1<f64> = array![1.0, 0.0, 3.0, 2.0, 4.0, 5.0];
assert_eq!(individual, expected);
}
#[test]
fn test_scramble_mutation_same_idx() {
let mut individual: Array1<f64> = array![0.0, 1.0, 2.0, 3.0, 4.0, 5.0];
let mut rng = FakeRandomGeneratorScramble::new(vec![0, 0]);
let mutation_operator = ScrambleMutation::new();
{
let view = individual.view_mut();
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);
}
}