use numrs2::array::Array;
use numrs2::random::{self, set_seed};
const SAMPLE_SIZE: usize = 10000;
fn calculate_mean(arr: &Array<f64>) -> f64 {
let data = arr.to_vec();
let sum: f64 = data.iter().sum();
sum / data.len() as f64
}
fn calculate_variance(arr: &Array<f64>, mean: f64) -> f64 {
let data = arr.to_vec();
let sum_sq_diff: f64 = data.iter().map(|x| (x - mean).powi(2)).sum();
sum_sq_diff / data.len() as f64
}
#[test]
fn test_normal_distribution_statistics() {
let mean = 3.0;
let std_dev = 2.0;
set_seed(42);
let samples = random::normal(mean, std_dev, &[SAMPLE_SIZE]).unwrap();
let sample_mean = calculate_mean(&samples);
let sample_variance = calculate_variance(&samples, sample_mean);
let _sample_std_dev = sample_variance.sqrt();
assert!(
(sample_mean - mean).abs() < 0.1 * std_dev,
"Normal distribution: Expected mean close to {}, got {}",
mean,
sample_mean
);
assert!(
(sample_variance - std_dev * std_dev).abs() < 0.15 * std_dev * std_dev,
"Normal distribution: Expected variance close to {}, got {}",
std_dev * std_dev,
sample_variance
);
}
#[test]
fn test_uniform_distribution_statistics() {
let low = 2.0;
let high = 7.0;
let range = high - low;
set_seed(42);
let samples = random::uniform(low, high, &[SAMPLE_SIZE]).unwrap();
let sample_mean = calculate_mean(&samples);
let sample_variance = calculate_variance(&samples, sample_mean);
let expected_mean = (low + high) / 2.0;
let expected_variance = range * range / 12.0;
assert!(
(sample_mean - expected_mean).abs() < 0.1 * range,
"Uniform distribution: Expected mean close to {}, got {}",
expected_mean,
sample_mean
);
assert!(
(sample_variance - expected_variance).abs() < 0.15 * expected_variance,
"Uniform distribution: Expected variance close to {}, got {}",
expected_variance,
sample_variance
);
let all_in_range = samples.to_vec().iter().all(|&x| x >= low && x <= high);
assert!(
all_in_range,
"Uniform distribution: Some values are outside [{}, {}]",
low, high
);
}
#[test]
fn test_beta_distribution_statistics() {
let alpha = 2.0;
let beta = 5.0;
set_seed(42);
let samples = random::beta(alpha, beta, &[SAMPLE_SIZE]).unwrap();
let sample_mean = calculate_mean(&samples);
let sample_variance = calculate_variance(&samples, sample_mean);
let expected_mean = alpha / (alpha + beta);
let expected_variance = (alpha * beta) / ((alpha + beta).powi(2) * (alpha + beta + 1.0));
assert!(
(sample_mean - expected_mean).abs() < 0.1 * expected_mean,
"Beta distribution: Expected mean close to {}, got {}",
expected_mean,
sample_mean
);
assert!(
(sample_variance - expected_variance).abs() < 0.2 * expected_variance,
"Beta distribution: Expected variance close to {}, got {}",
expected_variance,
sample_variance
);
let all_in_range = samples.to_vec().iter().all(|&x| (0.0..=1.0).contains(&x));
assert!(
all_in_range,
"Beta distribution: Some values are outside [0, 1]"
);
}
#[test]
fn test_exponential_distribution_statistics() {
let scale = 3.0;
set_seed(42);
let samples = random::exponential(scale, &[SAMPLE_SIZE]).unwrap();
let sample_mean = calculate_mean(&samples);
let sample_variance = calculate_variance(&samples, sample_mean);
let expected_mean = scale;
let expected_variance = scale * scale;
assert!(
(sample_mean - expected_mean).abs() < 0.15 * expected_mean,
"Exponential distribution: Expected mean close to {}, got {}",
expected_mean,
sample_mean
);
assert!(
(sample_variance - expected_variance).abs() < 0.2 * expected_variance,
"Exponential distribution: Expected variance close to {}, got {}",
expected_variance,
sample_variance
);
let all_positive = samples.to_vec().iter().all(|&x| x > 0.0);
assert!(
all_positive,
"Exponential distribution: Some values are not positive"
);
}
#[test]
fn test_gamma_distribution_statistics() {
let shape = 3.0;
let scale = 2.0;
set_seed(42);
let samples = random::gamma(shape, scale, &[SAMPLE_SIZE]).unwrap();
let sample_mean = calculate_mean(&samples);
let sample_variance = calculate_variance(&samples, sample_mean);
let expected_mean = shape * scale;
let expected_variance = shape * scale * scale;
assert!(
(sample_mean - expected_mean).abs() < 0.15 * expected_mean,
"Gamma distribution: Expected mean close to {}, got {}",
expected_mean,
sample_mean
);
assert!(
(sample_variance - expected_variance).abs() < 0.2 * expected_variance,
"Gamma distribution: Expected variance close to {}, got {}",
expected_variance,
sample_variance
);
let all_positive = samples.to_vec().iter().all(|&x| x > 0.0);
assert!(
all_positive,
"Gamma distribution: Some values are not positive"
);
}
#[test]
fn test_lognormal_distribution_statistics() {
let mu = 0.0;
let sigma = 1.0;
set_seed(42);
let samples = random::lognormal(mu, sigma, &[SAMPLE_SIZE]).unwrap();
let sample_mean = calculate_mean(&samples);
let sample_variance = calculate_variance(&samples, sample_mean);
let expected_mean = (mu + sigma * sigma / 2.0).exp();
let expected_variance = ((sigma * sigma).exp() - 1.0) * (2.0 * mu + sigma * sigma).exp();
assert!(
(sample_mean - expected_mean).abs() < 0.2 * expected_mean,
"Lognormal distribution: Expected mean close to {}, got {}",
expected_mean,
sample_mean
);
assert!(
(sample_variance - expected_variance).abs() < 0.3 * expected_variance,
"Lognormal distribution: Expected variance close to {}, got {}",
expected_variance,
sample_variance
);
let all_positive = samples.to_vec().iter().all(|&x| x > 0.0);
assert!(
all_positive,
"Lognormal distribution: Some values are not positive"
);
}
#[test]
fn test_weibull_distribution_statistics() {
let shape = 2.0;
let scale = 3.0;
set_seed(42);
let samples = random::weibull(shape, scale, &[SAMPLE_SIZE]).unwrap();
let sample_mean = calculate_mean(&samples);
let expected_mean = 2.66;
assert!(
(sample_mean - expected_mean).abs() < 0.15 * expected_mean,
"Weibull distribution: Expected mean close to {}, got {}",
expected_mean,
sample_mean
);
let all_positive = samples.to_vec().iter().all(|&x| x > 0.0);
assert!(
all_positive,
"Weibull distribution: Some values are not positive"
);
}
#[test]
fn test_binomial_distribution_statistics() {
let n = 20u64;
let p = 0.3;
set_seed(42);
let samples = random::binomial::<u64>(n, p, &[SAMPLE_SIZE]).unwrap();
let samples_f64 = Array::from_vec(samples.to_vec().iter().map(|&x| x as f64).collect());
let sample_mean = calculate_mean(&samples_f64);
let sample_variance = calculate_variance(&samples_f64, sample_mean);
let expected_mean = n as f64 * p;
let expected_variance = n as f64 * p * (1.0 - p);
assert!(
(sample_mean - expected_mean).abs() < 0.1 * expected_mean,
"Binomial distribution: Expected mean close to {}, got {}",
expected_mean,
sample_mean
);
assert!(
(sample_variance - expected_variance).abs() < 0.15 * expected_variance,
"Binomial distribution: Expected variance close to {}, got {}",
expected_variance,
sample_variance
);
let all_in_range = samples.to_vec().iter().all(|&x| x <= n);
assert!(
all_in_range,
"Binomial distribution: Some values are outside [0, {}]",
n
);
}
#[test]
fn test_poisson_distribution_statistics() {
let lambda = 5.0;
set_seed(42);
let samples = random::poisson::<u64>(lambda, &[SAMPLE_SIZE]).unwrap();
let samples_f64 = Array::from_vec(samples.to_vec().iter().map(|&x| x as f64).collect());
let sample_mean = calculate_mean(&samples_f64);
let sample_variance = calculate_variance(&samples_f64, sample_mean);
let expected_mean = lambda;
let expected_variance = lambda;
assert!(
(sample_mean - expected_mean).abs() < 0.1 * expected_mean,
"Poisson distribution: Expected mean close to {}, got {}",
expected_mean,
sample_mean
);
assert!(
(sample_variance - expected_variance).abs() < 0.15 * expected_variance,
"Poisson distribution: Expected variance close to {}, got {}",
expected_variance,
sample_variance
);
let all_non_negative = samples.to_vec().iter().all(|_x| true);
assert!(
all_non_negative,
"Poisson distribution: Some values are negative"
);
}
#[test]
#[ignore] fn test_seed_reproducibility() {
set_seed(42);
let samples1 = random::normal(0.0, 1.0, &[100]).unwrap();
set_seed(42);
let samples2 = random::normal(0.0, 1.0, &[100]).unwrap();
set_seed(43);
let samples3 = random::normal(0.0, 1.0, &[100]).unwrap();
let samples1_vec = samples1.to_vec();
let samples2_vec = samples2.to_vec();
assert_eq!(
samples1_vec, samples2_vec,
"Same seed should produce identical results"
);
let samples3_vec = samples3.to_vec();
assert_ne!(
samples1_vec, samples3_vec,
"Different seeds should produce different results"
);
}