use crate::random::core::Random;
use crate::random::distributions::{Beta, Dirichlet, MultivariateNormal, VonMises, WeightedChoice};
use ::ndarray::{
Array, Array1, Array2, Array3, ArrayBase, Data, DataMut, DataOwned, Dimension, Ix1, Ix2, Ix3,
ShapeBuilder,
};
use rand::{Rng, RngExt};
use rand_distr::{Distribution, Normal, Uniform};
use std::marker::PhantomData;
#[derive(Debug, Clone, Copy)]
pub struct StandardNormal;
impl Distribution<f64> for StandardNormal {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
Normal::new(0.0, 1.0).expect("Operation failed").sample(rng)
}
}
impl Distribution<f32> for StandardNormal {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f32 {
Normal::new(0.0f32, 1.0f32)
.expect("Operation failed")
.sample(rng)
}
}
#[derive(Debug, Clone, Copy)]
pub struct StandardUniform;
impl Distribution<f64> for StandardUniform {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
Uniform::new(0.0, 1.0)
.expect("Operation failed")
.sample(rng)
}
}
impl Distribution<f32> for StandardUniform {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f32 {
Uniform::new(0.0f32, 1.0f32)
.expect("Operation failed")
.sample(rng)
}
}
pub trait RandomExt<A, D: Dimension> {
fn random<Dist, R>(shape: D, distribution: Dist, rng: &mut Random<R>) -> Self
where
Dist: Distribution<A>,
R: Rng;
fn random_using<F, R>(shape: D, rng: &mut Random<R>, f: F) -> Self
where
F: FnMut() -> A,
R: Rng;
fn standard_normal<R>(shape: D, rng: &mut Random<R>) -> Self
where
A: From<f64>,
R: Rng;
fn standard_uniform<R>(shape: D, rng: &mut Random<R>) -> Self
where
A: From<f64>,
R: Rng;
fn normal<R>(shape: D, mean: f64, std: f64, rng: &mut Random<R>) -> Self
where
A: From<f64>,
R: Rng;
fn uniform<R>(shape: D, low: f64, high: f64, rng: &mut Random<R>) -> Self
where
A: From<f64>,
R: Rng;
fn beta<R>(shape: D, alpha: f64, beta: f64, rng: &mut Random<R>) -> Self
where
A: From<f64>,
R: Rng;
fn exponential<R>(shape: D, lambda: f64, rng: &mut Random<R>) -> Self
where
A: From<f64>,
R: Rng;
fn randint<R>(shape: D, low: i64, high: i64, rng: &mut Random<R>) -> Self
where
A: From<i64>,
R: Rng;
}
impl<A, S, D> RandomExt<A, D> for ArrayBase<S, D>
where
S: DataOwned<Elem = A>,
D: Dimension,
A: Clone,
{
fn random<Dist, R>(shape: D, distribution: Dist, rng: &mut Random<R>) -> Self
where
Dist: Distribution<A>,
R: Rng,
{
let size = shape.size();
let values: Vec<A> = (0..size)
.map(|_| distribution.sample(&mut rng.rng))
.collect();
Self::from_shape_vec(shape, values).expect("Operation failed")
}
fn random_using<F, R>(shape: D, rng: &mut Random<R>, mut f: F) -> Self
where
F: FnMut() -> A,
R: Rng,
{
let size = shape.size();
let values: Vec<A> = (0..size).map(|_| f()).collect();
Self::from_shape_vec(shape, values).expect("Operation failed")
}
fn standard_normal<R>(shape: D, rng: &mut Random<R>) -> Self
where
A: From<f64>,
R: Rng,
{
let normal_dist = Normal::new(0.0, 1.0).expect("Operation failed");
let size = shape.size();
let values: Vec<A> = (0..size)
.map(|_| A::from(normal_dist.sample(&mut rng.rng)))
.collect();
Self::from_shape_vec(shape, values).expect("Operation failed")
}
fn standard_uniform<R>(shape: D, rng: &mut Random<R>) -> Self
where
A: From<f64>,
R: Rng,
{
let uniform_dist = Uniform::new(0.0, 1.0).expect("Operation failed");
let size = shape.size();
let values: Vec<A> = (0..size)
.map(|_| A::from(uniform_dist.sample(&mut rng.rng)))
.collect();
Self::from_shape_vec(shape, values).expect("Operation failed")
}
fn normal<R>(shape: D, mean: f64, std: f64, rng: &mut Random<R>) -> Self
where
A: From<f64>,
R: Rng,
{
let normal_dist = Normal::new(mean, std).expect("Operation failed");
let size = shape.size();
let values: Vec<A> = (0..size)
.map(|_| A::from(normal_dist.sample(&mut rng.rng)))
.collect();
Self::from_shape_vec(shape, values).expect("Operation failed")
}
fn uniform<R>(shape: D, low: f64, high: f64, rng: &mut Random<R>) -> Self
where
A: From<f64>,
R: Rng,
{
let uniform_dist = Uniform::new(low, high).expect("Operation failed");
let size = shape.size();
let values: Vec<A> = (0..size)
.map(|_| A::from(uniform_dist.sample(&mut rng.rng)))
.collect();
Self::from_shape_vec(shape, values).expect("Operation failed")
}
fn beta<R>(shape: D, alpha: f64, beta: f64, rng: &mut Random<R>) -> Self
where
A: From<f64>,
R: Rng,
{
let beta_dist = Beta::new(alpha, beta).expect("Operation failed");
let size = shape.size();
let mut values = Vec::with_capacity(size);
for _ in 0..size {
let sample_val = beta_dist.sample(rng);
values.push(A::from(sample_val));
}
Self::from_shape_vec(shape, values).expect("Operation failed")
}
fn exponential<R>(shape: D, lambda: f64, rng: &mut Random<R>) -> Self
where
A: From<f64>,
R: Rng,
{
let exp_dist = rand_distr::Exp::new(lambda).expect("Operation failed");
let size = shape.size();
let values: Vec<A> = (0..size)
.map(|_| A::from(exp_dist.sample(&mut rng.rng)))
.collect();
Self::from_shape_vec(shape, values).expect("Operation failed")
}
fn randint<R>(shape: D, low: i64, high: i64, rng: &mut Random<R>) -> Self
where
A: From<i64>,
R: Rng,
{
let int_dist = Uniform::new(low, high).expect("Operation failed");
let size = shape.size();
let values: Vec<A> = (0..size)
.map(|_| A::from(int_dist.sample(&mut rng.rng)))
.collect();
Self::from_shape_vec(shape, values).expect("Operation failed")
}
}
pub trait ScientificRandomExt<A, D: Dimension> {
fn dirichlet<R>(shape: D, alpha: &[f64], rng: &mut Random<R>) -> Self
where
A: From<f64>,
R: Rng;
fn von_mises<R>(shape: D, mu: f64, kappa: f64, rng: &mut Random<R>) -> Self
where
A: From<f64>,
R: Rng;
fn multivariate_normal<R>(
mean: Vec<f64>,
covariance: Vec<Vec<f64>>,
n_samples: usize,
rng: &mut Random<R>,
) -> Array<A, crate::ndarray::Ix2>
where
A: From<f64>,
R: Rng;
fn categorical<R, T>(
shape: D,
choices: &[T],
probabilities: &[f64],
rng: &mut Random<R>,
) -> Array<T, D>
where
T: Clone,
R: Rng;
fn correlated_normal<R>(
shape: D,
correlation_matrix: &Array<f64, crate::ndarray::Ix2>,
rng: &mut Random<R>,
) -> Self
where
A: From<f64>,
R: Rng;
fn sparse<R, Dist>(shape: D, density: f64, distribution: Dist, rng: &mut Random<R>) -> Self
where
A: Clone + Default,
R: Rng,
Dist: Distribution<A>;
}
impl<A, S, D> ScientificRandomExt<A, D> for ArrayBase<S, D>
where
S: DataOwned<Elem = A>,
D: Dimension,
A: Clone,
{
fn dirichlet<R>(shape: D, alpha: &[f64], rng: &mut Random<R>) -> Self
where
A: From<f64>,
R: Rng,
{
let dirichlet = Dirichlet::new(alpha.to_vec()).expect("Operation failed");
let size = shape.size();
let mut values = Vec::with_capacity(size);
for _ in 0..size {
let sample_vec = dirichlet.sample(rng);
let sample_val = sample_vec.get(0).copied().unwrap_or(0.0);
values.push(A::from(sample_val));
}
Self::from_shape_vec(shape, values).expect("Operation failed")
}
fn von_mises<R>(shape: D, mu: f64, kappa: f64, rng: &mut Random<R>) -> Self
where
A: From<f64>,
R: Rng,
{
let von_mises = VonMises::mu(mu, kappa).expect("Operation failed");
let size = shape.size();
let mut values = Vec::with_capacity(size);
for _ in 0..size {
let sample_val = von_mises.sample(rng);
values.push(A::from(sample_val));
}
Self::from_shape_vec(shape, values).expect("Operation failed")
}
fn multivariate_normal<R>(
mean: Vec<f64>,
covariance: Vec<Vec<f64>>,
n_samples: usize,
rng: &mut Random<R>,
) -> Array<A, crate::ndarray::Ix2>
where
A: From<f64>,
R: Rng,
{
let mvn = MultivariateNormal::new(mean.clone(), covariance).expect("Operation failed");
let dim = mean.len();
Array::from_shape_fn((n_samples, dim), |_| {
let sample = mvn.sample(rng);
A::from(sample[0]) })
}
fn categorical<R, T>(
shape: D,
choices: &[T],
probabilities: &[f64],
rng: &mut Random<R>,
) -> Array<T, D>
where
T: Clone,
R: Rng,
{
let weighted = WeightedChoice::new(choices.to_vec(), probabilities.to_vec())
.expect("Operation failed");
Array::from_shape_fn(shape, |_| weighted.sample(rng).clone())
}
fn correlated_normal<R>(
shape: D,
correlation_matrix: &Array<f64, crate::ndarray::Ix2>,
rng: &mut Random<R>,
) -> Self
where
A: From<f64>,
R: Rng,
{
Self::standard_normal(shape, rng)
}
fn sparse<R, Dist>(shape: D, density: f64, distribution: Dist, rng: &mut Random<R>) -> Self
where
A: Clone + Default,
R: Rng,
Dist: Distribution<A>,
{
let size = shape.size();
let values: Vec<A> = (0..size)
.map(|_| {
if rand::RngExt::random::<f64>(&mut rng.rng) < density {
distribution.sample(&mut rng.rng)
} else {
A::default()
}
})
.collect();
Self::from_shape_vec(shape, values).expect("Operation failed")
}
}
pub mod convenience {
use super::*;
use crate::random::thread_rng;
use ::ndarray::{Array1, Array2, Array3, Ix1, Ix2, Ix3};
pub fn randn(size: usize) -> Array1<f64> {
let mut rng = thread_rng();
Array1::standard_normal(Ix1(size), &mut rng)
}
pub fn rand(size: usize) -> Array1<f64> {
let mut rng = thread_rng();
Array1::standard_uniform(Ix1(size), &mut rng)
}
pub fn randn2(rows: usize, cols: usize) -> Array2<f64> {
let mut rng = thread_rng();
Array2::standard_normal(Ix2(rows, cols), &mut rng)
}
pub fn rand2(rows: usize, cols: usize) -> Array2<f64> {
let mut rng = thread_rng();
Array2::standard_uniform(Ix2(rows, cols), &mut rng)
}
pub fn randn3(dim1: usize, dim2: usize, dim3: usize) -> Array3<f64> {
let mut rng = thread_rng();
Array3::standard_normal(Ix3(dim1, dim2, dim3), &mut rng)
}
pub fn randint(size: usize, low: i64, high: i64) -> Array1<i64> {
let mut rng = thread_rng();
Array1::randint(Ix1(size), low, high, &mut rng)
}
pub fn choice<T: Clone>(choices: &[T], size: usize) -> Array1<T> {
let mut rng = thread_rng();
let uniform_dist = Uniform::new(0, choices.len()).expect("Operation failed");
Array1::from_shape_fn(Ix1(size), |_| {
let idx = uniform_dist.sample(&mut rng.rng);
choices[idx].clone()
})
}
}
pub mod optimized {
use super::*;
use crate::random::parallel::ParallelRng;
pub fn parallel_randn<R: Rng + Send + Sync + Clone>(
shape: (usize, usize),
rng: &mut Random<R>,
) -> Array<f64, crate::ndarray::Ix2> {
Array::standard_normal(Ix2(shape.0, shape.1), rng)
}
pub fn simd_rand<R: Rng>(size: usize, rng: &mut Random<R>) -> Array1<f64> {
Array1::standard_uniform(Ix1(size), rng)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::random::seeded_rng;
use approx::assert_abs_diff_eq;
use ndarray::{Array1, Array2, Ix1, Ix2};
#[test]
fn test_random_ext_basic() {
let mut rng = seeded_rng(42);
let arr: Array1<f64> = Array1::standard_normal(Ix1(10), &mut rng);
assert_eq!(arr.len(), 10);
}
#[test]
fn test_random_ext_uniform() {
let mut rng = seeded_rng(123);
let arr: Array2<f64> = Array2::uniform(Ix2(5, 5), 0.0, 1.0, &mut rng);
assert_eq!(arr.shape(), &[5, 5]);
assert!(arr.iter().all(|&x| x >= 0.0 && x < 1.0));
}
#[test]
fn test_reproducibility() {
let mut rng1 = seeded_rng(999);
let mut rng2 = seeded_rng(999);
let arr1: Array1<f64> = Array1::standard_normal(Ix1(100), &mut rng1);
let arr2: Array1<f64> = Array1::standard_normal(Ix1(100), &mut rng2);
for (a, b) in arr1.iter().zip(arr2.iter()) {
assert_abs_diff_eq!(a, b, epsilon = 1e-10);
}
}
#[test]
fn test_convenience_functions() {
let arr = convenience::randn(50);
assert_eq!(arr.len(), 50);
let matrix = convenience::rand2(3, 4);
assert_eq!(matrix.shape(), &[3, 4]);
}
#[test]
fn test_scientific_extensions() {
let mut rng = seeded_rng(456);
let beta_arr: Array1<f64> = Array1::beta(Ix1(20), 2.0, 5.0, &mut rng);
assert_eq!(beta_arr.len(), 20);
assert!(beta_arr.iter().all(|&x| x >= 0.0 && x <= 1.0));
let vm_arr: Array1<f64> = Array1::von_mises(Ix1(15), 0.0, 1.0, &mut rng);
assert_eq!(vm_arr.len(), 15);
}
}