Skip to content

Commit afbfe3d

Browse files
committed
Add tests
1 parent 11cabb6 commit afbfe3d

5 files changed

Lines changed: 331 additions & 0 deletions

File tree

tests/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env python
2+
# Created by "Thieu" at 16:09, 03/05/2025 ----------%
3+
# Email: nguyenthieu2102@gmail.com %
4+
# Github: https://github.com/thieu1995 %
5+
# --------------------------------------------------%

tests/test_GdWnnClassifier.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#!/usr/bin/env python
2+
# Created by "Thieu" at 10:29, 25/05/2025 ----------%
3+
# Email: nguyenthieu2102@gmail.com %
4+
# Github: https://github.com/thieu1995 %
5+
# --------------------------------------------------%
6+
7+
import pytest
8+
import numpy as np
9+
from sklearn.datasets import make_classification
10+
from sklearn.model_selection import train_test_split
11+
from waveletml import GdWnnClassifier
12+
13+
14+
@pytest.mark.parametrize("n_classes", [2, 3])
15+
def test_fit_predict_score(n_classes):
16+
# Create synthetic classification dataset
17+
X, y = make_classification(n_samples=200, n_features=5, n_informative=3,
18+
n_classes=n_classes, random_state=42)
19+
20+
# Split into train/test
21+
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
22+
23+
# Initialize classifier
24+
model = GdWnnClassifier(epochs=10, batch_size=16, seed=42, verbose=False)
25+
26+
# Fit model
27+
model.fit(X_train, y_train)
28+
29+
# Predict
30+
y_pred = model.predict(X_test)
31+
assert y_pred.shape == y_test.shape
32+
assert set(np.unique(y_pred)).issubset(set(np.unique(y_train)))
33+
34+
# Predict probabilities
35+
y_proba = model.predict_proba(X_test)
36+
assert y_proba.shape[0] == X_test.shape[0]
37+
if n_classes == 2:
38+
assert y_proba.shape[1] == 1 or len(y_proba.shape) == 1
39+
else:
40+
assert y_proba.shape[1] == n_classes
41+
42+
# Check accuracy score
43+
score = model.score(X_test, y_test)
44+
assert isinstance(score, float)
45+
assert 0.0 <= score <= 1.0
46+
47+
48+
def test_invalid_valid_rate():
49+
X, y = make_classification(n_samples=100, n_features=4, n_classes=2, random_state=42)
50+
model = GdWnnClassifier(valid_rate=1.5)
51+
with pytest.raises(ValueError, match="Validation rate must be between 0 and 1."):
52+
model.fit(X, y)
53+
54+
55+
def test_invalid_device():
56+
with pytest.raises(ValueError, match="GPU is not available"):
57+
GdWnnClassifier(device="gpu") # Force failure if CUDA is not available
58+
59+
60+
def test_metrics_output():
61+
X, y = make_classification(n_samples=100, n_features=4, n_classes=2, random_state=42)
62+
model = GdWnnClassifier(epochs=5, batch_size=16, seed=42, verbose=False)
63+
model.fit(X, y)
64+
scores = model.scores(X, y)
65+
assert isinstance(scores, dict)
66+
assert "AS" in scores or "RS" in scores

