diff --git a/src/pyrecest/filters/hypertoroidal_fourier_filter.py b/src/pyrecest/filters/hypertoroidal_fourier_filter.py index a198df740..9e045b3f0 100644 --- a/src/pyrecest/filters/hypertoroidal_fourier_filter.py +++ b/src/pyrecest/filters/hypertoroidal_fourier_filter.py @@ -20,6 +20,7 @@ ) from pyrecest.distributions.hypertorus.hypertoroidal_fourier_distribution import ( HypertoroidalFourierDistribution, + _normalize_coefficient_shape, ) from .abstract_filter import AbstractFilter @@ -56,9 +57,11 @@ def __init__(self, n_coefficients, transformation="sqrt"): "HypertoroidalFourierFilter is not supported on the " f"{pyrecest.backend.__backend_name__} backend." ) - if isinstance(n_coefficients, int): - n_coefficients = (n_coefficients,) - n_coefficients = tuple(int(n) for n in n_coefficients) + n_coefficients = _normalize_coefficient_shape( + n_coefficients, + "n_coefficients", + require_odd=True, + ) dim = len(n_coefficients) # Build a uniform HFD directly (only the DC component is non-zero) diff --git a/tests/filters/test_hypertoroidal_fourier_filter_coefficient_validation.py b/tests/filters/test_hypertoroidal_fourier_filter_coefficient_validation.py new file mode 100644 index 000000000..d64d062f4 --- /dev/null +++ b/tests/filters/test_hypertoroidal_fourier_filter_coefficient_validation.py @@ -0,0 +1,39 @@ +import unittest + +import numpy as np + +import pyrecest.backend +from pyrecest.filters.hypertoroidal_fourier_filter import HypertoroidalFourierFilter + + +@unittest.skipIf( + pyrecest.backend.__backend_name__ in ("jax", "pytorch"), + reason="HypertoroidalFourierFilter is not supported on this backend", +) +class TestHypertoroidalFourierFilterCoefficientValidation(unittest.TestCase): + def test_accepts_numpy_integer_scalar(self): + fourier_filter = HypertoroidalFourierFilter(np.int64(11)) + + self.assertEqual(fourier_filter.filter_state.coeff_mat.shape, (11,)) + + def test_rejects_values_that_would_be_silently_reinterpreted(self): + invalid_values = ( + True, + "11", + (), + (11.5,), + (11.0,), + ) + + for value in invalid_values: + with self.subTest(value=value): + with self.assertRaises((TypeError, ValueError)): + HypertoroidalFourierFilter(value) + + def test_rejects_nonpositive_or_even_coefficient_counts(self): + invalid_values = (0, -1, 10, (11, 0), (11, 12)) + + for value in invalid_values: + with self.subTest(value=value): + with self.assertRaisesRegex(ValueError, "n_coefficients"): + HypertoroidalFourierFilter(value)