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
}
fn calculate_skewness(arr: &Array<f64>, mean: f64, std_dev: f64) -> f64 {
let data = arr.to_vec();
let n = data.len() as f64;
let sum_cubed_diff: f64 = data.iter().map(|x| ((x - mean) / std_dev).powi(3)).sum();
sum_cubed_diff * n / ((n - 1.0) * (n - 2.0))
}
fn calculate_kurtosis(arr: &Array<f64>, mean: f64, std_dev: f64) -> f64 {
let data = arr.to_vec();
let n = data.len() as f64;
let sum_fourth_power: f64 = data.iter().map(|x| ((x - mean) / std_dev).powi(4)).sum();
sum_fourth_power * n * (n + 1.0) / ((n - 1.0) * (n - 2.0) * (n - 3.0))
- 3.0 * (n - 1.0).powi(2) / ((n - 2.0) * (n - 3.0))
}
fn is_within_bounds(value: f64, expected: f64, tolerance: f64) -> bool {
(value - expected).abs() <= tolerance
}
#[test]
fn test_normal_distribution_properties() {
let mean = 5.0;
let std_dev = 2.0;
set_seed(12345);
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();
let sample_skewness = calculate_skewness(&samples, sample_mean, sample_std_dev);
let sample_kurtosis = calculate_kurtosis(&samples, sample_mean, sample_std_dev);
assert!(
is_within_bounds(sample_mean, mean, 0.1 * std_dev),
"Expected mean close to {}, got {}",
mean,
sample_mean
);
assert!(
is_within_bounds(sample_variance, std_dev * std_dev, 0.2 * std_dev * std_dev),
"Expected variance close to {}, got {}",
std_dev * std_dev,
sample_variance
);
assert!(
is_within_bounds(sample_skewness, 0.0, 0.2),
"Expected skewness close to 0, got {}",
sample_skewness
);
assert!(
is_within_bounds(sample_kurtosis, 0.0, 0.4),
"Expected kurtosis close to 0, got {}",
sample_kurtosis
);
}
#[test]
fn test_uniform_distribution_properties() {
let low = 2.0;
let high = 7.0;
let range = high - low;
set_seed(12345);
let samples = random::uniform(low, high, &[SAMPLE_SIZE]).unwrap();
let sample_mean = calculate_mean(&samples);
let sample_variance = calculate_variance(&samples, sample_mean);
let sample_std_dev = sample_variance.sqrt();
let sample_skewness = calculate_skewness(&samples, sample_mean, sample_std_dev);
let sample_kurtosis = calculate_kurtosis(&samples, sample_mean, sample_std_dev);
let expected_mean = (low + high) / 2.0;
assert!(
is_within_bounds(sample_mean, expected_mean, 0.1 * range),
"Expected mean close to {}, got {}",
expected_mean,
sample_mean
);
let expected_variance = range * range / 12.0;
assert!(
is_within_bounds(sample_variance, expected_variance, 0.2 * expected_variance),
"Expected variance close to {}, got {}",
expected_variance,
sample_variance
);
assert!(
is_within_bounds(sample_skewness, 0.0, 0.2),
"Expected skewness close to 0, got {}",
sample_skewness
);
assert!(
is_within_bounds(sample_kurtosis, -1.2, 0.3),
"Expected kurtosis close to -1.2, got {}",
sample_kurtosis
);
let all_in_range = samples.to_vec().iter().all(|&x| x >= low && x <= high);
assert!(
all_in_range,
"Some values are outside the specified range [{}, {}]",
low, high
);
}
#[test]
fn test_beta_distribution_properties() {
let alpha = 2.0;
let beta = 5.0;
set_seed(12345);
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);
assert!(
is_within_bounds(sample_mean, expected_mean, 0.1),
"Expected mean close to {}, got {}",
expected_mean,
sample_mean
);
let expected_variance = (alpha * beta) / ((alpha + beta).powi(2) * (alpha + beta + 1.0));
assert!(
is_within_bounds(sample_variance, expected_variance, 0.1),
"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, "Some values are outside [0, 1]");
}
#[test]
fn test_gamma_distribution_properties() {
let shape = 3.0;
let scale = 2.0;
set_seed(12345);
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;
assert!(
is_within_bounds(sample_mean, expected_mean, 0.2 * expected_mean),
"Expected mean close to {}, got {}",
expected_mean,
sample_mean
);
let expected_variance = shape * scale * scale;
assert!(
is_within_bounds(sample_variance, expected_variance, 0.3 * expected_variance),
"Expected variance close to {}, got {}",
expected_variance,
sample_variance
);
let all_positive = samples.to_vec().iter().all(|&x| x > 0.0);
assert!(all_positive, "Some values are not positive");
}
#[test]
fn test_exponential_distribution_properties() {
let scale = 2.0;
set_seed(12345);
let samples = random::exponential(scale, &[SAMPLE_SIZE]).unwrap();
let sample_mean = calculate_mean(&samples);
let sample_variance = calculate_variance(&samples, sample_mean);
assert!(
is_within_bounds(sample_mean, scale, 0.2 * scale),
"Expected mean close to {}, got {}",
scale,
sample_mean
);
let expected_variance = scale * scale;
assert!(
is_within_bounds(sample_variance, expected_variance, 0.3 * expected_variance),
"Expected variance close to {}, got {}",
expected_variance,
sample_variance
);
let all_positive = samples.to_vec().iter().all(|&x| x > 0.0);
assert!(all_positive, "Some values are not positive");
}
#[test]
fn test_binomial_distribution_properties() {
let n = 20u64;
let p = 0.3;
set_seed(12345);
let samples = random::binomial::<u64>(n, p, &[SAMPLE_SIZE]).unwrap();
let sample_mean = calculate_mean(&Array::from_vec(
samples.to_vec().iter().map(|&x| x as f64).collect(),
));
let sample_variance = calculate_variance(
&Array::from_vec(samples.to_vec().iter().map(|&x| x as f64).collect()),
sample_mean,
);
let expected_mean = n as f64 * p;
assert!(
is_within_bounds(sample_mean, expected_mean, 0.2 * expected_mean),
"Expected mean close to {}, got {}",
expected_mean,
sample_mean
);
let expected_variance = n as f64 * p * (1.0 - p);
assert!(
is_within_bounds(sample_variance, expected_variance, 0.3 * expected_variance),
"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, "Some values are outside the range [0, {}]", n);
}
#[test]
fn test_poisson_distribution_properties() {
let lambda = 5.0;
set_seed(12345);
let samples = random::poisson::<u64>(lambda, &[SAMPLE_SIZE]).unwrap();
let sample_mean = calculate_mean(&Array::from_vec(
samples.to_vec().iter().map(|&x| x as f64).collect(),
));
let sample_variance = calculate_variance(
&Array::from_vec(samples.to_vec().iter().map(|&x| x as f64).collect()),
sample_mean,
);
assert!(
is_within_bounds(sample_mean, lambda, 0.2 * lambda),
"Expected mean close to {}, got {}",
lambda,
sample_mean
);
assert!(
is_within_bounds(sample_variance, lambda, 0.2 * lambda),
"Expected variance close to {}, got {}",
lambda,
sample_variance
);
let all_non_negative = samples.to_vec().iter().all(|&_x| true);
assert!(all_non_negative, "Some values are negative");
}
#[test]
#[ignore = "Seeding behavior changed during SciRS2 migration - requires seeding implementation fix"]
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();
assert_eq!(
samples1.to_vec(),
samples2.to_vec(),
"Same seed should produce identical sequences"
);
assert_ne!(
samples1.to_vec(),
samples3.to_vec(),
"Different seeds should produce different sequences"
);
}