Skip to content

Commit

Permalink
lint: fix NPY002 in tests/*
Browse files Browse the repository at this point in the history
This commit updates the tests code so to make them to use np.random.default_rng with a certain seed, rather than relying on global random seed handling, i.e. using np.random.seed.

To do so, a new fixture, 'rng', has been added so to avoid the tests code to initialize a np.random.Generator instance manually.
  • Loading branch information
marcofavorito authored and marcofavoritobi committed Sep 1, 2023
1 parent 743d153 commit 6dab2b3
Show file tree
Hide file tree
Showing 14 changed files with 252 additions and 130 deletions.
9 changes: 9 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
import inspect
from pathlib import Path

import numpy as np
import pytest

CUR_PATH = Path(inspect.getfile(inspect.currentframe())).parent # type: ignore[arg-type]
ROOT_DIR = Path(CUR_PATH, "..").resolve().absolute()
DOCS_DIR = ROOT_DIR / "docs"
Expand All @@ -27,3 +30,9 @@
EXAMPLE_SAVING_FOLDER = ROOT_DIR / "examples" / "saving_folder"

DEFAULT_SUBPROCESS_TIMEOUT = 100.0


@pytest.fixture()
def rng() -> np.random.Generator:
"""Return random number generator."""
return np.random.default_rng(seed=11)
8 changes: 4 additions & 4 deletions tests/fixtures/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ def normal_mv(theta: NDArray, N: int, seed: int) -> NDArray: # noqa: N803
Returns:
the sampled series
"""
np.random.seed(seed=seed)
rng = np.random.default_rng(seed=seed)

y = np.random.normal(theta[0], theta[1], N)
y = rng.normal(theta[0], theta[1], N)
return np.atleast_2d(y).T


Expand All @@ -63,7 +63,7 @@ def bh4(theta: NDArray, N: int, seed: int) -> NDArray: # noqa: N803
Returns:
simulated series
"""
np.random.seed(seed=seed)
rng = np.random.default_rng(seed=seed)

R = 1.01 # noqa: N806
beta = 120
Expand All @@ -88,7 +88,7 @@ def bh4(theta: NDArray, N: int, seed: int) -> NDArray: # noqa: N803
for t in range(2, N + 1):
expectation = np.add(g * x[t - 1], b)
weighted_exp = np.multiply(n, expectation)
dividend_noise = np.random.normal(0, sigma, 1)
dividend_noise = rng.normal(0, sigma, 1)
x[t] = (np.sum(weighted_exp) + dividend_noise) / R

left_factor = x[t] - R * x[t - 1]
Expand Down
58 changes: 30 additions & 28 deletions tests/test_calibrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,38 +46,40 @@ class TestCalibrate:

expected_params = np.array(
[
[0.59, 0.36],
[0.63, 0.41],
[0.18, 0.39],
[0.56, 0.37],
[0.83, 0.35],
[0.54, 0.32],
[0.74, 0.32],
[0.53, 0.46],
[0.57, 0.39],
[0.94, 0.42],
[0.32, 0.93],
[0.8, 0.06],
[0.01, 0.02],
[0.04, 0.99],
[
[0.52, 0.01],
[0.56, 0.37],
[0.59, 0.36],
[0.55, 0.46],
[0.53, 0.46],
[0.8, 0.06],
[1.0, 0.01],
[0.74, 0.32],
[0.60, 0.42],
[0.18, 0.39],
[0.51, 0.33],
[0.04, 0.99],
[0.32, 0.93],
[0.56, 0.24],
],
],
)

expected_losses = [
0.33400294,
0.55274918,
0.55798021,
0.61712034,
0.91962075,
1.31118518,
1.51682355,
1.55503666,
1.65968375,
1.78845827,
1.79905545,
2.07605975,
2.28484134,
3.01432484,
0.8795007015523011,
0.9922451648013014,
1.1559062441690586,
1.243804840789122,
1.763306220343992,
1.8816532512692634,
2.1458913789840075,
2.5567620672044096,
2.864828018578677,
2.880577936629117,
2.9058561113219326,
3.777058720373308,
4.474663277994701,
5.796152952731929,
]

win32_expected_params = np.array(
Expand Down
14 changes: 6 additions & 8 deletions tests/test_losses/test_fourier.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,32 +23,30 @@
)


def test_fourier_ideal_low_pass() -> None:
def test_fourier_ideal_low_pass(rng: np.random.Generator) -> None:
"""Test the Fourier loss with the ideal low-pass filter."""
np.random.seed(11)
series_real = np.sin(np.linspace(0, 50, 1000))[:, None]
series_sim = series_real + np.random.normal(0, 0.1, series_real.shape)
series_sim = series_real + rng.normal(0, 0.1, series_real.shape)
euclidean_loss = np.sqrt(np.sum((series_sim - series_real) ** 2))

# check that for no filter (f=1.0) this loss is approximately equivalent to
# the Euclidean loss and that with increasingly aggressive filters (up to
# f=0.01) the loss goes towards zero.
expected_losses = [euclidean_loss, 2.23, 0.97, 0.27]
expected_losses = [euclidean_loss, 2.21, 0.97, 0.187]
for i, f in enumerate([1.0, 0.5, 0.1, 0.01]):
loss_func = FourierLoss(f=f, frequency_filter=ideal_low_pass_filter)
loss = loss_func.compute_loss(series_sim[None, :, :], series_real)
assert np.isclose(expected_losses[i], loss, atol=0.01)


def test_fourier_gaussian_low_pass() -> None:
def test_fourier_gaussian_low_pass(rng: np.random.Generator) -> None:
"""Test the Fourier loss with the gaussian low-pass filter."""
np.random.seed(11)
series_real = np.sin(np.linspace(0, 50, 1000))[:, None]
series_sim = series_real + np.random.normal(0, 0.1, series_real.shape)
series_sim = series_real + rng.normal(0, 0.1, series_real.shape)

# check that with increasingly aggressive filters (up to f=0.01) the loss
# goes towards zero.
expected_losses = [2.75, 0.95, 0.27]
expected_losses = [2.73, 0.95, 0.19]
for i, f in enumerate([1.0, 0.1, 0.01]):
loss_func = FourierLoss(f=f, frequency_filter=gaussian_low_pass_filter)
loss = loss_func.compute_loss(series_sim[None, :, :], series_real)
Expand Down
27 changes: 12 additions & 15 deletions tests/test_losses/test_gsl.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,41 +92,38 @@ def test_get_words(self, args: tuple) -> None:
GslDivLoss.get_words(*args)


def test_gsl_default() -> None:
def test_gsl_default(rng: np.random.Generator) -> None:
"""Test the Gsl-div loss function."""
expected_loss = 0.39737637181336855
expected_loss = 0.3972285978726733

np.random.seed(11)
series_sim = np.random.normal(0, 1, (100, 3))
series_real = np.random.normal(0, 1, (100, 3))
series_sim = rng.normal(0, 1, (100, 3))
series_real = rng.normal(0, 1, (100, 3))

loss_func = GslDivLoss()
loss = loss_func.compute_loss(series_sim[None, :, :], series_real)

assert np.isclose(expected_loss, loss)


def test_gsl_with_nb_values() -> None:
def test_gsl_with_nb_values(rng: np.random.Generator) -> None:
"""Test the Gsl-div loss function with nb_values set."""
expected_loss = 0.4353415724764564
expected_loss = 0.4354049587629579

np.random.seed(11)
series_sim = np.random.normal(0, 1, (2, 100, 3))
series_real = np.random.normal(0, 1, (100, 3))
series_sim = rng.normal(0, 1, (2, 100, 3))
series_real = rng.normal(0, 1, (100, 3))

loss_func = GslDivLoss(nb_values=10)
loss = loss_func.compute_loss(series_sim, series_real)

assert np.isclose(expected_loss, loss)


def test_gsl_with_nb_word_lengths() -> None:
def test_gsl_with_nb_word_lengths(rng: np.random.Generator) -> None:
"""Test the Gsl-div loss function with nb_word_lengths set."""
expected_loss = 0.7210261201578492
expected_loss = 0.7177347914787273

np.random.seed(11)
series_sim = np.random.normal(0, 1, (100, 3))
series_real = np.random.normal(0, 1, (100, 3))
series_sim = rng.normal(0, 1, (100, 3))
series_real = rng.normal(0, 1, (100, 3))

loss_func = GslDivLoss(nb_word_lengths=10)
loss = loss_func.compute_loss(series_sim[None, :, :], series_real)
Expand Down
21 changes: 9 additions & 12 deletions tests/test_losses/test_likelihood.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,49 +19,46 @@
from black_it.loss_functions.likelihood import LikelihoodLoss


def test_likelihood_1d() -> None:
def test_likelihood_1d(rng: np.random.Generator) -> None:
"""Test the computation of the Likelihood in the Likelihood loss in 1d."""
# sample from a Gaussian distribution.
np.random.seed(11)
real_data = np.random.normal(0, 1, size=(7, 1))
real_data = rng.normal(0, 1, size=(7, 1))

expected_neg_log_likelihood = -np.sum(
-0.5 * np.sum(real_data**2, axis=1) - 0.5 * np.log(2.0 * np.pi),
axis=0,
)
expected_likelihood = np.exp(-expected_neg_log_likelihood)

sim_data_ensemble = np.random.normal(0, 1, size=(3, 100000, 1))
sim_data_ensemble = rng.normal(0, 1, size=(3, 100000, 1))
loss = LikelihoodLoss(h="silverman")
neg_log_lik = loss.compute_loss(sim_data_ensemble, real_data)
lik = np.exp(-neg_log_lik)
assert np.isclose(lik, expected_likelihood, rtol=0.1)


def test_likelihood_2d() -> None:
def test_likelihood_2d(rng: np.random.Generator) -> None:
"""Test the computation of the Likelihood in the Likelihood loss in 2d."""
# sample from a Gaussian distribution.
np.random.seed(11)
real_data = np.random.normal(0, 1, size=(10, 2))
real_data = rng.normal(0, 1, size=(10, 2))

expected_neg_log_likelihood = -np.sum(
-0.5 * np.sum(real_data**2, axis=1) - 2.0 / 2.0 * np.log(2.0 * np.pi),
axis=0,
)
expected_likelihood = np.exp(-expected_neg_log_likelihood)
sim_data_ensemble = np.random.normal(0, 1, size=(1, 1000000, 2))
sim_data_ensemble = rng.normal(0, 1, size=(1, 1000000, 2))
loss = LikelihoodLoss(h=1.0)
neg_log_lik = loss.compute_loss(sim_data_ensemble, real_data)
lik = np.exp(-neg_log_lik)
assert np.isclose(lik, expected_likelihood, rtol=0.1)


def test_likelihood_2d_wsigma() -> None:
def test_likelihood_2d_wsigma(rng: np.random.Generator) -> None:
"""Test the computation of the Likelihood in the Likelihood loss in 2d."""
# sample from a Gaussian distribution.
np.random.seed(11)
sigma, d = 3.0, 2
real_data = np.random.normal(0, sigma, size=(10, d))
real_data = rng.normal(0, sigma, size=(10, d))

expected_neg_log_likelihood = -np.sum(
-0.5 / sigma**2 * np.sum(real_data**2, axis=1)
Expand All @@ -70,7 +67,7 @@ def test_likelihood_2d_wsigma() -> None:
)
expected_likelihood = np.exp(-expected_neg_log_likelihood)

sim_data_ensemble = np.random.normal(0, sigma, size=(1, 1000000, d))
sim_data_ensemble = rng.normal(0, sigma, size=(1, 1000000, d))
loss = LikelihoodLoss(h=sigma)
neg_log_lik = loss.compute_loss(sim_data_ensemble, real_data)
lik = np.exp(-neg_log_lik)
Expand Down
40 changes: 23 additions & 17 deletions tests/test_losses/test_msm.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,13 @@
from black_it.loss_functions.msm import MethodOfMomentsLoss


def test_msm_default() -> None:
def test_msm_default(rng: np.random.Generator) -> None:
"""Test the 'method of moments' loss."""
expected_loss = 2.830647081075395
expected_loss = 2.054721024744742

np.random.seed(11)
# ensemble size 2, time series length 100, number of variables 3
series_sim = np.random.normal(0, 1, (2, 100, 3))
series_real = np.random.normal(0, 1, (100, 3))
series_sim = rng.normal(0, 1, (2, 100, 3))
series_real = rng.normal(0, 1, (100, 3))

loss_func = MethodOfMomentsLoss()

Expand All @@ -39,15 +38,16 @@ def test_msm_default() -> None:
assert np.isclose(expected_loss, loss)


def test_msm_default_calculator_custom_covariance_matrix() -> None:
def test_msm_default_calculator_custom_covariance_matrix(
rng: np.random.Generator,
) -> None:
"""Test the MSM loss when the covariance matrix is not None."""
expected_loss = 16.49853079135471
expected_loss = 7.569748247731355

np.random.seed(11)
series_sim = np.random.normal(0, 1, (2, 100, 3))
series_real = np.random.normal(0, 1, (100, 3))
series_sim = rng.normal(0, 1, (2, 100, 3))
series_real = rng.normal(0, 1, (100, 3))

random_mat = np.random.rand(18, 18)
random_mat = rng.random(size=(18, 18))
covariance_matrix = random_mat.T.dot(random_mat)

loss_func = MethodOfMomentsLoss(covariance_mat=covariance_matrix)
Expand All @@ -57,19 +57,23 @@ def test_msm_default_calculator_custom_covariance_matrix() -> None:
assert np.isclose(expected_loss, loss)


def test_msm_default_calculator_non_symmetric_covariance_matrix() -> None:
def test_msm_default_calculator_non_symmetric_covariance_matrix(
rng: np.random.Generator,
) -> None:
"""Test the MSM loss raises error when the provided matrix is not symmetric."""
with pytest.raises(
ValueError,
match="the provided covariance matrix is not valid as it is not a symmetric matrix",
):
MethodOfMomentsLoss(covariance_mat=np.random.rand(2, 3))
MethodOfMomentsLoss(covariance_mat=rng.random(size=(2, 3)))


def test_msm_default_calculator_wrong_shape_covariance_matrix() -> None:
def test_msm_default_calculator_wrong_shape_covariance_matrix(
rng: np.random.Generator,
) -> None:
"""Test the MSM loss raises error when the covariance matrix has wrong shape."""
dimension = 20
random_mat = np.random.rand(dimension, dimension)
random_mat = rng.random(size=(dimension, dimension))
wrong_covariance_matrix = random_mat.T.dot(random_mat)
with pytest.raises(
ValueError,
Expand All @@ -93,7 +97,9 @@ def custom_moment_calculator(time_series: NDArray) -> NDArray:
assert np.isclose(expected_loss, loss)


def test_msm_custom_calculator_wrong_shape_covariance_matrix() -> None:
def test_msm_custom_calculator_wrong_shape_covariance_matrix(
rng: np.random.Generator,
) -> None:
"""Test the 'method of moments' loss with a custom calculator and a custom covariance of the wrong shape."""
series_sim = np.array([[0, 1]]).T
series_real = np.array([[1, 2]]).T
Expand All @@ -102,7 +108,7 @@ def custom_moment_calculator(time_series: NDArray) -> NDArray:
return np.array([np.mean(time_series)])

dimension = 3
random_mat = np.random.rand(dimension, dimension)
random_mat = rng.random(size=(dimension, dimension))
wrong_covariance_matrix = random_mat.T.dot(random_mat)

loss_func = MethodOfMomentsLoss(
Expand Down
4 changes: 2 additions & 2 deletions tests/test_plot/test_plot_descriptive_statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ class TestTsStats(BasePlotTest):

def setup(self) -> None:
"""Set up the test."""
np.random.seed(42)
data = np.random.rand(100)
rng = np.random.default_rng(42)
data = rng.random(100)
self.args = [data]
Loading

0 comments on commit 6dab2b3

Please sign in to comment.