Skip to content

Commit

Permalink
Improve NumpyReducer
Browse files Browse the repository at this point in the history
  • Loading branch information
durandtibo committed Mar 1, 2024
1 parent 9d66e5f commit 3ed15be
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 18 deletions.
4 changes: 3 additions & 1 deletion src/coola/reducers/numpy_.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
np = Mock() # pragma: no cover


T = TypeVar("T", bound=Sequence[Union[int, float]])
T = TypeVar("T", Sequence[Union[int, float]], np.ndarray)


class NumpyReducer(BaseBasicReducer[T]):
Expand Down Expand Up @@ -52,6 +52,8 @@ def __str__(self) -> str:
return f"{self.__class__.__qualname__}()"

def _is_empty(self, values: T) -> bool:
if isinstance(values, np.ndarray):
return values.size == 0
return not values

def _max(self, values: T) -> int | float:
Expand Down
96 changes: 79 additions & 17 deletions tests/unit/reducers/test_numpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,26 @@

import math
from typing import TYPE_CHECKING
from unittest.mock import patch
from unittest.mock import Mock, patch

import pytest

from coola.reducers import EmptySequenceError, NumpyReducer, ReducerRegistry
from coola.testing import numpy_available
from tests.unit.reducers.test_basic import EMPTY_SEQUENCES
from coola.utils import is_numpy_available

if is_numpy_available():
import numpy as np
else:
np = Mock() # pragma: no cover

if TYPE_CHECKING:
from collections.abc import Sequence


EMPTY_SEQUENCES = [[], (), np.array([])]


@numpy_available
def test_reducer_registry_available_reducers() -> None:
assert isinstance(ReducerRegistry.registry["numpy"], NumpyReducer)
Expand All @@ -30,7 +38,10 @@ def test_numpy_reducer_str() -> None:


@numpy_available
@pytest.mark.parametrize("values", [[-2, -1, 0, 1, 2], (-2, -1, 0, 1, 2), [2], [2, -1, -2, -3]])
@pytest.mark.parametrize(
"values",
[[-2, -1, 0, 1, 2], (-2, -1, 0, 1, 2), [2], [2, -1, -2, -3], np.array([-2, -1, 0, 1, 2])],
)
def test_numpy_reducer_max_int(values: Sequence[int | float]) -> None:
val = NumpyReducer().max(values)
assert isinstance(val, int)
Expand All @@ -39,7 +50,14 @@ def test_numpy_reducer_max_int(values: Sequence[int | float]) -> None:

@numpy_available
@pytest.mark.parametrize(
"values", [[-2.5, -1.5, 0.5, 1.5, 2.5], (-2.5, -1.5, 0.5, 1.5, 2.5), [2.5], [2.5, -1.5, -2, -3]]
"values",
[
[-2.5, -1.5, 0.5, 1.5, 2.5],
(-2.5, -1.5, 0.5, 1.5, 2.5),
[2.5],
[2.5, -1.5, -2, -3],
np.array([-2.5, -1.5, 0.5, 1.5, 2.5]),
],
)
def test_numpy_reducer_max_float(values: Sequence[int | float]) -> None:
val = NumpyReducer().max(values)
Expand All @@ -57,7 +75,9 @@ def test_numpy_reducer_max_empty(values: Sequence[int | float]) -> None:


@numpy_available
@pytest.mark.parametrize("values", [[-2, -1, 0, 1, 2], (-2, -1, 0, 1, 2), [0]])
@pytest.mark.parametrize(
"values", [[-2, -1, 0, 1, 2], (-2, -1, 0, 1, 2), [0], np.array([-2, -1, 0, 1, 2])]
)
def test_numpy_reducer_mean_int(values: Sequence[int | float]) -> None:
val = NumpyReducer().mean(values)
assert isinstance(val, float)
Expand All @@ -66,7 +86,13 @@ def test_numpy_reducer_mean_int(values: Sequence[int | float]) -> None:

@numpy_available
@pytest.mark.parametrize(
"values", [[-1.5, -0.5, 0.5, 1.5, 2.5], (-1.5, -0.5, 0.5, 1.5, 2.5), [0.5]]
"values",
[
[-1.5, -0.5, 0.5, 1.5, 2.5],
(-1.5, -0.5, 0.5, 1.5, 2.5),
[0.5],
np.array([-1.5, -0.5, 0.5, 1.5, 2.5]),
],
)
def test_numpy_reducer_mean_float(values: Sequence[int | float]) -> None:
val = NumpyReducer().mean(values)
Expand All @@ -84,14 +110,22 @@ def test_numpy_reducer_mean_empty(values: Sequence[int | float]) -> None:


@numpy_available
@pytest.mark.parametrize("values", [[-2, -1, 0, 1, 2], (-2, -1, 0, 1, 2), [0]])
@pytest.mark.parametrize(
"values", [[-2, -1, 0, 1, 2], (-2, -1, 0, 1, 2), [0], np.array([-2, -1, 0, 1, 2])]
)
def test_numpy_reducer_median_int(values: Sequence[int | float]) -> None:
assert NumpyReducer().median(values) == 0


@numpy_available
@pytest.mark.parametrize(
"values", [[-1.5, -0.5, 0.5, 1.5, 2.5], (-1.5, -0.5, 0.5, 1.5, 2.5), [0.5]]
"values",
[
[-1.5, -0.5, 0.5, 1.5, 2.5],
(-1.5, -0.5, 0.5, 1.5, 2.5),
[0.5],
np.array([-1.5, -0.5, 0.5, 1.5, 2.5]),
],
)
def test_numpy_reducer_median_float(values: Sequence[int | float]) -> None:
assert NumpyReducer().median(values) == 0.5
Expand All @@ -107,7 +141,10 @@ def test_numpy_reducer_median_empty(values: Sequence[int | float]) -> None:


