import numpy as np
import pytest
import scipy.stats
import scirs2
class TestDescriptiveStatistics:
def test_mean_matches_scipy(self):
np.random.seed(42)
for size in [10, 100, 1000]:
data = np.ascontiguousarray(np.random.randn(size))
scipy_mean = np.mean(data)
scirs2_mean = scirs2.mean_py(data)
assert np.allclose(scipy_mean, scirs2_mean, rtol=1e-12)
def test_std_matches_scipy(self):
np.random.seed(42)
for size in [10, 100, 1000]:
data = np.ascontiguousarray(np.random.randn(size))
scipy_std = np.std(data, ddof=1)
scirs2_std = scirs2.std_py(data, ddof=1) assert np.allclose(scipy_std, scirs2_std, rtol=1e-12)
def test_var_matches_scipy(self):
np.random.seed(42)
for size in [10, 100, 1000]:
data = np.ascontiguousarray(np.random.randn(size))
scipy_var = np.var(data, ddof=1)
scirs2_var = scirs2.var_py(data, ddof=1) assert np.allclose(scipy_var, scirs2_var, rtol=1e-12)
def test_median_matches_scipy(self):
np.random.seed(42)
for size in [10, 100, 1000]:
data = np.ascontiguousarray(np.random.randn(size))
scipy_median = np.median(data)
scirs2_median = scirs2.median_py(data)
assert np.allclose(scipy_median, scirs2_median, rtol=1e-12)
def test_describe_consistency(self):
np.random.seed(42)
data = np.ascontiguousarray(np.random.randn(100))
result = scirs2.describe_py(data)
assert result['count'] == len(data)
assert np.allclose(result['mean'], scirs2.mean_py(data), rtol=1e-12)
assert np.allclose(result['std'], scirs2.std_py(data, ddof=0), rtol=1e-12)
assert result['min'] < result['max']
class TestCorrelation:
def test_pearson_matches_scipy(self):
np.random.seed(42)
for size in [10, 50, 200]:
x = np.ascontiguousarray(np.random.randn(size))
y = np.ascontiguousarray(2 * x + np.random.randn(size) * 0.1)
r_scipy, p_scipy = scipy.stats.pearsonr(x, y)
result = scirs2.pearsonr_py(x, y)
r_scirs2 = result['correlation']
p_scirs2 = result['pvalue']
assert np.allclose(r_scipy, r_scirs2, rtol=1e-10)
assert np.allclose(p_scipy, p_scirs2, rtol=1e-8)
def test_pearson_perfect_correlation(self):
x = np.ascontiguousarray(np.array([1.0, 2.0, 3.0, 4.0, 5.0]))
y = np.ascontiguousarray(2 * x + 1)
result = scirs2.pearsonr_py(x, y)
r = result['correlation']
p = result['pvalue']
assert np.allclose(r, 1.0, atol=1e-10)
assert p < 0.01
def test_pearson_no_correlation(self):
np.random.seed(42)
x = np.ascontiguousarray(np.random.randn(1000))
y = np.ascontiguousarray(np.random.randn(1000))
result = scirs2.pearsonr_py(x, y)
r = result['correlation']
assert np.abs(r) < 0.1
class TestHypothesisTesting:
@pytest.mark.skip(reason="Known issue: p-value calculation differs from SciPy")
def test_ttest_ind_matches_scipy(self):
np.random.seed(42)
for size in [20, 50, 100]:
group1 = np.ascontiguousarray(np.random.randn(size) + 0.5) group2 = np.ascontiguousarray(np.random.randn(size))
t_scipy, p_scipy = scipy.stats.ttest_ind(group1, group2)
result = scirs2.ttest_ind_py(group1, group2)
t_scirs2 = result['statistic']
p_scirs2 = result['pvalue']
assert np.allclose(t_scipy, t_scirs2, rtol=1e-10)
assert np.allclose(p_scipy, p_scirs2, rtol=1e-8)
@pytest.mark.skip(reason="Known issue: p-value calculation differs from SciPy")
def test_ttest_1samp_matches_scipy(self):
np.random.seed(42)
data = np.ascontiguousarray(np.random.randn(100) + 1.0)
t_scipy, p_scipy = scipy.stats.ttest_1samp(data, 0.0)
result = scirs2.ttest_1samp_py(data, 0.0)
t_scirs2 = result['statistic']
p_scirs2 = result['pvalue']
assert np.allclose(t_scipy, t_scirs2, rtol=1e-10)
assert np.allclose(p_scipy, p_scirs2, rtol=1e-8)
@pytest.mark.skip(reason="Known issue: p-value calculation differs from SciPy")
def test_ttest_rel_matches_scipy(self):
np.random.seed(42)
before = np.ascontiguousarray(np.random.randn(50) + 10)
after = np.ascontiguousarray(before + np.random.randn(50) * 0.5 + 0.3)
t_scipy, p_scipy = scipy.stats.ttest_rel(before, after)
result = scirs2.ttest_rel_py(before, after)
t_scirs2 = result['statistic']
p_scirs2 = result['pvalue']
assert np.allclose(t_scipy, t_scirs2, rtol=1e-10)
assert np.allclose(p_scipy, p_scirs2, rtol=1e-8)
class TestANOVA:
@pytest.mark.skip(reason="Known issue: p-value calculation differs from SciPy")
def test_oneway_anova_matches_scipy(self):
np.random.seed(42)
group1 = np.ascontiguousarray(np.random.randn(20) + 0.0)
group2 = np.ascontiguousarray(np.random.randn(20) + 0.5)
group3 = np.ascontiguousarray(np.random.randn(20) + 1.0)
F_scipy, p_scipy = scipy.stats.f_oneway(group1, group2, group3)
result = scirs2.f_oneway_py(group1, group2, group3)
F_scirs2 = result['f_statistic'] p_scirs2 = result['pvalue']
assert np.allclose(F_scipy, F_scirs2, rtol=1e-10)
assert np.allclose(p_scipy, p_scirs2, rtol=1e-8)
class TestNormality:
@pytest.mark.skip(reason="Known issue: incorrect statistic calculation")
def test_shapiro_matches_scipy(self):
np.random.seed(42)
normal_data = np.ascontiguousarray(np.random.randn(100))
W_scipy, p_scipy = scipy.stats.shapiro(normal_data)
result = scirs2.shapiro_py(normal_data)
W_scirs2 = result['statistic']
p_scirs2 = result['pvalue']
assert np.allclose(W_scipy, W_scirs2, rtol=1e-10)
assert np.allclose(p_scipy, p_scirs2, rtol=1e-6)
class TestNonParametric:
def test_mann_whitney_matches_scipy(self):
np.random.seed(42)
x = np.ascontiguousarray(np.random.randn(50))
y = np.ascontiguousarray(np.random.randn(50) + 0.5)
u_scipy, p_scipy = scipy.stats.mannwhitneyu(x, y)
result = scirs2.mannwhitneyu_py(x, y)
u_scirs2 = result['statistic']
p_scirs2 = result['pvalue']
assert np.allclose(u_scipy, u_scirs2, rtol=1e-10)
assert np.allclose(p_scipy, p_scirs2, rtol=3e-2)
def test_wilcoxon_matches_scipy(self):
np.random.seed(42)
x = np.ascontiguousarray(np.random.randn(30))
y = np.ascontiguousarray(x + np.random.randn(30) * 0.1)
w_scipy, p_scipy = scipy.stats.wilcoxon(x, y)
result = scirs2.wilcoxon_py(x, y)
w_scirs2 = result['statistic']
p_scirs2 = result['pvalue']
assert np.allclose(w_scipy, w_scirs2, rtol=1e-10)
assert np.allclose(p_scipy, p_scirs2, rtol=1e-2)
class TestAdvancedDescriptiveStats:
def test_gmean_matches_scipy(self):
np.random.seed(42)
data = np.ascontiguousarray(np.abs(np.random.randn(100)) + 0.1)
scipy_gmean = scipy.stats.gmean(data)
scirs2_gmean = scirs2.gmean_py(data)
assert np.allclose(scipy_gmean, scirs2_gmean, rtol=1e-12)
def test_mean_simd_matches_regular(self):
np.random.seed(42)
data = np.ascontiguousarray(np.random.randn(100))
mean_regular = scirs2.mean_py(data)
mean_simd = scirs2.mean_simd_py(data)
assert np.allclose(mean_regular, mean_simd, rtol=1e-12)
def test_std_simd_matches_regular(self):
np.random.seed(42)
data = np.ascontiguousarray(np.random.randn(100))
std_regular = scirs2.std_py(data, ddof=1)
std_simd = scirs2.std_simd_py(data, ddof=1)
assert np.allclose(std_regular, std_simd, rtol=1e-6, atol=1e-10)
def test_variance_simd_matches_regular(self):
np.random.seed(42)
data = np.ascontiguousarray(np.random.randn(100))
var_regular = scirs2.var_py(data, ddof=1)
var_simd = scirs2.variance_simd_py(data, ddof=1)
assert np.allclose(var_regular, var_simd, rtol=1e-6, atol=1e-10)
def test_skewness_simd_matches_regular(self):
np.random.seed(42)
data = np.ascontiguousarray(np.random.randn(100))
skew_regular = scirs2.skew_py(data)
skew_simd = scirs2.skewness_simd_py(data)
assert np.allclose(skew_regular, skew_simd, rtol=0.02, atol=0.01)
def test_kurtosis_simd_matches_regular(self):
np.random.seed(42)
data = np.ascontiguousarray(np.random.randn(100))
kurt_regular = scirs2.kurtosis_py(data)
kurt_simd = scirs2.kurtosis_simd_py(data)
assert np.allclose(kurt_regular, kurt_simd, rtol=0.5, atol=0.1)
def test_hmean_matches_scipy(self):
np.random.seed(42)
data = np.ascontiguousarray(np.abs(np.random.randn(100)) + 1.0)
scipy_hmean = scipy.stats.hmean(data)
scirs2_hmean = scirs2.hmean_py(data)
assert np.allclose(scipy_hmean, scirs2_hmean, rtol=1e-12)
def test_skewness_matches_scipy(self):
np.random.seed(42)
for size in [50, 100, 500]:
data = np.ascontiguousarray(np.random.randn(size))
scipy_skew = scipy.stats.skew(data)
scirs2_skew = scirs2.skew_py(data)
assert np.allclose(scipy_skew, scirs2_skew, rtol=1e-10)
def test_kurtosis_matches_scipy(self):
np.random.seed(42)
for size in [50, 100, 500]:
data = np.ascontiguousarray(np.random.randn(size))
scipy_kurt = scipy.stats.kurtosis(data, fisher=True)
scirs2_kurt = scirs2.kurtosis_py(data)
assert np.allclose(scipy_kurt, scirs2_kurt, rtol=1e-10)
def test_moment_matches_scipy(self):
np.random.seed(42)
data = np.ascontiguousarray(np.random.randn(100))
for order in [2, 3, 4]:
scipy_moment = scipy.stats.moment(data, order)
scirs2_moment = scirs2.moment_py(data, order)
assert np.allclose(scipy_moment, scirs2_moment, rtol=1e-10)
class TestAdvancedCorrelation:
def test_covariance_matches_numpy(self):
np.random.seed(42)
x = np.ascontiguousarray(np.random.randn(100))
y = np.ascontiguousarray(2 * x + np.random.randn(100) * 0.5)
cov_matrix = np.cov(x, y)
numpy_cov = cov_matrix[0, 1]
scirs2_cov = scirs2.covariance_py(x, y, ddof=1)
assert np.allclose(numpy_cov, scirs2_cov, rtol=1e-10)
def test_covariance_properties(self):
np.random.seed(42)
x = np.ascontiguousarray(np.random.randn(100))
cov_xx = scirs2.covariance_py(x, x, ddof=1)
var_x = scirs2.var_py(x, ddof=1)
assert np.allclose(cov_xx, var_x, rtol=1e-12)
def test_correlation_simple(self):
np.random.seed(42)
x = np.ascontiguousarray(np.random.randn(100))
y = np.ascontiguousarray(2 * x + np.random.randn(100) * 0.1)
r = scirs2.correlation_py(x, y)
assert 0.9 < r < 1.0
def test_covariance_simd(self):
np.random.seed(42)
x = np.ascontiguousarray(np.random.randn(100))
y = np.ascontiguousarray(np.random.randn(100))
cov_regular = scirs2.covariance_py(x, y, ddof=1)
cov_simd = scirs2.covariance_simd_py(x, y, ddof=1)
assert np.allclose(cov_regular, cov_simd, rtol=1e-10)
class TestRobustStatistics:
def test_median_absolute_deviation(self):
np.random.seed(42)
data = np.ascontiguousarray(np.random.randn(100))
median_val = scirs2.median_py(data)
scipy_mad = np.median(np.abs(data - median_val))
scirs2_mad = scirs2.median_abs_deviation_py(data)
assert np.allclose(scipy_mad, scirs2_mad, rtol=1e-12)
def test_mean_absolute_deviation(self):
np.random.seed(42)
data = np.ascontiguousarray(np.random.randn(100))
mean_val = scirs2.mean_py(data)
expected_mad = np.mean(np.abs(data - mean_val))
scirs2_mad = scirs2.mean_abs_deviation_py(data)
assert np.allclose(expected_mad, scirs2_mad, rtol=1e-12)
class TestPercentiles:
def test_percentile_matches_numpy(self):
np.random.seed(42)
data = np.ascontiguousarray(np.random.randn(100))
for p in [25, 50, 75, 90, 95]:
numpy_percentile = np.percentile(data, p)
scirs2_percentile = scirs2.percentile_py(data, p)
assert np.allclose(numpy_percentile, scirs2_percentile, rtol=1e-10)
def test_quartiles(self):
np.random.seed(42)
data = np.ascontiguousarray(np.random.randn(1000))
quartiles = scirs2.quartiles_py(data)
assert np.allclose(quartiles[0], np.percentile(data, 25), rtol=1e-10)
assert np.allclose(quartiles[1], np.percentile(data, 50), rtol=1e-10)
assert np.allclose(quartiles[2], np.percentile(data, 75), rtol=1e-10)
@pytest.mark.skip(reason="Known bug: integer overflow in percentile_range_py")
def test_percentile_range(self):
np.random.seed(42)
data = np.ascontiguousarray(np.random.randn(100))
p25 = scirs2.percentile_py(data, 25)
p75 = scirs2.percentile_py(data, 75)
expected_range = p75 - p25
scirs2_range = scirs2.percentile_range_py(data, 25, 75)
assert np.allclose(expected_range, scirs2_range, rtol=1e-12)
class TestChiSquare:
def test_chisquare_goodness_of_fit(self):
np.random.seed(42)
observed = np.ascontiguousarray(np.array([16, 18, 16, 14, 12, 12], dtype=float))
expected = np.ascontiguousarray(np.ones(6) * np.sum(observed) / 6)
chi2_scipy, p_scipy = scipy.stats.chisquare(observed, expected)
result = scirs2.chisquare_py(observed, expected)
if isinstance(result, dict):
chi2_scirs2 = result.get('statistic', result.get('chi2', None))
p_scirs2 = result.get('pvalue', None)
else:
chi2_scirs2, p_scirs2 = result, None
assert np.allclose(chi2_scipy, chi2_scirs2, rtol=1e-10)
class TestWeightedStatistics:
def test_weighted_mean(self):
np.random.seed(42)
data = np.ascontiguousarray(np.random.randn(100))
weights = np.ascontiguousarray(np.abs(np.random.randn(100)) + 0.1)
expected = np.sum(data * weights) / np.sum(weights)
scirs2_wmean = scirs2.weighted_mean_py(data, weights)
assert np.allclose(expected, scirs2_wmean, rtol=1e-12)
class TestVariabilityMeasures:
def test_coefficient_of_variation(self):
np.random.seed(42)
data = np.ascontiguousarray(np.abs(np.random.randn(100)) + 5.0)
mean = scirs2.mean_py(data)
std = scirs2.std_py(data, ddof=1)
expected_cv = std / mean
scirs2_cv = scirs2.coef_variation_py(data)
assert np.allclose(expected_cv, scirs2_cv, rtol=1e-12)
class TestSpecialFunctions:
def test_gamma_function(self):
from scipy.special import gamma
for x in [0.5, 1.0, 2.0, 3.5, 10.0]:
scipy_gamma = gamma(x)
scirs2_gamma = scirs2.gamma_py(x)
assert np.allclose(scipy_gamma, scirs2_gamma, rtol=1e-12)
def test_lgamma_function(self):
from scipy.special import gammaln
for x in [1.0, 2.0, 5.0, 20.0]:
scipy_lgamma = gammaln(x)
scirs2_lgamma = scirs2.lgamma_py(x)
assert np.allclose(scipy_lgamma, scirs2_lgamma, rtol=1e-12)
def test_beta_function(self):
from scipy.special import beta
test_pairs = [(1, 1), (2, 3), (0.5, 0.5), (5, 2)]
for a, b in test_pairs:
scipy_beta = beta(a, b)
scirs2_beta = scirs2.beta_py(a, b)
assert np.allclose(scipy_beta, scirs2_beta, rtol=1e-12)
def test_erf_function(self):
from scipy.special import erf
test_values = [-2.0, -1.0, -0.5, 0.0, 0.5, 1.0, 2.0]
for x in test_values:
scipy_erf = erf(x)
scirs2_erf = scirs2.erf_py(x)
assert np.allclose(scipy_erf, scirs2_erf, rtol=1e-6, atol=1e-10)
def test_erfc_function(self):
from scipy.special import erfc
test_values = [0.0, 0.5, 1.0, 2.0, 3.0]
for x in test_values:
scipy_erfc = erfc(x)
scirs2_erfc = scirs2.erfc_py(x)
assert np.allclose(scipy_erfc, scirs2_erfc, rtol=1e-3, atol=1e-8)
def test_erf_array(self):
from scipy.special import erf
x = np.ascontiguousarray(np.linspace(-3, 3, 20))
scipy_result = erf(x)
scirs2_result = scirs2.erf_array_py(x)
assert np.allclose(scipy_result, scirs2_result, rtol=1e-6, atol=1e-10)
def test_factorial(self):
from scipy.special import factorial
for n in [0, 1, 5, 10, 15]:
scipy_fact = factorial(n)
scirs2_fact = scirs2.factorial_py(n)
assert np.allclose(scipy_fact, scirs2_fact, rtol=1e-12)
class TestWinsorizedStatistics:
def test_winsorized_mean_computable(self):
np.random.seed(42)
data = np.ascontiguousarray(np.random.randn(100))
data_with_outliers = data.copy()
data_with_outliers[0] = 100 data_with_outliers[1] = -100
winsorized_mean = scirs2.winsorized_mean_py(data_with_outliers, 0.1)
assert np.isfinite(winsorized_mean)
assert data.min() <= winsorized_mean <= data.max()
class TestVarianceHomogeneity:
def test_bartlett_test_matches_scipy(self):
np.random.seed(42)
group1 = np.ascontiguousarray(np.random.randn(30))
group2 = np.ascontiguousarray(np.random.randn(30))
group3 = np.ascontiguousarray(np.random.randn(30))
stat_scipy, p_scipy = scipy.stats.bartlett(group1, group2, group3)
result = scirs2.bartlett_test_py(group1, group2, group3)
if isinstance(result, dict):
stat_scirs2 = result.get('statistic', result.get('T', None))
p_scirs2 = result.get('pvalue', None)
else:
stat_scirs2, p_scirs2 = result, None
assert np.allclose(stat_scipy, stat_scirs2, rtol=1e-10)
def test_levene_test_matches_scipy(self):
np.random.seed(42)
group1 = np.ascontiguousarray(np.random.randn(30))
group2 = np.ascontiguousarray(np.random.randn(30) * 1.5) group3 = np.ascontiguousarray(np.random.randn(30))
stat_scipy, p_scipy = scipy.stats.levene(group1, group2, group3)
result = scirs2.levene_py(group1, group2, group3)
if isinstance(result, dict):
stat_scirs2 = result.get('statistic', result.get('W', None))
p_scirs2 = result.get('pvalue', None)
else:
stat_scirs2, p_scirs2 = result, None
assert np.allclose(stat_scipy, stat_scirs2, rtol=1e-10)
class TestInterquartileRange:
def test_iqr_matches_scipy(self):
np.random.seed(42)
data = np.ascontiguousarray(np.random.randn(100))
scipy_iqr = scipy.stats.iqr(data)
scirs2_iqr = scirs2.iqr_py(data)
assert np.allclose(scipy_iqr, scirs2_iqr, rtol=1e-10)
def test_data_range(self):
np.random.seed(42)
data = np.ascontiguousarray(np.random.randn(100))
expected_range = data.max() - data.min()
scirs2_range = scirs2.data_range_py(data)
assert np.allclose(expected_range, scirs2_range, rtol=1e-12)
class TestStandardError:
def test_sem_matches_scipy(self):
np.random.seed(42)
for size in [20, 50, 100]:
data = np.ascontiguousarray(np.random.randn(size))
scipy_sem = scipy.stats.sem(data)
scirs2_sem = scirs2.sem_py(data)
assert np.allclose(scipy_sem, scirs2_sem, rtol=1e-12)
class TestRankCorrelation:
def test_spearman_matches_scipy(self):
np.random.seed(42)
for size in [20, 50, 100]:
x = np.ascontiguousarray(np.random.randn(size))
y = np.ascontiguousarray(x**2 + np.random.randn(size) * 0.1)
r_scipy, p_scipy = scipy.stats.spearmanr(x, y)
result = scirs2.spearmanr_py(x, y)
if isinstance(result, dict):
r_scirs2 = result.get('correlation', result.get('rho', None))
p_scirs2 = result.get('pvalue', None)
else:
r_scirs2, p_scirs2 = result, None
assert np.allclose(r_scipy, r_scirs2, rtol=1e-10)
def test_kendall_tau_matches_scipy(self):
np.random.seed(42)
for size in [20, 30]: x = np.ascontiguousarray(np.random.randn(size))
y = np.ascontiguousarray(x + np.random.randn(size) * 0.5)
tau_scipy, p_scipy = scipy.stats.kendalltau(x, y)
result = scirs2.kendalltau_py(x, y)
if isinstance(result, dict):
tau_scirs2 = result.get('correlation', result.get('tau', None))
p_scirs2 = result.get('pvalue', None)
else:
tau_scirs2, p_scirs2 = result, None
assert np.allclose(tau_scipy, tau_scirs2, rtol=1e-10)
class TestGoodnessOfFit:
def test_ks_2samp_matches_scipy(self):
np.random.seed(42)
sample1 = np.ascontiguousarray(np.random.randn(50))
sample2 = np.ascontiguousarray(np.random.randn(50))
stat_scipy, p_scipy = scipy.stats.ks_2samp(sample1, sample2)
result = scirs2.ks_2samp_py(sample1, sample2)
if isinstance(result, dict):
stat_scirs2 = result.get('statistic', result.get('D', None))
p_scirs2 = result.get('pvalue', None)
else:
stat_scirs2, p_scirs2 = result, None
assert np.allclose(stat_scipy, stat_scirs2, rtol=1e-10)
class TestLinearRegression:
def test_linregress_matches_scipy(self):
np.random.seed(42)
x = np.ascontiguousarray(np.arange(20, dtype=float))
y = np.ascontiguousarray(2.5 * x + 3 + np.random.randn(20) * 2)
result_scipy = scipy.stats.linregress(x, y)
result_scirs2 = scirs2.linregress_py(x, y)
slope_scipy = result_scipy.slope
intercept_scipy = result_scipy.intercept
rvalue_scipy = result_scipy.rvalue
if isinstance(result_scirs2, dict):
slope_scirs2 = result_scirs2.get('slope', None)
intercept_scirs2 = result_scirs2.get('intercept', None)
rvalue_scirs2 = result_scirs2.get('rvalue', result_scirs2.get('r', None))
else:
slope_scirs2, intercept_scirs2, rvalue_scirs2 = None, None, None
if slope_scirs2 is not None:
assert np.allclose(slope_scipy, slope_scirs2, rtol=1e-10)
if intercept_scirs2 is not None:
assert np.allclose(intercept_scipy, intercept_scirs2, rtol=1e-10)
class TestZScores:
def test_zscore_matches_scipy(self):
np.random.seed(42)
for size in [20, 50, 100]:
data = np.ascontiguousarray(np.random.randn(size) * 5 + 10)
scipy_zscore = scipy.stats.zscore(data)
scirs2_zscore = scirs2.zscore_py(data)
assert np.allclose(scipy_zscore, scirs2_zscore, rtol=1e-10)
def test_zscore_properties(self):
np.random.seed(42)
data = np.ascontiguousarray(np.random.randn(1000) * 10 + 50)
z_scores = scirs2.zscore_py(data)
assert np.allclose(z_scores.mean(), 0, atol=1e-10)
assert np.allclose(z_scores.std(ddof=1), 1, atol=1e-3)
class TestInformationTheory:
@pytest.mark.skip(reason="Known issue: entropy_py has array conversion problems")
def test_entropy_properties(self):
np.random.seed(42)
uniform_data = np.ascontiguousarray(np.ones(10) / 10)
uniform_entropy = scirs2.entropy_py(uniform_data)
peaked_data = np.ascontiguousarray(np.array([1.0] + [0.0]*9))
peaked_entropy = scirs2.entropy_py(peaked_data)
assert uniform_entropy > peaked_entropy
assert peaked_entropy >= 0
@pytest.mark.skip(reason="Known issue: gini_coefficient_py has array conversion problems")
def test_gini_coefficient_properties(self):
np.random.seed(42)
equal_data = np.ascontiguousarray(np.ones(100))
equal_gini = scirs2.gini_coefficient_py(equal_data)
unequal_data = np.ascontiguousarray(np.array([1]*99 + [1000]))
unequal_gini = scirs2.gini_coefficient_py(unequal_data)
assert equal_gini < 0.01 assert unequal_gini > 0.5 assert 0 <= equal_gini <= 1
assert 0 <= unequal_gini <= 1
class TestModeStatistic:
@pytest.mark.skip(reason="Known issue: mode_py has array conversion problems")
def test_mode_basic(self):
data = np.ascontiguousarray(np.array([1, 2, 2, 2, 3, 3, 4]))
result = scirs2.mode_py(data)
if isinstance(result, dict):
mode_val = result.get('mode', result.get('value', None))
else:
mode_val = result
if mode_val is not None:
assert np.allclose(mode_val, 2.0, rtol=1e-10)
class TestBoxplotStatistics:
def test_boxplot_stats_computable(self):
np.random.seed(42)
data = np.ascontiguousarray(np.random.randn(100))
result = scirs2.boxplot_stats_py(data)
if isinstance(result, dict):
assert 'q1' in result or 'quartile1' in result or 'lower' in result
assert result is not None
class TestEllipticIntegrals:
def test_ellipk_matches_scipy(self):
from scipy.special import ellipk
for m in [0.1, 0.5, 0.9]:
scipy_k = ellipk(m)
scirs2_k = scirs2.ellipk_py(m)
assert np.allclose(scipy_k, scirs2_k, rtol=1e-10)
def test_ellipe_matches_scipy(self):
from scipy.special import ellipe
for m in [0.1, 0.5]:
scipy_e = ellipe(m)
scirs2_e = scirs2.ellipe_py(m)
assert np.allclose(scipy_e, scirs2_e, rtol=1e-3, atol=1e-10)
class TestAdditionalErrorFunctions:
def test_erfinv_properties(self):
for x in [-0.5, 0.0, 0.5, 0.9]:
try:
y = scirs2.erfinv_py(x)
assert np.isfinite(y)
except (ValueError, RuntimeError):
pass
def test_erfcinv_properties(self):
for x in [0.1, 0.5, 1.0, 1.5]:
try:
y = scirs2.erfcinv_py(x)
assert np.isfinite(y)
except (ValueError, RuntimeError):
pass
class TestBesselFunctions:
def test_i0_matches_scipy(self):
from scipy.special import i0
for x in [0.0, 0.5, 1.0, 2.0, 5.0]:
scipy_i0 = i0(x)
scirs2_i0 = scirs2.i0_py(x)
assert np.allclose(scipy_i0, scirs2_i0, rtol=1e-6, atol=1e-10)
def test_i1_matches_scipy(self):
from scipy.special import i1
for x in [0.0, 0.5, 1.0, 2.0, 5.0]:
scipy_i1 = i1(x)
scirs2_i1 = scirs2.i1_py(x)
assert np.allclose(scipy_i1, scirs2_i1, rtol=1e-6, atol=1e-10)
class TestDigamma:
def test_digamma_basic_values(self):
for x in [1.0, 2.0, 5.0, 10.0]:
try:
result = scirs2.digamma_py(x)
assert np.isfinite(result)
if x > 1:
prev = scirs2.digamma_py(x - 1)
assert result > prev
except (ValueError, RuntimeError):
pass
class TestMoreHypothesisTests:
@pytest.mark.skip(reason="Known issue: fisher_exact_py has array conversion problems")
def test_fisher_exact_computable(self):
table = np.ascontiguousarray(np.array([[8, 2], [1, 5]]))
from scipy.stats import fisher_exact
oddsratio_scipy, p_scipy = fisher_exact(table)
result = scirs2.fisher_exact_py(table)
if isinstance(result, dict):
oddsratio_scirs2 = result.get('oddsratio', result.get('odds_ratio', None))
p_scirs2 = result.get('pvalue', None)
else:
oddsratio_scirs2, p_scirs2 = None, None
if oddsratio_scirs2 is not None:
assert np.isfinite(oddsratio_scirs2)
@pytest.mark.skip(reason="friedman_py has different API (single array input)")
def test_friedman_computable(self):
np.random.seed(42)
sample1 = np.ascontiguousarray(np.random.randn(20))
sample2 = np.ascontiguousarray(sample1 + np.random.randn(20) * 0.5)
sample3 = np.ascontiguousarray(sample1 + np.random.randn(20) * 0.5)
from scipy.stats import friedmanchisquare
stat_scipy, p_scipy = friedmanchisquare(sample1, sample2, sample3)
class TestChi2Tests:
def test_chi2_independence_computable(self):
table = np.ascontiguousarray(np.array([[10, 10, 20], [20, 20, 20]]))
result = scirs2.chi2_independence_py(table)
if isinstance(result, dict):
assert 'statistic' in result or 'chi2' in result
else:
assert np.isfinite(result)
class TestDeciles:
def test_deciles_properties(self):
np.random.seed(42)
data = np.ascontiguousarray(np.random.randn(1000))
deciles = scirs2.deciles_py(data)
assert len(deciles) == 9
assert np.all(deciles[:-1] <= deciles[1:])
p10 = scirs2.percentile_py(data, 10)
assert np.allclose(deciles[0], p10, rtol=1e-10)
if __name__ == "__main__":
pytest.main([__file__, "-v"])