tests/test_GdWnnRegressor.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/usr/bin/env python
2+
# Created by "Thieu" at 10:31, 25/05/2025 ----------%
3+
# Email: nguyenthieu2102@gmail.com %
4+
# Github: https://github.com/thieu1995 %
5+
# --------------------------------------------------%
6+
7+
import pytest
8+
import numpy as np
9+
from sklearn.datasets import make_regression
10+
from sklearn.model_selection import train_test_split
11+
from waveletml import GdWnnRegressor
12+
13+
14+
def test_fit_predict_score_regression():
15+
# Generate synthetic regression data
16+
X, y = make_regression(n_samples=150, n_features=6, noise=0.2, random_state=42)
17+
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)
18+
19+
# Initialize regressor
20+
model = GdWnnRegressor(epochs=10, batch_size=16, seed=42, verbose=False)
21+
22+
# Fit model
23+
model.fit(X_train, y_train)
24+
25+
# Predict
26+
y_pred = model.predict(X_test)
27+
assert y_pred.shape == (X_test.shape[0], 1)
28+
29+
# Score
30+
score = model.score(X_test, y_test)
31+
assert isinstance(score, float)
32+
assert -1.0 <= score <= 1.0 # R² score range
33+
34+
# Scores (evaluate)
35+
result = model.scores(X_test, y_test)
36+
assert isinstance(result, dict)
37+
assert "MSE" in result or "MAE" in result
38+
39+
40+
def test_multi_target_regression():
41+
# Generate synthetic multi-output regression data
42+
X = np.random.rand(100, 5)
43+
y = np.random.rand(100, 3)
44+
45+
model = GdWnnRegressor(epochs=5, batch_size=16, seed=0, verbose=False)
46+
model.fit(X, y)
47+
48+
y_pred = model.predict(X)
49+
assert y_pred.shape == y.shape
50+
51+
52+
def test_invalid_valid_rate_regressor():
53+
X, y = make_regression(n_samples=100, n_features=4, noise=0.1, random_state=42)
54+
model = GdWnnRegressor(valid_rate=2.0)
55+
with pytest.raises(ValueError, match="Validation rate must be between 0 and 1."):
56+
model.fit(X, y)
57+
58+
59+
def test_invalid_device_regressor():
60+
with pytest.raises(ValueError, match="GPU is not available"):
61+
GdWnnRegressor(device="gpu") # Force GPU failure if not available

tests/test_MhaWnnClassifier.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#!/usr/bin/env python
2+
# Created by "Thieu" at 10:33, 25/05/2025 ----------%
3+
# Email: nguyenthieu2102@gmail.com %
4+
# Github: https://github.com/thieu1995 %
5+
# --------------------------------------------------%
6+
7+
import pytest
8+
import numpy as np
9+
from sklearn.datasets import make_classification
10+
from waveletml import MhaWnnClassifier
11+
12+
13+
def test_binary_classification_fit_predict_score():
14+
X, y = make_classification(n_samples=120, n_features=6, n_classes=2, random_state=42)
15+
16+
model = MhaWnnClassifier(
17+
size_hidden=5,
18+
optim="BaseGA", # Use Genetic Algorithm for diversity
19+
optim_params={"epoch": 20, "pop_size": 20},
20+
obj_name="AS", # Accuracy Score
21+
seed=42,
22+
verbose=False
23+
)
24+
25+
model.fit(X, y)
26+
y_pred = model.predict(X)
27+
assert y_pred.shape == (X.shape[0],)
28+
assert np.all(np.isin(y_pred, [0, 1]))
29+
30+
score = model.score(X, y)
31+
assert isinstance(score, float)
32+
assert 0 <= score <= 1
33+
34+
35+
def test_multiclass_classification_fit_predict():
36+
X, y = make_classification(n_samples=100, n_features=5, n_classes=3, n_informative=3, n_redundant=0,
37+
random_state=42)
38+
39+
model = MhaWnnClassifier(
40+
size_hidden=6,
41+
optim="OriginalPSO", # Particle Swarm Optimization
42+
optim_params={"epoch": 20, "pop_size": 20},
43+
obj_name="AS",
44+
seed=1,
45+
verbose=False
46+
)
47+
48+
model.fit(X, y)
49+
y_pred = model.predict(X)
50+
assert y_pred.shape == (X.shape[0],)
51+
assert set(np.unique(y_pred)).issubset(set(np.unique(y)))
52+
53+
54+
def test_predict_proba_output_shape():
55+
X, y = make_classification(n_samples=80, n_features=4, n_classes=2, random_state=0)
56+
57+
model = MhaWnnClassifier(
58+
optim="OriginalDE",
59+
optim_params={"epoch": 20, "pop_size": 20},
60+
obj_name="AS",
61+
verbose=False
62+
)
63+
64+
model.fit(X, y)
65+
probs = model.predict_proba(X)
66+
assert isinstance(probs, np.ndarray)
67+
assert probs.shape == (X.shape[0], 1) or probs.shape[1] > 1
68+
69+
70+
def test_invalid_obj_name_raises_error():
71+
X, y = make_classification(
72+
n_samples=60,
73+
n_features=3,
74+
n_informative=2,
75+
n_redundant=0,
76+
n_repeated=0,
77+
n_classes=2,
78+
random_state=0
79+
)
80+
81+
model = MhaWnnClassifier(
82+
optim="BaseGA",
83+
optim_params={"epoch": 20, "pop_size": 20},
84+
obj_name="INVALID_METRIC",
85+
verbose=False
86+
)
87+
88+
with pytest.raises(ValueError,
89+
match="obj_name is not supported. Please check the library: permetrics to see the supported objective function."):
90+
model.fit(X, y)
91+
92+
93+
def test_predict_proba_invalid_task():
94+
X, y = make_classification(
95+
n_samples=60,
96+
n_features=3,
97+
n_informative=2,
98+
n_redundant=0,
99+
n_repeated=0,
100+
n_classes=2,
101+
random_state=0
102+
)
103+
104+
model = MhaWnnClassifier(
105+
optim="BaseGA",
106+
optim_params={"epoch": 25, "pop_size": 20},
107+
obj_name="AS",
108+
verbose=False
109+
)
110+
111+
model.fit(X, y)
112+
model.task = "regression" # Force task to be incorrect
113+
with pytest.raises(ValueError, match="predict_proba is only available for classification tasks."):
114+
model.predict_proba(X)

