import numpy as np
import pytest
import scirs2
class TestEntropy:
def test_entropy_uniform_distribution(self):
data = np.array([1, 1, 1, 2, 2, 2, 3, 3, 3], dtype=np.int64)
result = scirs2.entropy_py(data)
assert result > 0.0
def test_entropy_deterministic(self):
data = np.array([1, 1, 1, 1, 1], dtype=np.int64)
result = scirs2.entropy_py(data)
assert abs(result - 0.0) < 0.001
def test_entropy_binary(self):
data = np.array([0, 0, 0, 0, 1, 1, 1, 1], dtype=np.int64)
result_nat = scirs2.entropy_py(data) result_bits = scirs2.entropy_py(data, base=2.0)
assert abs(result_bits - 1.0) < 0.01
def test_entropy_base_parameter(self):
data = np.array([1, 1, 2, 2, 3, 3], dtype=np.int64)
entropy_e = scirs2.entropy_py(data) entropy_2 = scirs2.entropy_py(data, base=2.0) entropy_10 = scirs2.entropy_py(data, base=10.0)
assert entropy_e > 0.0
assert entropy_2 > 0.0
assert entropy_10 > 0.0
assert abs(entropy_e - entropy_2 * np.log(2)) < 0.01
def test_entropy_skewed_distribution(self):
data = np.array([1, 1, 1, 1, 1, 1, 2, 3], dtype=np.int64)
result = scirs2.entropy_py(data)
assert result > 0.0
assert result < 1.5
class TestKLDivergence:
def test_kl_divergence_identical_distributions(self):
p = np.array([0.3, 0.3, 0.4])
q = np.array([0.3, 0.3, 0.4])
result = scirs2.kl_divergence_py(p, q)
assert abs(result - 0.0) < 0.0001
def test_kl_divergence_different_distributions(self):
p = np.array([0.4, 0.3, 0.3])
q = np.array([0.33, 0.33, 0.34])
result = scirs2.kl_divergence_py(p, q)
assert result > 0.0
def test_kl_divergence_asymmetric(self):
p = np.array([0.8, 0.15, 0.05])
q = np.array([0.3, 0.5, 0.2])
kl_pq = scirs2.kl_divergence_py(p, q)
kl_qp = scirs2.kl_divergence_py(q, p)
assert abs(kl_pq - kl_qp) > 0.01
def test_kl_divergence_uniform_vs_peaked(self):
uniform = np.array([0.25, 0.25, 0.25, 0.25])
peaked = np.array([0.7, 0.1, 0.1, 0.1])
result = scirs2.kl_divergence_py(peaked, uniform)
assert result > 0.1
def test_kl_divergence_normalized_distributions(self):
p = np.array([0.5, 0.3, 0.2])
q = np.array([0.4, 0.4, 0.2])
assert abs(np.sum(p) - 1.0) < 0.0001
assert abs(np.sum(q) - 1.0) < 0.0001
result = scirs2.kl_divergence_py(p, q)
assert result >= 0.0
class TestCrossEntropy:
def test_cross_entropy_identical_distributions(self):
p = np.array([0.3, 0.3, 0.4])
q = np.array([0.3, 0.3, 0.4])
result = scirs2.cross_entropy_py(p, q)
assert result > 0.0
def test_cross_entropy_different_distributions(self):
p = np.array([0.5, 0.3, 0.2])
q = np.array([0.4, 0.4, 0.2])
result = scirs2.cross_entropy_py(p, q)
assert result > 0.0
def test_cross_entropy_vs_kl_divergence(self):
p = np.array([0.4, 0.3, 0.3])
q = np.array([0.33, 0.33, 0.34])
cross_ent = scirs2.cross_entropy_py(p, q)
kl_div = scirs2.kl_divergence_py(p, q)
assert cross_ent >= 0.0
def test_cross_entropy_asymmetric(self):
p = np.array([0.8, 0.15, 0.05])
q = np.array([0.3, 0.5, 0.2])
ce_pq = scirs2.cross_entropy_py(p, q)
ce_qp = scirs2.cross_entropy_py(q, p)
assert abs(ce_pq - ce_qp) > 0.01
def test_cross_entropy_minimum_at_identity(self):
p = np.array([0.5, 0.3, 0.2])
q1 = p.copy() q2 = np.array([0.4, 0.4, 0.2]) q3 = np.array([0.33, 0.33, 0.34])
ce1 = scirs2.cross_entropy_py(p, q1)
ce2 = scirs2.cross_entropy_py(p, q2)
ce3 = scirs2.cross_entropy_py(p, q3)
assert ce1 <= ce2
assert ce1 <= ce3
class TestWeightedMean:
def test_weighted_mean_equal_weights(self):
data = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
weights = np.array([1.0, 1.0, 1.0, 1.0, 1.0])
weighted = scirs2.weighted_mean_py(data, weights)
regular = np.mean(data)
assert abs(weighted - regular) < 0.001
def test_weighted_mean_emphasis(self):
data = np.array([10.0, 15.0, 20.0, 25.0, 80.0])
weights = np.array([1.0, 1.0, 5.0, 1.0, 1.0])
weighted = scirs2.weighted_mean_py(data, weights)
regular = np.mean(data)
assert abs(weighted - 20.0) < abs(regular - 20.0)
def test_weighted_mean_zero_weight(self):
data = np.array([10.0, 20.0, 30.0, 40.0, 50.0])
weights = np.array([1.0, 1.0, 0.0, 0.0, 0.0])
weighted = scirs2.weighted_mean_py(data, weights)
assert abs(weighted - 15.0) < 0.001
def test_weighted_mean_different_scales(self):
data = np.array([10.0, 20.0, 30.0])
weights1 = np.array([1.0, 2.0, 3.0])
weights2 = np.array([2.0, 4.0, 6.0])
weighted1 = scirs2.weighted_mean_py(data, weights1)
weighted2 = scirs2.weighted_mean_py(data, weights2)
assert abs(weighted1 - weighted2) < 0.001
def test_weighted_mean_single_value(self):
data = np.array([42.0])
weights = np.array([1.0])
weighted = scirs2.weighted_mean_py(data, weights)
assert abs(weighted - 42.0) < 0.001
class TestMoment:
def test_moment_first_centered(self):
data = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
result = scirs2.moment_py(data, order=1, center=True)
assert abs(result - 0.0) < 0.0001
def test_moment_second_centered_is_variance(self):
data = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
moment2 = scirs2.moment_py(data, order=2, center=True)
variance = np.var(data, ddof=0)
assert abs(moment2 - variance) < 0.001
def test_moment_first_uncentered_is_mean(self):
data = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
moment1 = scirs2.moment_py(data, order=1, center=False)
mean = np.mean(data)
assert abs(moment1 - mean) < 0.001
def test_moment_third_centered(self):
data_symmetric = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
moment3_sym = scirs2.moment_py(data_symmetric, order=3, center=True)
assert abs(moment3_sym) < 0.01
data_skewed = np.array([1.0, 1.0, 1.0, 2.0, 10.0])
moment3_skew = scirs2.moment_py(data_skewed, order=3, center=True)
assert abs(moment3_skew) > 0.1
def test_moment_fourth_centered(self):
data = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
moment4 = scirs2.moment_py(data, order=4, center=True)
assert moment4 > 0.0
def test_moment_higher_order(self):
data = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
moment5 = scirs2.moment_py(data, order=5, center=True)
moment6 = scirs2.moment_py(data, order=6, center=True)
assert abs(moment5) < 0.1
assert moment6 > 0.0
class TestInformationTheoryRealWorld:
def test_machine_learning_cross_entropy_loss(self):
true_label = np.array([0.0, 1.0, 0.0])
pred_poor = np.array([0.6, 0.2, 0.2])
pred_good = np.array([0.1, 0.8, 0.1])
loss_poor = scirs2.cross_entropy_py(true_label, pred_poor)
loss_good = scirs2.cross_entropy_py(true_label, pred_good)
assert loss_good < loss_poor
def test_information_gain_simulation(self):
before = np.array([1, 1, 1, 2, 2, 2], dtype=np.int64)
subset1 = np.array([1, 1, 1], dtype=np.int64)
subset2 = np.array([2, 2, 2], dtype=np.int64)
entropy_before = scirs2.entropy_py(before, base=2.0)
entropy_subset1 = scirs2.entropy_py(subset1, base=2.0)
entropy_subset2 = scirs2.entropy_py(subset2, base=2.0)
assert abs(entropy_subset1) < 0.01
assert abs(entropy_subset2) < 0.01
assert entropy_before > 0.5
def test_weighted_average_grading(self):
scores = np.array([85.0, 92.0, 78.0, 88.0])
weights_scenario1 = np.array([0.1, 0.1, 0.3, 0.5])
weighted_grade = scirs2.weighted_mean_py(scores, weights_scenario1)
assert 85.0 < weighted_grade < 90.0
def test_portfolio_weighted_return(self):
returns = np.array([5.0, 10.0, -2.0, 8.0])
weights = np.array([0.4, 0.3, 0.1, 0.2])
portfolio_return = scirs2.weighted_mean_py(returns, weights)
assert -2.0 <= portfolio_return <= 10.0
class TestInformationTheoryEdgeCases:
def test_entropy_large_dataset(self):
np.random.seed(42)
data = np.random.randint(0, 10, size=1000, dtype=np.int64)
result = scirs2.entropy_py(data, base=2.0)
assert result > 0.0
assert result < 10.0
def test_kl_divergence_small_values(self):
p = np.array([0.98, 0.01, 0.01])
q = np.array([0.01, 0.98, 0.01])
result = scirs2.kl_divergence_py(p, q)
assert result > 1.0
def test_weighted_mean_many_values(self):
np.random.seed(42)
data = np.random.randn(1000) * 10 + 50
weights = np.random.rand(1000)
result = scirs2.weighted_mean_py(data, weights)
assert 30.0 < result < 70.0
def test_moment_zero_variance(self):
data = np.array([5.0, 5.0, 5.0, 5.0])
moment2 = scirs2.moment_py(data, order=2, center=True)
moment3 = scirs2.moment_py(data, order=3, center=True)
assert abs(moment2) < 0.0001
assert abs(moment3) < 0.0001
if __name__ == "__main__":
pytest.main([__file__, "-v"])