Initial commit: OptimizR - High-performance optimization algorithms in Rust with Python bindings
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
"""
|
||||
Test suite for OptimizR
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import numpy as np
|
||||
from optimizr import (
|
||||
HMM,
|
||||
mcmc_sample,
|
||||
differential_evolution,
|
||||
grid_search,
|
||||
mutual_information,
|
||||
shannon_entropy,
|
||||
)
|
||||
|
||||
|
||||
class TestHMM:
|
||||
"""Test Hidden Markov Model"""
|
||||
|
||||
def test_hmm_initialization(self):
|
||||
hmm = HMM(n_states=3)
|
||||
assert hmm.n_states == 3
|
||||
# After initialization, matrices are zeros (not None)
|
||||
assert hmm.transition_matrix_ is not None
|
||||
assert hmm.transition_matrix_.shape == (3, 3)
|
||||
|
||||
def test_hmm_fit(self):
|
||||
np.random.seed(42)
|
||||
returns = np.random.randn(1000)
|
||||
|
||||
hmm = HMM(n_states=2)
|
||||
hmm.fit(returns, n_iterations=10)
|
||||
|
||||
assert hmm.transition_matrix_ is not None
|
||||
assert hmm.transition_matrix_.shape == (2, 2)
|
||||
assert hmm.emission_means_ is not None
|
||||
assert len(hmm.emission_means_) == 2
|
||||
|
||||
def test_hmm_predict(self):
|
||||
np.random.seed(42)
|
||||
returns = np.random.randn(100)
|
||||
|
||||
hmm = HMM(n_states=2)
|
||||
hmm.fit(returns, n_iterations=10)
|
||||
states = hmm.predict(returns)
|
||||
|
||||
assert len(states) == len(returns)
|
||||
assert set(states).issubset({0, 1})
|
||||
|
||||
|
||||
class TestMCMC:
|
||||
"""Test MCMC Sampling"""
|
||||
|
||||
def test_mcmc_basic(self):
|
||||
def log_likelihood(params, data):
|
||||
mu, sigma = params
|
||||
if sigma <= 0:
|
||||
return float('-inf')
|
||||
residuals = (np.array(data) - mu) / sigma
|
||||
return -0.5 * np.sum(residuals**2) - len(data) * np.log(sigma)
|
||||
|
||||
np.random.seed(42)
|
||||
data = np.random.randn(50) + 2.0
|
||||
|
||||
samples = mcmc_sample(
|
||||
log_likelihood_fn=log_likelihood,
|
||||
data=data,
|
||||
initial_params=np.array([0.0, 1.0]),
|
||||
param_bounds=[(-10, 10), (0.1, 10)],
|
||||
n_samples=100,
|
||||
burn_in=10,
|
||||
proposal_std=0.1
|
||||
)
|
||||
|
||||
assert samples.shape == (100, 2)
|
||||
assert np.all(samples[:, 1] > 0) # Sigma should be positive
|
||||
|
||||
|
||||
class TestDifferentialEvolution:
|
||||
"""Test Differential Evolution"""
|
||||
|
||||
def test_de_sphere(self):
|
||||
"""Test on simple sphere function"""
|
||||
def sphere(x):
|
||||
return np.sum(np.array(x)**2)
|
||||
|
||||
x, fun = differential_evolution(
|
||||
objective_fn=sphere,
|
||||
bounds=[(-5, 5)] * 3,
|
||||
popsize=10,
|
||||
maxiter=50
|
||||
)
|
||||
|
||||
assert len(x) == 3
|
||||
assert fun < 1.0 # Should find near-zero minimum
|
||||
|
||||
def test_de_rosenbrock(self):
|
||||
"""Test on Rosenbrock function"""
|
||||
def rosenbrock(x):
|
||||
x = np.array(x)
|
||||
return np.sum(100.0 * (x[1:] - x[:-1]**2)**2 + (1 - x[:-1])**2)
|
||||
|
||||
x, fun = differential_evolution(
|
||||
objective_fn=rosenbrock,
|
||||
bounds=[(-2, 2)] * 5,
|
||||
popsize=15,
|
||||
maxiter=100
|
||||
)
|
||||
|
||||
assert len(x) == 5
|
||||
assert fun < 10.0 # Should find reasonably good minimum
|
||||
|
||||
|
||||
class TestGridSearch:
|
||||
"""Test Grid Search"""
|
||||
|
||||
def test_grid_search_2d(self):
|
||||
"""Test on 2D quadratic"""
|
||||
def objective(x):
|
||||
return -(x[0]**2 + x[1]**2) # Peak at (0, 0)
|
||||
|
||||
x, fun = grid_search(
|
||||
objective_fn=objective,
|
||||
bounds=[(-5, 5), (-5, 5)],
|
||||
n_points=20
|
||||
)
|
||||
|
||||
assert len(x) == 2
|
||||
assert np.allclose(x, [0, 0], atol=0.5) # Should find near (0, 0)
|
||||
assert fun > -1.0 # Should find near-zero maximum
|
||||
|
||||
|
||||
class TestInformationTheory:
|
||||
"""Test Information Theory Metrics"""
|
||||
|
||||
def test_shannon_entropy_uniform(self):
|
||||
"""Uniform distribution should have high entropy"""
|
||||
np.random.seed(42)
|
||||
x = np.random.uniform(0, 1, 10000)
|
||||
entropy = shannon_entropy(x, n_bins=10)
|
||||
|
||||
assert entropy > 2.0 # ln(10) ≈ 2.3
|
||||
|
||||
def test_shannon_entropy_constant(self):
|
||||
"""Constant should have zero entropy"""
|
||||
x = np.ones(1000)
|
||||
entropy = shannon_entropy(x, n_bins=10)
|
||||
|
||||
assert entropy < 0.01
|
||||
|
||||
def test_mutual_information_independent(self):
|
||||
"""Independent variables should have low MI"""
|
||||
np.random.seed(42)
|
||||
x = np.random.randn(10000)
|
||||
y = np.random.randn(10000)
|
||||
mi = mutual_information(x, y, n_bins=10)
|
||||
|
||||
assert mi >= 0.0
|
||||
assert mi < 0.5 # Should be close to zero
|
||||
|
||||
def test_mutual_information_dependent(self):
|
||||
"""Dependent variables should have high MI"""
|
||||
np.random.seed(42)
|
||||
x = np.random.randn(10000)
|
||||
y = 2 * x + np.random.randn(10000) * 0.1
|
||||
mi = mutual_information(x, y, n_bins=20)
|
||||
|
||||
assert mi > 1.0 # Strong dependence
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__, "-v"])
|
||||
Reference in New Issue
Block a user