use crate::{
corrcoef,
correlation_parallel_enhanced::{corrcoef_parallel_enhanced, ParallelCorrelationConfig},
descriptive::{kurtosis, mean, moment, skew, var},
descriptive_simd::{mean_simd, variance_simd},
memory_optimized_advanced::{
corrcoef_memory_aware, AdaptiveMemoryManager as AdvancedMemoryManager, MemoryConstraints,
},
moments_simd::{kurtosis_simd, skewness_simd},
pearson_r,
};
use scirs2_core::ndarray::{Array1, Array2};
use scirs2_core::ndarray::ArrayStatCompat;
#[derive(Clone, Debug)]
pub struct StatisticalTestData {
pub data: Vec<f64>,
}
impl StatisticalTestData {
pub fn new(data: Vec<f64>) -> Self {
Self { data }
}
pub fn generate_sample() -> Self {
let data = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
Self { data }
}
pub fn generate_large_sample() -> Self {
let data: Vec<f64> = (1..=100).map(|i| i as f64).collect();
Self { data }
}
}
#[derive(Clone, Debug)]
pub struct MatrixTestData {
pub data: Vec<Vec<f64>>,
pub rows: usize,
pub cols: usize,
}
impl MatrixTestData {
pub fn new(data: Vec<Vec<f64>>) -> Self {
let rows = data.len();
let cols = if rows > 0 { data[0].len() } else { 0 };
Self {
data: data,
rows,
cols,
}
}
pub fn generate_sample() -> Self {
let data = vec![
vec![1.0, 5.0, 10.0],
vec![2.0, 4.0, 9.0],
vec![3.0, 3.0, 8.0],
vec![4.0, 2.0, 7.0],
vec![5.0, 1.0, 6.0],
];
Self::new(data)
}
}
pub struct SimdConsistencyTester;
impl SimdConsistencyTester {
pub fn test_mean_consistency(testdata: &StatisticalTestData) -> bool {
if testdata.data.len() < 1 {
return false;
}
let arr = Array1::from_vec(testdata.data.clone());
match (mean(&arr.view()), mean_simd(&arr.view())) {
(Ok(scalar_result), Ok(simd_result)) => {
let relative_error =
((scalar_result - simd_result) / scalar_result.max(1e-10)).abs();
relative_error < 1e-12
}
_ => false,
}
}
pub fn test_variance_consistency(testdata: &StatisticalTestData) -> bool {
if testdata.data.len() < 2 {
return false;
}
let arr = Array1::from_vec(testdata.data.clone());
match (var(&arr.view(), 1, None), variance_simd(&arr.view(), 1)) {
(Ok(scalar_result), Ok(simd_result)) => {
let relative_error =
((scalar_result - simd_result) / scalar_result.max(1e-10)).abs();
relative_error < 1e-12
}
_ => false,
}
}
pub fn test_skewness_consistency(testdata: &StatisticalTestData) -> bool {
if testdata.data.len() < 3 {
return false;
}
let arr = Array1::from_vec(testdata.data.clone());
match (
skew(&arr.view(), false, None),
skewness_simd(&arr.view(), false),
) {
(Ok(scalar_result), Ok(simd_result)) => {
let relative_error =
((scalar_result - simd_result) / scalar_result.abs().max(1e-10)).abs();
relative_error < 1e-12
}
_ => false,
}
}
pub fn test_kurtosis_consistency(testdata: &StatisticalTestData) -> bool {
if testdata.data.len() < 4 {
return false;
}
let arr = Array1::from_vec(testdata.data.clone());
match (
kurtosis(&arr.view(), true, false, None),
kurtosis_simd(&arr.view(), true, false),
) {
(Ok(scalar_result), Ok(simd_result)) => {
let relative_error =
((scalar_result - simd_result) / scalar_result.abs().max(1e-10)).abs();
relative_error < 1e-12
}
_ => false,
}
}
}
pub struct ParallelConsistencyTester;
impl ParallelConsistencyTester {
pub fn test_correlation_matrix_consistency(matrixdata: &MatrixTestData) -> bool {
if matrixdata.rows < 3 || matrixdata.cols < 2 {
return false;
}
let mut data = Array2::zeros((matrixdata.rows, matrixdata.cols));
for (i, row) in matrixdata.data.iter().enumerate() {
for (j, &val) in row.iter().enumerate() {
data[[i, j]] = val;
}
}
let config = ParallelCorrelationConfig::default();
match (
corrcoef(&data.view(), "pearson"),
corrcoef_parallel_enhanced(&data.view(), "pearson", &config),
) {
(Ok(sequential_result), Ok(parallel_result)) => {
let mut max_error = 0.0;
for i in 0..matrixdata.cols {
for j in 0..matrixdata.cols {
let error = (sequential_result[[i, j]] - parallel_result[[i, j]]).abs();
max_error = (max_error as f64).max(error as f64);
}
}
max_error < 1e-12
}
_ => false,
}
}
}
pub struct MathematicalInvariantTester;
impl MathematicalInvariantTester {
pub fn test_correlation_bounds(
testdata1: &StatisticalTestData,
testdata2: &StatisticalTestData,
) -> bool {
if testdata1.data.len() != testdata2.data.len() || testdata1.data.len() < 2 {
return false;
}
let arr1 = Array1::from_vec(testdata1.data.clone());
let arr2 = Array1::from_vec(testdata2.data.clone());
match pearson_r(&arr1.view(), &arr2.view()) {
Ok(corr) => corr >= -1.0 && corr <= 1.0,
_ => false,
}
}
pub fn test_variance_properties(testdata: &StatisticalTestData) -> bool {
if testdata.data.len() < 2 {
return true; }
let arr = Array1::from_vec(testdata.data.clone());
let variance_result = var(&arr.view(), 1, None);
if let Ok(variance) = variance_result {
if variance < 0.0 {
return false;
}
} else {
return false;
}
let shifteddata: Vec<f64> = testdata.data.iter().map(|&x| x + 100.0).collect();
let shifted_arr = Array1::from_vec(shifteddata);
match (var(&arr.view(), 1, None), var(&shifted_arr.view(), 1, None)) {
(Ok(var1), Ok(var2)) => {
let relative_error = ((var1 - var2) / var1.max(1e-10)).abs();
relative_error < 1e-12
}
_ => false,
}
}
pub fn test_moment_properties(testdata: &StatisticalTestData) -> bool {
if testdata.data.len() < 2 {
return true;
}
let arr = Array1::from_vec(testdata.data.clone());
match (mean(&arr.view()), moment(&arr.view(), 1, false, None)) {
(Ok(mean_val), Ok(moment1)) => {
let relative_error = ((mean_val - moment1) / mean_val.max(1e-10)).abs();
relative_error < 1e-12
}
_ => false,
}
}
pub fn test_correlation_matrix_symmetry(matrixdata: &MatrixTestData) -> bool {
if matrixdata.rows < 2 || matrixdata.cols < 2 {
return true;
}
let mut data = Array2::zeros((matrixdata.rows, matrixdata.cols));
for (i, row) in matrixdata.data.iter().enumerate() {
for (j, &val) in row.iter().enumerate() {
data[[i, j]] = val;
}
}
match corrcoef(&data.view(), "pearson") {
Ok(corr_matrix) => {
let (nrows, ncols) = corr_matrix.dim();
if nrows != ncols {
return false;
}
for i in 0..nrows {
for j in 0..ncols {
let error = (corr_matrix[[i, j]] - corr_matrix[[j, i]]).abs();
if error > 1e-12 {
return false;
}
}
}
for i in 0..nrows {
let error = (corr_matrix[[i, i]] - 1.0).abs();
if error > 1e-12 {
return false;
}
}
true
}
_ => false,
}
}
pub fn test_mean_linearity(testdata: &StatisticalTestData) -> bool {
if testdata.data.len() < 1 {
return true;
}
let arr = Array1::from_vec(testdata.data.clone());
let a = 2.5;
let b = 10.0;
let transformeddata: Vec<f64> = testdata.data.iter().map(|&x| a * x + b).collect();
let transformed_arr = Array1::from_vec(transformeddata);
match (mean(&arr.view()), mean(&transformed_arr.view())) {
(Ok(mean_x), Ok(mean_ax_b)) => {
let expected = a * mean_x + b;
let relative_error = ((expected - mean_ax_b) / expected.max(1e-10)).abs();
relative_error < 1e-12
}
_ => false,
}
}
pub fn test_variance_scaling(testdata: &StatisticalTestData) -> bool {
if testdata.data.len() < 2 {
return true;
}
let arr = Array1::from_vec(testdata.data.clone());
let a = 3.0;
let scaleddata: Vec<f64> = testdata.data.iter().map(|&x| a * x).collect();
let scaled_arr = Array1::from_vec(scaleddata);
match (var(&arr.view(), 1, None), var(&scaled_arr.view(), 1, None)) {
(Ok(var_x), Ok(var_ax)) => {
let expected = a * a * var_x;
let relative_error = ((expected - var_ax) / expected.max(1e-10)).abs();
relative_error < 1e-12
}
_ => false,
}
}
pub fn test_correlation_translation_invariance(
testdata1: &StatisticalTestData,
testdata2: &StatisticalTestData,
) -> bool {
if testdata1.data.len() != testdata2.data.len() || testdata1.data.len() < 2 {
return false;
}
let arr1 = Array1::from_vec(testdata1.data.clone());
let arr2 = Array1::from_vec(testdata2.data.clone());
let c1 = 50.0;
let c2 = -30.0;
let shifteddata1: Vec<f64> = testdata1.data.iter().map(|&x| x + c1).collect();
let shifteddata2: Vec<f64> = testdata2.data.iter().map(|&x| x + c2).collect();
let shifted_arr1 = Array1::from_vec(shifteddata1);
let shifted_arr2 = Array1::from_vec(shifteddata2);
match (
pearson_r(&arr1.view(), &arr2.view()),
pearson_r(&shifted_arr1.view(), &shifted_arr2.view()),
) {
(Ok(corr1), Ok(corr2)) => {
let relative_error = ((corr1 - corr2) / corr1.max(1e-10)).abs();
relative_error < 1e-12
}
_ => false,
}
}
pub fn test_skewness_properties(testdata: &StatisticalTestData) -> bool {
if testdata.data.len() < 3 {
return true;
}
let _arr = Array1::from_vec(testdata.data.clone());
let mut right_skewed = testdata.data.clone();
right_skewed.extend(vec![100.0, 200.0, 300.0]);
let right_skewed_arr = Array1::from_vec(right_skewed);
let mut left_skewed = testdata.data.clone();
left_skewed.extend(vec![-100.0, -200.0, -300.0]);
let left_skewed_arr = Array1::from_vec(left_skewed);
match (
skew(&right_skewed_arr.view(), false, None),
skew(&left_skewed_arr.view(), false, None),
) {
(Ok(right_skew), Ok(left_skew)) => {
right_skew > 0.0 && left_skew < 0.0
}
_ => false,
}
}
pub fn test_kurtosis_properties(testdata: &StatisticalTestData) -> bool {
if testdata.data.len() < 4 {
return true;
}
let uniformdata: Vec<f64> = (0..100).map(|i| i as f64 / 100.0).collect();
let uniform_arr = Array1::from_vec(uniformdata);
match kurtosis(&uniform_arr.view(), false, false, None) {
Ok(kurt) => {
kurt < 3.0
}
_ => false,
}
}
}
pub struct BatchProcessingTester;
impl BatchProcessingTester {
pub fn test_batch_mean_consistency(matrixdata: &MatrixTestData) -> bool {
if matrixdata.rows < 1 || matrixdata.cols < 1 {
return false;
}
let mut data = Array2::zeros((matrixdata.rows, matrixdata.cols));
for (i, row) in matrixdata.data.iter().enumerate() {
for (j, &val) in row.iter().enumerate() {
data[[i, j]] = val;
}
}
let mut individual_means = Vec::new();
for col_idx in 0..matrixdata.cols {
let column = data.column(col_idx);
match mean(&column) {
Ok(col_mean) => individual_means.push(col_mean),
_ => return false,
}
}
let batch_means: Vec<f64> = (0..matrixdata.cols)
.map(|col_idx| {
let column = data.column(col_idx);
column.mean_or(0.0)
})
.collect();
match Ok::<Vec<f64>, crate::error::StatsError>(batch_means) {
Ok(batch_moments) => {
for (i, &individual_mean) in individual_means.iter().enumerate() {
if i >= batch_moments.len() {
return false;
}
let relative_error =
((individual_mean - batch_moments[i]) / individual_mean.max(1e-10)).abs();
if relative_error > 1e-12 {
return false;
}
}
true
}
_ => false,
}
}
pub fn test_batch_correlation_consistency(matrixdata: &MatrixTestData) -> bool {
if matrixdata.rows < 3 || matrixdata.cols < 3 {
return false;
}
let mut data = Array2::zeros((matrixdata.rows, matrixdata.cols));
for (i, row) in matrixdata.data.iter().enumerate() {
for (j, &val) in row.iter().enumerate() {
data[[i, j]] = val;
}
}
let _config = ParallelCorrelationConfig::default();
let correlation_pairs = vec![(0, 1), (0, 2), (1, 2)];
let batch_results: Result<Vec<f64>, crate::error::StatsError> = correlation_pairs
.iter()
.map(|&(i, j)| {
let col_i = data.column(i);
let col_j = data.column(j);
pearson_r(&col_i, &col_j)
})
.collect();
match batch_results {
Ok(batch_results) => {
for (idx, &(i, j)) in correlation_pairs.iter().enumerate() {
let col_i = data.column(i);
let col_j = data.column(j);
match pearson_r(&col_i, &col_j) {
Ok(individual_corr) => {
if idx >= batch_results.len() {
return false;
}
let relative_error = ((individual_corr - batch_results[idx])
/ individual_corr.max(1e-10))
.abs();
if relative_error > 1e-12 {
return false;
}
}
_ => return false,
}
}
true
}
_ => false,
}
}
}
pub struct MemoryOptimizationTester;
impl MemoryOptimizationTester {
pub fn test_memory_optimized_correlation(matrixdata: &MatrixTestData) -> bool {
if matrixdata.rows < 2 || matrixdata.cols < 2 {
return false;
}
let mut data = Array2::zeros((matrixdata.rows, matrixdata.cols));
for (i, row) in matrixdata.data.iter().enumerate() {
for (j, &val) in row.iter().enumerate() {
data[[i, j]] = val;
}
}
let constraints = MemoryConstraints::default();
let mut memory_manager = AdvancedMemoryManager::new(constraints);
match (
corrcoef(&data.view(), "pearson"),
corrcoef_memory_aware(&data.view(), "pearson", &mut memory_manager),
) {
(Ok(standard_result), Ok(memory_optimized_result)) => {
let (nrows, ncols) = standard_result.dim();
if nrows != memory_optimized_result.nrows()
|| ncols != memory_optimized_result.ncols()
{
return false;
}
let mut max_error = 0.0;
for i in 0..nrows {
for j in 0..ncols {
let error =
(standard_result[[i, j]] - memory_optimized_result[[i, j]]).abs();
max_error = (max_error as f64).max(error as f64);
}
}
max_error < 1e-12
}
_ => false,
}
}
}
pub struct NumericalStabilityTester;
impl NumericalStabilityTester {
pub fn test_extreme_values() -> bool {
let largedata = vec![1e15, 1e15 + 1.0, 1e15 + 2.0, 1e15 + 3.0];
let large_arr = Array1::from_vec(largedata);
let smalldata = vec![1e-15, 2e-15, 3e-15, 4e-15];
let small_arr = Array1::from_vec(smalldata);
match (mean(&large_arr.view()), mean(&small_arr.view())) {
(Ok(large_mean), Ok(small_mean)) => {
(large_mean as f64).is_finite() && (small_mean as f64).is_finite()
}
_ => false,
}
}
pub fn test_nearly_identical_values() -> bool {
let base_value = 1000000.0;
let epsilon = 1e-10;
let data = vec![
base_value,
base_value + epsilon,
base_value + 2.0 * epsilon,
base_value + 3.0 * epsilon,
];
let arr = Array1::from_vec(data);
match var(&arr.view(), 1, None) {
Ok(variance) => variance >= 0.0 && (variance as f64).is_finite(),
_ => false,
}
}
pub fn test_mixed_sign_values() -> bool {
let data = vec![-1e6, -1.0, 0.0, 1.0, 1e6];
let arr = Array1::from_vec(data);
match (
mean(&arr.view()),
var(&arr.view(), 1, None),
skew(&arr.view(), false, None),
) {
(Ok(mean_val), Ok(var_val), Ok(skew_val)) => {
(mean_val as f64).is_finite()
&& (var_val as f64).is_finite()
&& (skew_val as f64).is_finite()
}
_ => false,
}
}
pub fn test_perfect_correlation() -> bool {
let x = vec![1.0, 2.0, 3.0, 4.0, 5.0];
let y = vec![2.0, 4.0, 6.0, 8.0, 10.0];
let arr_x = Array1::from_vec(x);
let arr_y = Array1::from_vec(y);
match pearson_r(&arr_x.view(), &arr_y.view()) {
Ok(corr) => ((corr - 1.0) as f64).abs() < 1e-12,
_ => false,
}
}
pub fn test_perfect_anticorrelation() -> bool {
let x = vec![1.0, 2.0, 3.0, 4.0, 5.0];
let y = vec![5.0, 4.0, 3.0, 2.0, 1.0];
let arr_x = Array1::from_vec(x);
let arr_y = Array1::from_vec(y);
match pearson_r(&arr_x.view(), &arr_y.view()) {
Ok(corr) => ((corr + 1.0) as f64).abs() < 1e-12,
_ => false,
}
}
pub fn test_zero_variance() -> bool {
let constantdata = vec![5.0, 5.0, 5.0, 5.0, 5.0];
let arr = Array1::from_vec(constantdata);
match var(&arr.view(), 1, None) {
Ok(variance) => (variance as f64).abs() < 1e-15,
_ => false,
}
}
pub fn test_repeated_operations() -> bool {
let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
for _ in 0..100 {
let arr = Array1::from_vec(data.clone());
match mean(&arr.view()) {
Ok(mean_val) => {
if !(mean_val as f64).is_finite() {
return false;
}
}
_ => return false,
}
}
true
}
}
pub struct FuzzingTester;
impl FuzzingTester {
pub fn generate_randomdata(size: usize, seed: u64) -> StatisticalTestData {
use scirs2_core::random::rngs::StdRng;
use scirs2_core::random::{Rng, SeedableRng};
let mut rng = StdRng::seed_from_u64(seed);
let data: Vec<f64> = (0..size)
.map(|_| rng.random_range(-1000.0..1000.0))
.collect();
StatisticalTestData::new(data)
}
pub fn generate_skeweddata(
size: usize,
skew_direction: f64,
seed: u64,
) -> StatisticalTestData {
use scirs2_core::random::rngs::StdRng;
use scirs2_core::random::{Rng, SeedableRng};
let mut rng = StdRng::seed_from_u64(seed);
let mut data: Vec<f64> = (0..size).map(|_| rng.random_range(0.0..1.0)).collect();
if skew_direction > 0.0 {
data = data.into_iter().map(|x| x.powf(skew_direction)).collect();
} else if skew_direction < 0.0 {
data = data
.into_iter()
.map(|x| 1.0 - (1.0 - x).powf(-skew_direction))
.collect();
}
StatisticalTestData::new(data)
}
pub fn generate_outlierdata(
size: usize,
outlier_fraction: f64,
seed: u64,
) -> StatisticalTestData {
use scirs2_core::random::rngs::StdRng;
use scirs2_core::random::{Rng, SeedableRng};
let mut rng = StdRng::seed_from_u64(seed);
let mut data: Vec<f64> = (0..size).map(|_| rng.random_range(-1.0..1.0)).collect();
let num_outliers = (size as f64 * outlier_fraction) as usize;
for _ in 0..num_outliers {
let idx = rng.random_range(0..size);
data[idx] = rng.random_range(-100.0..100.0); }
StatisticalTestData::new(data)
}
pub fn test_mean_stability_fuzz(iterations: usize) -> bool {
for i in 0..iterations {
let testdata = Self::generate_randomdata(100, i as u64);
let arr = Array1::from_vec(testdata.data);
match mean(&arr.view()) {
Ok(result) => {
if !result.is_finite() {
return false;
}
}
Err(_) => {
if !arr.is_empty() {
return false;
}
}
}
}
true
}
pub fn test_variance_stability_fuzz(iterations: usize) -> bool {
for i in 0..iterations {
let skew_levels = [-2.0, -0.5, 0.0, 0.5, 2.0];
for &skew in &skew_levels {
let testdata = Self::generate_skeweddata(100, skew, i as u64);
let arr = Array1::from_vec(testdata.data);
if arr.len() < 2 {
continue;
}
match var(&arr.view(), 1, None) {
Ok(result) => {
if !result.is_finite() || result < 0.0 {
return false;
}
}
Err(_) => return false,
}
}
}
true
}
pub fn test_correlation_robustness_fuzz(iterations: usize) -> bool {
for i in 0..iterations {
let outlier_fractions = [0.0, 0.1, 0.2, 0.3];
for &fraction in &outlier_fractions {
let testdata1 = Self::generate_outlierdata(50, fraction, i as u64);
let testdata2 = Self::generate_outlierdata(50, fraction, (i + 1) as u64);
let arr1 = Array1::from_vec(testdata1.data);
let arr2 = Array1::from_vec(testdata2.data);
match pearson_r(&arr1.view(), &arr2.view()) {
Ok(corr) => {
if !corr.is_finite() || corr < -1.0 || corr > 1.0 {
return false;
}
}
Err(_) => return false,
}
}
}
true
}
}
pub struct CrossPlatformTester;
impl CrossPlatformTester {
pub fn test_floating_point_consistency(testdata: &StatisticalTestData) -> bool {
if testdata.data.len() < 2 {
return true;
}
let f32data: Vec<f32> = testdata.data.iter().map(|&x| x as f32).collect();
let f64_from_f32: Vec<f64> = f32data.iter().map(|&x| x as f64).collect();
let original_arr = Array1::from_vec(testdata.data.clone());
let converted_arr = Array1::from_vec(f64_from_f32);
match (mean(&original_arr.view()), mean(&converted_arr.view())) {
(Ok(original_mean), Ok(converted_mean)) => {
let relative_error =
((original_mean - converted_mean) / original_mean.max(1e-10)).abs();
relative_error < 1e-6 }
_ => false,
}
}
pub fn test_endianness_independence(testdata: &StatisticalTestData) -> bool {
if testdata.data.len() < 2 {
return true;
}
let arr = Array1::from_vec(testdata.data.clone());
let mut means = Vec::new();
for _ in 0..10 {
match mean(&arr.view()) {
Ok(m) => means.push(m),
_ => return false,
}
}
let first_mean = means[0];
means.iter().all(|&m| (m - first_mean).abs() < 1e-15)
}
}
pub struct RobustnessTester;
impl RobustnessTester {
pub fn test_nan_infinity_handling() -> bool {
let nandata = vec![1.0, 2.0, f64::NAN, 4.0, 5.0];
let nan_arr = Array1::from_vec(nandata);
let infdata = vec![1.0, 2.0, f64::INFINITY, 4.0, 5.0];
let inf_arr = Array1::from_vec(infdata);
let nan_result = mean(&nan_arr.view());
let inf_result = mean(&inf_arr.view());
match (nan_result, inf_result) {
(Ok(nan_mean), Ok(inf_mean)) => {
nan_mean.is_nan() && inf_mean.is_infinite()
}
(Err(_), Err(_)) => true, _ => false, }
}
pub fn test_largedataset_stability() -> bool {
let largesize = 10_000;
let data: Vec<f64> = (0..largesize).map(|i| (i as f64).sin()).collect();
let arr = Array1::from_vec(data);
match mean(&arr.view()) {
Ok(result) => result.is_finite(),
Err(_) => false,
}
}
pub fn test_single_element_arrays() -> bool {
let singledata = vec![42.0];
let arr = Array1::from_vec(singledata);
match mean(&arr.view()) {
Ok(result) => ((result - 42.0) as f64).abs() < 1e-15,
Err(_) => false,
}
}
pub fn test_empty_arrays() -> bool {
let empty_data: Vec<f64> = vec![];
let arr = Array1::from_vec(empty_data);
match mean(&arr.view()) {
Ok(_) => false, Err(_) => true, }
}
pub fn test_zero_arrays() -> bool {
let zerodata = vec![0.0; 100];
let arr = Array1::from_vec(zerodata);
match (mean(&arr.view()), var(&arr.view(), 1, None)) {
(Ok(mean_val), Ok(var_val)) => {
(mean_val as f64).abs() < 1e-15 && (var_val as f64).abs() < 1e-15
}
_ => false,
}
}
pub fn test_constant_arrays() -> bool {
let constant_value = 123.456;
let constantdata = vec![constant_value; 50];
let arr = Array1::from_vec(constantdata);
match (mean(&arr.view()), var(&arr.view(), 1, None)) {
(Ok(mean_val), Ok(var_val)) => {
((mean_val - constant_value) as f64).abs() < 1e-15 && (var_val as f64).abs() < 1e-15
}
_ => false,
}
}
}
pub struct PerformanceRegressionTester;
impl PerformanceRegressionTester {
pub fn benchmark_mean_performance(size: usize, iterations: usize) -> std::time::Duration {
let data: Vec<f64> = (0..size).map(|i| i as f64).collect();
let arr = Array1::from_vec(data);
let start = std::time::Instant::now();
for _ in 0..iterations {
let _ = mean(&arr.view());
}
start.elapsed()
}
pub fn benchmark_variance_performance(size: usize, iterations: usize) -> std::time::Duration {
let data: Vec<f64> = (0..size).map(|i| i as f64).collect();
let arr = Array1::from_vec(data);
let start = std::time::Instant::now();
for _ in 0..iterations {
let _ = var(&arr.view(), 1, None);
}
start.elapsed()
}
pub fn compare_simd_performance(
size: usize,
iterations: usize,
) -> (std::time::Duration, std::time::Duration) {
let data: Vec<f64> = (0..size).map(|i| i as f64).collect();
let arr = Array1::from_vec(data);
let start_scalar = std::time::Instant::now();
for _ in 0..iterations {
let _ = mean(&arr.view());
}
let scalar_time = start_scalar.elapsed();
let start_simd = std::time::Instant::now();
for _ in 0..iterations {
let _ = mean_simd(&arr.view());
}
let simd_time = start_simd.elapsed();
(scalar_time, simd_time)
}
pub fn test_performance_stability() -> bool {
let size = 1_000;
let iterations = 10;
let patterns = [
(0..size).map(|i| i as f64).collect::<Vec<_>>(), (0..size).map(|i| (i % 1000) as f64).collect::<Vec<_>>(), (0..size)
.map(|i| ((i * 31) % 10007) as f64)
.collect::<Vec<_>>(), ];
let mut times = Vec::new();
for pattern in &patterns {
let arr = Array1::from_vec(pattern.clone());
let start = std::time::Instant::now();
for _ in 0..iterations {
let _ = mean(&arr.view());
}
times.push(start.elapsed());
}
let min_time = times.iter().min().expect("Operation failed");
let max_time = times.iter().max().expect("Operation failed");
max_time.as_nanos() <= min_time.as_nanos() * 2
}
}
pub struct ExtendedMathematicalTester;
impl ExtendedMathematicalTester {
pub fn test_cauchy_schwarz_inequality(
xdata: &StatisticalTestData,
y_data: &StatisticalTestData,
zdata: &StatisticalTestData,
) -> bool {
if xdata.data.len() != y_data.data.len() || y_data.data.len() != zdata.data.len() {
return false;
}
let x_arr = Array1::from_vec(xdata.data.clone());
let y_arr = Array1::from_vec(y_data.data.clone());
let z_arr = Array1::from_vec(zdata.data.clone());
match (
pearson_r(&x_arr.view(), &y_arr.view()),
pearson_r(&y_arr.view(), &z_arr.view()),
pearson_r(&x_arr.view(), &z_arr.view()),
) {
(Ok(rxy), Ok(ryz), Ok(rxz)) => {
let bound = ((1.0 - rxy * rxy) * (1.0 - ryz * ryz)).sqrt() + (rxy * ryz).abs();
rxz.abs() <= bound + 1e-6
}
_ => false,
}
}
pub fn test_triangle_inequality_property(
xdata: &StatisticalTestData,
y_data: &StatisticalTestData,
zdata: &StatisticalTestData,
) -> bool {
if xdata.data.len() != y_data.data.len() || y_data.data.len() != zdata.data.len() {
return false;
}
let x_arr = Array1::from_vec(xdata.data.clone());
let y_arr = Array1::from_vec(y_data.data.clone());
let z_arr = Array1::from_vec(zdata.data.clone());
match (
pearson_r(&x_arr.view(), &y_arr.view()),
pearson_r(&y_arr.view(), &z_arr.view()),
pearson_r(&x_arr.view(), &z_arr.view()),
) {
(Ok(rxy), Ok(ryz), Ok(rxz)) => {
let dxy = 1.0 - rxy.abs();
let dyz = 1.0 - ryz.abs();
let dxz = 1.0 - rxz.abs();
dxz <= dxy + dyz + 1e-12
}
_ => false,
}
}
pub fn test_jensen_inequality(testdata: &StatisticalTestData) -> bool {
if testdata.data.len() < 2 {
return true;
}
let positivedata: Vec<f64> = testdata.data.iter()
.map(|&x| x.abs().min(10.0)) .collect();
let arr = Array1::from_vec(positivedata.clone());
let exp_arr = Array1::from_vec(positivedata.iter().map(|&x| x.exp()).collect());
match (mean(&arr.view()), mean(&exp_arr.view())) {
(Ok(mean_x), Ok(mean_exp_x)) => {
let exp_mean_x = mean_x.exp();
mean_exp_x >= exp_mean_x - 1e-12
}
_ => false,
}
}
pub fn test_minkowski_inequality(
xdata: &StatisticalTestData,
y_data: &StatisticalTestData,
) -> bool {
if xdata.data.len() != y_data.data.len() || xdata.data.len() < 2 {
return false;
}
let x_arr = Array1::from_vec(xdata.data.clone());
let y_arr = Array1::from_vec(y_data.data.clone());
let sumdata: Vec<f64> = xdata
.data
.iter()
.zip(y_data.data.iter())
.map(|(&x, &y)| x + y)
.collect();
let sum_arr = Array1::from_vec(sumdata);
match (
var(&x_arr.view(), 1, None),
var(&y_arr.view(), 1, None),
var(&sum_arr.view(), 1, None),
) {
(Ok(var_x), Ok(var_y), Ok(var_sum)) => {
let std_x = var_x.sqrt();
let std_y = var_y.sqrt();
let std_sum = var_sum.sqrt();
std_sum <= std_x + std_y + 1e-10
}
_ => false,
}
}
pub fn test_chebyshev_inequality(testdata: &StatisticalTestData) -> bool {
if testdata.data.len() < 10 {
return true;
}
let arr = Array1::from_vec(testdata.data.clone());
match (mean(&arr.view()), var(&arr.view(), 1, None)) {
(Ok(mean_val), Ok(var_val)) => {
let std_val = var_val.sqrt();
if std_val <= 1e-10 {
return true; }
let k = 2.0;
let lower_bound = mean_val - k * std_val;
let upper_bound = mean_val + k * std_val;
let within_bounds = testdata
.data
.iter()
.filter(|&&x| x >= lower_bound && x <= upper_bound)
.count();
let proportion_within = within_bounds as f64 / testdata.data.len() as f64;
let chebyshev_bound = 1.0 - 1.0 / (k * k);
proportion_within >= chebyshev_bound - 0.1 }
_ => false,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_simd_consistency() {
let testdata = StatisticalTestData::generate_large_sample();
assert!(SimdConsistencyTester::test_mean_consistency(&testdata));
assert!(SimdConsistencyTester::test_variance_consistency(&testdata));
assert!(SimdConsistencyTester::test_skewness_consistency(&testdata));
assert!(SimdConsistencyTester::test_kurtosis_consistency(&testdata));
}
#[test]
fn test_parallel_consistency() {
let matrixdata = MatrixTestData::generate_sample();
assert!(ParallelConsistencyTester::test_correlation_matrix_consistency(&matrixdata));
}
#[test]
fn test_mathematical_invariants() {
let testdata1 = StatisticalTestData::generate_sample(); let testdata2 = StatisticalTestData::new(vec![2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0, 20.0]); let matrixdata = MatrixTestData::generate_sample();
assert!(MathematicalInvariantTester::test_correlation_bounds(
&testdata1,
&testdata1
));
assert!(MathematicalInvariantTester::test_variance_properties(
&testdata1
));
assert!(MathematicalInvariantTester::test_moment_properties(
&testdata1
));
assert!(MathematicalInvariantTester::test_correlation_matrix_symmetry(&matrixdata));
assert!(MathematicalInvariantTester::test_mean_linearity(
&testdata1
));
assert!(MathematicalInvariantTester::test_variance_scaling(
&testdata1
));
assert!(
MathematicalInvariantTester::test_correlation_translation_invariance(
&testdata1,
&testdata2
)
);
assert!(MathematicalInvariantTester::test_skewness_properties(
&testdata1
));
assert!(MathematicalInvariantTester::test_kurtosis_properties(
&testdata1
));
}
#[test]
fn test_batch_processing() {
let matrixdata = MatrixTestData::generate_sample();
assert!(BatchProcessingTester::test_batch_mean_consistency(
&matrixdata
));
assert!(BatchProcessingTester::test_batch_correlation_consistency(
&matrixdata
));
}
#[test]
fn test_memory_optimization() {
let matrixdata = MatrixTestData::generate_sample();
assert!(MemoryOptimizationTester::test_memory_optimized_correlation(
&matrixdata
));
}
#[test]
fn test_numerical_stability() {
assert!(NumericalStabilityTester::test_extreme_values());
assert!(NumericalStabilityTester::test_nearly_identical_values());
assert!(NumericalStabilityTester::test_mixed_sign_values());
assert!(NumericalStabilityTester::test_perfect_correlation());
assert!(NumericalStabilityTester::test_perfect_anticorrelation());
assert!(NumericalStabilityTester::test_zero_variance());
assert!(NumericalStabilityTester::test_repeated_operations());
}
#[test]
fn test_fuzzing_framework() {
assert!(FuzzingTester::test_mean_stability_fuzz(1));
assert!(FuzzingTester::test_variance_stability_fuzz(1));
assert!(FuzzingTester::test_correlation_robustness_fuzz(1));
}
#[test]
fn test_cross_platform_consistency() {
let testdata = StatisticalTestData::generate_sample();
assert!(CrossPlatformTester::test_floating_point_consistency(
&testdata
));
assert!(CrossPlatformTester::test_endianness_independence(
&testdata
));
}
#[test]
fn test_robustness() {
assert!(RobustnessTester::test_nan_infinity_handling());
assert!(RobustnessTester::test_largedataset_stability());
assert!(RobustnessTester::test_single_element_arrays());
assert!(RobustnessTester::test_empty_arrays());
assert!(RobustnessTester::test_zero_arrays());
assert!(RobustnessTester::test_constant_arrays());
}
#[test]
#[ignore] fn test_performance_regression() {
let size = 1000;
let iterations = 100;
let mean_time = PerformanceRegressionTester::benchmark_mean_performance(size, iterations);
let var_time =
PerformanceRegressionTester::benchmark_variance_performance(size, iterations);
assert!(mean_time.as_millis() < 1000); assert!(var_time.as_millis() < 1000);
let (scalar_time, simd_time) =
PerformanceRegressionTester::compare_simd_performance(size, iterations);
assert!(simd_time.as_nanos() <= scalar_time.as_nanos() * 2);
assert!(PerformanceRegressionTester::test_performance_stability());
}
#[test]
fn test_extended_mathematical_properties() {
let testdata1 = StatisticalTestData::generate_sample(); let testdata2 = StatisticalTestData::new(vec![2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0, 20.0]); let testdata3 = StatisticalTestData::new(vec![1.0, 4.0, 2.0, 8.0, 5.0, 7.0, 3.0, 9.0, 6.0, 10.0]);
assert!(ExtendedMathematicalTester::test_cauchy_schwarz_inequality(
&testdata1,
&testdata2,
&testdata3
));
assert!(
ExtendedMathematicalTester::test_triangle_inequality_property(
&testdata1,
&testdata2,
&testdata3
)
);
assert!(ExtendedMathematicalTester::test_jensen_inequality(
&testdata1
));
assert!(ExtendedMathematicalTester::test_minkowski_inequality(
&testdata1,
&testdata2
));
assert!(ExtendedMathematicalTester::test_chebyshev_inequality(
&testdata2
)); }
#[test]
fn testdata_generators() {
let randomdata = FuzzingTester::generate_randomdata(100, 42);
assert_eq!(randomdata.data.len(), 100);
let skeweddata = FuzzingTester::generate_skeweddata(50, 2.0, 123);
assert_eq!(skeweddata.data.len(), 50);
let outlierdata = FuzzingTester::generate_outlierdata(75, 0.1, 456);
assert_eq!(outlierdata.data.len(), 75);
let data1 = FuzzingTester::generate_randomdata(10, 999);
let data2 = FuzzingTester::generate_randomdata(10, 999);
assert_eq!(data1.data, data2.data);
}
}