use ndarray::ArrayViewMut1;
use rand_distr::{Distribution, Normal};
use crate::{operators::MutationOperator, random::RandomGenerator};
#[derive(Debug, Clone)]
pub struct GaussianMutation {
pub gene_mutation_rate: f64,
pub sigma: f64,
}
impl GaussianMutation {
pub fn new(gene_mutation_rate: f64, sigma: f64) -> Self {
Self {
gene_mutation_rate,
sigma,
}
}
}
impl MutationOperator for GaussianMutation {
fn mutate<'a>(&self, mut individual: ArrayViewMut1<'a, f64>, rng: &mut impl RandomGenerator) {
let normal_dist = Normal::new(0.0, self.sigma)
.expect("Failed to create normal distribution. Sigma must be > 0.");
for gene in individual.iter_mut() {
if rng.gen_bool(self.gene_mutation_rate) {
let delta = normal_dist.sample(rng.rng());
*gene += delta;
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::random::MOORandomGenerator;
use ndarray::array;
use rand::SeedableRng;
use rand::rngs::StdRng;
#[test]
fn test_gaussian_mutation_all_genes() {
let mut pop = array![[0.5, 0.5, 0.5]];
let pop_before_mut = array![[0.5, 0.5, 0.5]];
let mutation_operator = GaussianMutation::new(1.0, 0.1);
let mut rng = MOORandomGenerator::new(StdRng::seed_from_u64(42));
mutation_operator.operate(&mut pop, 1.0, &mut rng);
assert_ne!(pop, pop_before_mut);
println!("Original: {:?}", pop_before_mut);
println!("Mutated: {:?}", pop);
}
#[test]
fn test_gaussian_mutation_no_genes() {
let mut pop = array![[0.5, 0.5, 0.5]];
let expected = array![[0.5, 0.5, 0.5]];
let mutation_operator = GaussianMutation::new(0.0, 0.1);
let mut rng = MOORandomGenerator::new(StdRng::seed_from_u64(42));
mutation_operator.operate(&mut pop, 1.0, &mut rng);
assert_eq!(pop, expected);
}
}