use ndarray::prelude::*;
use rand::Rng;
use rand_distr::{Distribution, StandardNormal, Uniform};
use num_traits::Float;
use crate::repro_rng::thread_rng;
pub fn gaussian<D, F>(arr: &mut Array<F, D>, indpb: f64, stdev: F)
where
F: Float + std::ops::AddAssign + std::fmt::Debug,
D: Dimension,
StandardNormal: Distribution<F>,
{
assert!(
stdev.is_finite() && stdev >= F::zero(),
"{:?} is not a valid standard deviation",
stdev
);
let mut rng = thread_rng();
arr.map_inplace(|elem| {
if rng.gen_bool(indpb) {
*elem += stdev * StandardNormal.sample(&mut rng);
}
})
}
pub fn gaussian_with<F, D>(
arr: &mut Array<F, D>,
probabilities: &Array<f64, D>,
stdevs: &Array<F, D>,
) where
F: Float + std::ops::AddAssign + std::fmt::Debug,
D: Dimension,
StandardNormal: Distribution<F>,
{
let mut rng = thread_rng();
azip!((elem in arr, &stdev in stdevs, &indpb in probabilities) {
assert!(stdev.is_finite() && stdev >= F::zero(), "{:?} is not a valid standard deviation", stdev);
if rng.gen_bool(indpb) {
*elem += stdev * StandardNormal.sample(&mut rng);
}
});
}
pub fn shuffle<T, D>(arr: &mut Array<T, D>, indpb: f64)
where
D: Dimension,
{
if let Some(slice) = arr.as_slice_memory_order_mut() {
let mut rng = thread_rng();
let len = slice.len();
let distr = Uniform::new(0, len);
for i in 0..slice.len() {
if rng.gen_bool(indpb) {
slice.swap(i, distr.sample(&mut rng));
}
}
} else {
panic!("array passed to shuffle must be contiguous");
}
}