@numpy_available
@pytest.mark.parametrize("values", [[-2, -1, 0, 1, 2], (-2, -1, 0, 1, 2), [-2], [-2, 1, 2, 3]])
@pytest.mark.parametrize(
"values",
[[-2, -1, 0, 1, 2], (-2, -1, 0, 1, 2), [-2], [-2, 1, 2, 3], np.array([-2, -1, 0, 1, 2])],
)
def test_numpy_reducer_min_int(values: Sequence[int | float]) -> None:
val = NumpyReducer().min(values)
assert isinstance(val, int)
Expand All @@ -116,7 +153,14 @@ def test_numpy_reducer_min_int(values: Sequence[int | float]) -> None:

@numpy_available
@pytest.mark.parametrize(
"values", [[-2.5, -1.5, 0.5, 1.5, 2.5], (-2.5, -1.5, 0.5, 1.5, 2.5), [-2.5], [-2.5, 1.5, 2, 3]]
"values",
[
[-2.5, -1.5, 0.5, 1.5, 2.5],
(-2.5, -1.5, 0.5, 1.5, 2.5),
[-2.5],
[-2.5, 1.5, 2, 3],
np.array([-2.5, -1.5, 0.5, 1.5, 2.5]),
],
)
def test_numpy_reducer_min_float(values: Sequence[int | float]) -> None:
val = NumpyReducer().min(values)
Expand All @@ -135,7 +179,12 @@ def test_numpy_reducer_min_empty(values: Sequence[int | float]) -> None:

@numpy_available
@pytest.mark.parametrize(
"values", [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)]
"values",
[
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
],
)
def test_numpy_reducer_quantile_int(values: Sequence[int | float]) -> None:
assert NumpyReducer().quantile(values, (0.2, 0.5, 0.9)) == [2, 5, 9]
Expand All @@ -147,6 +196,7 @@ def test_numpy_reducer_quantile_int(values: Sequence[int | float]) -> None:
[
[0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5, 10.5],
(0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5, 10.5),
np.array([0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5, 10.5]),
],
)
def test_numpy_reducer_quantile_float(values: Sequence[int | float]) -> None:
Expand All @@ -163,19 +213,22 @@ def test_numpy_reducer_quantile_empty(values: Sequence[int | float]) -> None:


@numpy_available
@pytest.mark.parametrize("values", [[2, 1, -2, 3, 0], (2, 1, -2, 3, 0)])
@pytest.mark.parametrize("values", [[2, 1, -2, 3, 0], (2, 1, -2, 3, 0), np.array([2, 1, -2, 3, 0])])
def test_numpy_reducer_sort_int(values: Sequence[int | float]) -> None:
assert NumpyReducer().sort(values) == [-2, 0, 1, 2, 3]


@numpy_available
@pytest.mark.parametrize("values", [[2.5, 1.5, -2.5, 3.5, 0.5], (2.5, 1.5, -2.5, 3.5, 0.5)])
@pytest.mark.parametrize(
"values",
[[2.5, 1.5, -2.5, 3.5, 0.5], (2.5, 1.5, -2.5, 3.5, 0.5), np.array([2.5, 1.5, -2.5, 3.5, 0.5])],
)
def test_numpy_reducer_sort_float(values: Sequence[int | float]) -> None:
assert NumpyReducer().sort(values) == [-2.5, 0.5, 1.5, 2.5, 3.5]


@numpy_available
@pytest.mark.parametrize("values", [[2, 1, -2, 3, 0], (2, 1, -2, 3, 0)])
@pytest.mark.parametrize("values", [[2, 1, -2, 3, 0], (2, 1, -2, 3, 0), np.array([2, 1, -2, 3, 0])])
def test_numpy_reducer_sort_descending(values: Sequence[int | float]) -> None:
assert NumpyReducer().sort(values, descending=True) == [3, 2, 1, 0, -2]

Expand All @@ -187,19 +240,28 @@ def test_numpy_reducer_sort_empty(values: Sequence[int | float]) -> None:


@numpy_available
@pytest.mark.parametrize("values", [[-2, -1, 0, 1, 2], (-2, -1, 0, 1, 2)])
@pytest.mark.parametrize(
"values", [[-2, -1, 0, 1, 2], (-2, -1, 0, 1, 2), np.array([-2, -1, 0, 1, 2])]
)
def test_numpy_reducer_std_int(values: Sequence[int | float]) -> None:
assert math.isclose(NumpyReducer().std(values), 1.5811388492584229, abs_tol=1e-6)


@numpy_available
@pytest.mark.parametrize("values", [[-1.5, -0.5, 0.5, 1.5, 2.5], (-1.5, -0.5, 0.5, 1.5, 2.5)])
@pytest.mark.parametrize(
"values",
[
[-1.5, -0.5, 0.5, 1.5, 2.5],
(-1.5, -0.5, 0.5, 1.5, 2.5),
np.array([-1.5, -0.5, 0.5, 1.5, 2.5]),
],
)
def test_numpy_reducer_std_float(values: Sequence[int | float]) -> None:
assert math.isclose(NumpyReducer().std(values), 1.5811388492584229, abs_tol=1e-6)


@numpy_available
@pytest.mark.parametrize("values", [[1], [1.0]])
@pytest.mark.parametrize("values", [[1], [1.0], np.array([1]), np.array([1.0])])
def test_numpy_reducer_std_one(values: Sequence[int | float]) -> None:
assert math.isnan(NumpyReducer().std(values))

Expand Down

0 comments on commit 3ed15be

Please sign in to comment.