use std::f64::consts::E;
use num_traits::{Num, Saturating};
use rand::prelude::{IteratorRandom, SliceRandom};
use rand::Rng;
use rand_distr::uniform::SampleUniform;
use rand_distr::{Distribution, Standard, StandardNormal};
pub fn mutate_swap<T: Copy>(s: &mut [T]) {
let mut r = rand::thread_rng();
s.swap(r.gen_range(0..s.len()), r.gen_range(0..s.len()));
}
pub fn mutate_insert<T: Copy>(s: &mut [T]) {
let mut r = rand::thread_rng();
let st = r.gen_range(0..s.len());
let en = r.gen_range(st..s.len());
for i in st..en {
s.swap(i, i + 1);
}
}
pub fn mutate_scramble<T: Copy>(s: &mut [T]) {
let mut r = rand::thread_rng();
let st = r.gen_range(0..s.len());
let en = r.gen_range(st..s.len());
s[st..=en].shuffle(&mut r);
}
pub fn mutate_inversion<T: Copy>(s: &mut [T]) {
let mut r = rand::thread_rng();
let st = r.gen_range(0..s.len());
let en = r.gen_range(st..s.len());
s[st..=en].reverse();
}
#[must_use]
pub fn mutate_gen<T>() -> T
where
Standard: Distribution<T>,
{
let mut r = rand::thread_rng();
r.gen::<T>()
}
pub fn mutate_reset<T>(s: &mut [T], v: T) {
let mut r = rand::thread_rng();
if let Some(ov) = s.iter_mut().choose(&mut r) {
*ov = v;
}
}
pub fn mutate_rate<T: Copy>(s: &mut [T], rate: f64, mut f: impl FnMut(T) -> T) {
let mut r = rand::thread_rng();
for v in s {
if r.gen::<f64>() < rate {
*v = f(*v);
}
}
}
#[must_use]
pub fn mutate_uniform(st: f64, en: f64) -> f64 {
let mut r = rand::thread_rng();
r.gen_range(st..=en)
}
#[must_use]
pub fn mutate_normal(v: f64, std: f64) -> f64 {
let mut r = rand::thread_rng();
v + std * r.sample::<f64, _>(StandardNormal)
}
#[must_use]
pub fn mutate_lognorm(v: f64, std: f64) -> f64 {
let mut r = rand::thread_rng();
v * E.powf(std * r.sample::<f64, _>(StandardNormal))
}
pub fn mutate_creep<T: Num + Saturating + SampleUniform + PartialOrd>(v: T, max_diff: T) -> T {
let mut r = rand::thread_rng();
let diff = r.gen_range(T::zero()..max_diff);
if r.gen::<bool>() { v.saturating_sub(diff) } else { v.saturating_add(diff) }
}