use crate::{
core::{
context::Context, individual::Individual, offspring::Offspring, population::Population,
state::State,
},
fitness::FitnessEvaluator,
operators::GeneticOperator,
};
use rand::{Rng, RngExt};
#[derive(Debug, Clone, Copy)]
pub struct Gaussian {
std_dev: f64,
min: Option<f64>,
max: Option<f64>,
}
impl Gaussian {
pub fn new(std_dev: f64) -> Self {
Self { std_dev, min: None, max: None }
}
pub fn min(mut self, min: f64) -> Self {
self.min = Some(min);
self
}
pub fn max(mut self, max: f64) -> Self {
self.max = Some(max);
self
}
}
fn box_muller(rng: &mut impl Rng) -> f64 {
let u1: f64 = rng.random();
let u2: f64 = rng.random();
(-2.0 * u1.ln()).sqrt() * (std::f64::consts::TAU * u2).cos()
}
impl<F, Fe, R, C, const N: usize> GeneticOperator<[f64; N], F, Fe, R, C> for Gaussian
where
R: Rng,
Fe: FitnessEvaluator<[f64; N], F>,
{
fn apply(
&self,
state: &State<[f64; N], F>,
ctx: &mut Context<Fe, R, C>,
) -> Offspring<[f64; N], F> {
let mut population = Population::with_capacity(state.population().len());
for individual in state.population() {
let mut genome = *individual.genome();
let idx = ctx.rng().random_range(0..N);
genome[idx] += box_muller(ctx.rng()) * self.std_dev;
if let Some(min) = self.min { genome[idx] = genome[idx].max(min); }
if let Some(max) = self.max { genome[idx] = genome[idx].min(max); }
population.add(Individual::new(genome));
}
Offspring::Multiple(population)
}
fn transform(
&self,
state: State<[f64; N], F>,
ctx: &mut Context<Fe, R, C>,
) -> Offspring<[f64; N], F> {
let std_dev = self.std_dev;
let min = self.min;
let max = self.max;
let population = state
.into_population()
.into_iter()
.map(|ind| {
ind.mutate_genome(|genome| {
let idx = ctx.rng().random_range(0..N);
genome[idx] += box_muller(ctx.rng()) * std_dev;
if let Some(lo) = min { genome[idx] = genome[idx].max(lo); }
if let Some(hi) = max { genome[idx] = genome[idx].min(hi); }
})
})
.collect();
Offspring::Multiple(population)
}
}
impl<F, Fe, R, C> GeneticOperator<Vec<f64>, F, Fe, R, C> for Gaussian
where
R: Rng,
Fe: FitnessEvaluator<Vec<f64>, F>,
{
fn apply(
&self,
state: &State<Vec<f64>, F>,
ctx: &mut Context<Fe, R, C>,
) -> Offspring<Vec<f64>, F> {
let mut population = Population::with_capacity(state.population().len());
for individual in state.population() {
let mut genome = individual.genome().clone();
let idx = ctx.rng().random_range(0..genome.len());
genome[idx] += box_muller(ctx.rng()) * self.std_dev;
if let Some(min) = self.min { genome[idx] = genome[idx].max(min); }
if let Some(max) = self.max { genome[idx] = genome[idx].min(max); }
population.add(Individual::new(genome));
}
Offspring::Multiple(population)
}
fn transform(
&self,
state: State<Vec<f64>, F>,
ctx: &mut Context<Fe, R, C>,
) -> Offspring<Vec<f64>, F> {
let std_dev = self.std_dev;
let min = self.min;
let max = self.max;
let population = state
.into_population()
.into_iter()
.map(|ind| {
ind.mutate_genome(|genome| {
let idx = ctx.rng().random_range(0..genome.len());
genome[idx] += box_muller(ctx.rng()) * std_dev;
if let Some(lo) = min { genome[idx] = genome[idx].max(lo); }
if let Some(hi) = max { genome[idx] = genome[idx].min(hi); }
})
})
.collect();
Offspring::Multiple(population)
}
}
impl<F, Fe, R, C, const N: usize> GeneticOperator<[f32; N], F, Fe, R, C> for Gaussian
where
R: Rng,
Fe: FitnessEvaluator<[f32; N], F>,
{
fn apply(
&self,
state: &State<[f32; N], F>,
ctx: &mut Context<Fe, R, C>,
) -> Offspring<[f32; N], F> {
let mut population = Population::with_capacity(state.population().len());
for individual in state.population() {
let mut genome = *individual.genome();
let idx = ctx.rng().random_range(0..N);
genome[idx] += (box_muller(ctx.rng()) * self.std_dev) as f32;
if let Some(min) = self.min { genome[idx] = genome[idx].max(min as f32); }
if let Some(max) = self.max { genome[idx] = genome[idx].min(max as f32); }
population.add(Individual::new(genome));
}
Offspring::Multiple(population)
}
fn transform(
&self,
state: State<[f32; N], F>,
ctx: &mut Context<Fe, R, C>,
) -> Offspring<[f32; N], F> {
let std_dev = self.std_dev;
let min = self.min;
let max = self.max;
let population = state
.into_population()
.into_iter()
.map(|ind| {
ind.mutate_genome(|genome| {
let idx = ctx.rng().random_range(0..N);
genome[idx] += (box_muller(ctx.rng()) * std_dev) as f32;
if let Some(lo) = min { genome[idx] = genome[idx].max(lo as f32); }
if let Some(hi) = max { genome[idx] = genome[idx].min(hi as f32); }
})
})
.collect();
Offspring::Multiple(population)
}
}
impl<F, Fe, R, C> GeneticOperator<Vec<f32>, F, Fe, R, C> for Gaussian
where
R: Rng,
Fe: FitnessEvaluator<Vec<f32>, F>,
{
fn apply(
&self,
state: &State<Vec<f32>, F>,
ctx: &mut Context<Fe, R, C>,
) -> Offspring<Vec<f32>, F> {
let mut population = Population::with_capacity(state.population().len());
for individual in state.population() {
let mut genome = individual.genome().clone();
let idx = ctx.rng().random_range(0..genome.len());
genome[idx] += (box_muller(ctx.rng()) * self.std_dev) as f32;
if let Some(min) = self.min { genome[idx] = genome[idx].max(min as f32); }
if let Some(max) = self.max { genome[idx] = genome[idx].min(max as f32); }
population.add(Individual::new(genome));
}
Offspring::Multiple(population)
}
fn transform(
&self,
state: State<Vec<f32>, F>,
ctx: &mut Context<Fe, R, C>,
) -> Offspring<Vec<f32>, F> {
let std_dev = self.std_dev;
let min = self.min;
let max = self.max;
let population = state
.into_population()
.into_iter()
.map(|ind| {
ind.mutate_genome(|genome| {
let idx = ctx.rng().random_range(0..genome.len());
genome[idx] += (box_muller(ctx.rng()) * std_dev) as f32;
if let Some(lo) = min { genome[idx] = genome[idx].max(lo as f32); }
if let Some(hi) = max { genome[idx] = genome[idx].min(hi as f32); }
})
})
.collect();
Offspring::Multiple(population)
}
}