tests/test_MhaWnnRegressor.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#!/usr/bin/env python
2+
# Created by "Thieu" at 10:35, 25/05/2025 ----------%
3+
# Email: nguyenthieu2102@gmail.com %
4+
# Github: https://github.com/thieu1995 %
5+
# --------------------------------------------------%
6+
7+
import pytest
8+
import numpy as np
9+
from sklearn.datasets import make_regression
10+
from waveletml import MhaWnnRegressor
11+
12+
13+
def test_single_output_regression_fit_predict_score():
14+
X, y = make_regression(n_samples=100, n_features=5, noise=0.1, random_state=42)
15+
16+
model = MhaWnnRegressor(
17+
size_hidden=6,
18+
optim="BaseGA",
19+
optim_params={"epoch": 25, "pop_size": 20},
20+
obj_name="R2", # R2 Score
21+
seed=42,
22+
verbose=False
23+
)
24+
25+
model.fit(X, y)
26+
y_pred = model.predict(X)
27+
assert y_pred.shape == (X.shape[0], 1) or y_pred.shape == (X.shape[0],)
28+
assert isinstance(y_pred, np.ndarray)
29+
30+
score = model.score(X, y)
31+
assert isinstance(score, float)
32+
assert -1 <= score <= 1
33+
34+
35+
def test_multi_output_regression_fit_predict():
36+
X, y = make_regression(n_samples=80, n_features=4, n_targets=3, noise=0.2, random_state=0)
37+
38+
model = MhaWnnRegressor(
39+
size_hidden=4,
40+
optim="OriginalPSO",
41+
optim_params={"epoch": 25, "pop_size": 20},
42+
obj_name="RMSE", # Root Mean Squared Error
43+
verbose=False
44+
)
45+
46+
model.fit(X, y)
47+
y_pred = model.predict(X)
48+
assert y_pred.shape == y.shape
49+
assert isinstance(y_pred, np.ndarray)
50+
51+
52+
def test_invalid_obj_name_raises_error():
53+
X, y = make_regression(n_samples=60, n_features=3, noise=0.3, random_state=0)
54+
55+
model = MhaWnnRegressor(
56+
size_hidden=5,
57+
optim="OriginalDE",
58+
optim_params={"epoch": 25, "pop_size": 20},
59+
obj_name="INVALID_METRIC",
60+
verbose=False
61+
)
62+
63+
with pytest.raises(ValueError, match="obj_name is not supported. Please check the library: permetrics to see the supported objective function."):
64+
model.fit(X, y)
65+
66+
67+
def test_score_consistency_with_r2_score():
68+
from sklearn.metrics import r2_score
69+
70+
X, y = make_regression(n_samples=50, n_features=3, noise=0.5, random_state=1)
71+
72+
model = MhaWnnRegressor(
73+
size_hidden=5,
74+
optim="BaseGA",
75+
optim_params={"epoch": 25, "pop_size": 20},
76+
obj_name="R2",
77+
seed=1,
78+
verbose=False
79+
)
80+
81+
model.fit(X, y)
82+
y_pred = model.predict(X)
83+
score1 = model.score(X, y)
84+
score2 = r2_score(y, y_pred)
85+
np.testing.assert_almost_equal(score1, score2, decimal=4)

0 commit comments

Comments
 (0)