diff --git a/csaps/__init__.py b/csaps/__init__.py index 1e507f7..650be5c 100644 --- a/csaps/__init__.py +++ b/csaps/__init__.py @@ -13,7 +13,6 @@ # Shortcut 'csaps', 'AutoSmoothingResult', - # Classes 'ISplinePPForm', 'ISmoothingSpline', @@ -21,7 +20,6 @@ 'NdGridSplinePPForm', 'CubicSmoothingSpline', 'NdGridCubicSmoothingSpline', - # Type-hints 'UnivariateDataType', 'MultivariateDataType', diff --git a/csaps/_base.py b/csaps/_base.py index d5ab3dc..b72f7e2 100644 --- a/csaps/_base.py +++ b/csaps/_base.py @@ -11,8 +11,7 @@ class ISplinePPForm(abc.ABC, Generic[TData, TProps]): - """The interface class for spline representation in PP-form - """ + """The interface class for spline representation in PP-form""" __module__ = 'csaps' @@ -84,24 +83,20 @@ def shape(self) -> Tuple[int, ...]: class ISmoothingSpline(abc.ABC, Generic[TSpline, TSmooth, TXi, TNu, TExtrapolate]): - """The interface class for smooting splines - """ + """The interface class for smooting splines""" __module__ = 'csaps' @property @abc.abstractmethod def smooth(self) -> TSmooth: - """Returns smoothing factor(s) - """ + """Returns smoothing factor(s)""" @property @abc.abstractmethod def spline(self) -> TSpline: - """Returns spline representation in PP-form - """ + """Returns spline representation in PP-form""" @abc.abstractmethod def __call__(self, xi: TXi, nu: Optional[TNu] = None, extrapolate: Optional[TExtrapolate] = None) -> np.ndarray: - """Evaluates spline on the data sites - """ + """Evaluates spline on the data sites""" diff --git a/csaps/_reshape.py b/csaps/_reshape.py index 4479680..31ca633 100644 --- a/csaps/_reshape.py +++ b/csaps/_reshape.py @@ -150,7 +150,7 @@ def umv_coeffs_to_flatten(arr: np.ndarray): strides = arr.strides[:-3:-1] arr_view = as_strided(arr, shape=shape, strides=strides) else: # pragma: no cover - raise ValueError(f"The array ndim must be 2 or 3, but given array has ndim={arr.ndim}.") + raise ValueError(f'The array ndim must be 2 or 3, but given array has ndim={arr.ndim}.') return arr_view diff --git a/csaps/_sspndg.py b/csaps/_sspndg.py index 32ecc8f..620eac1 100644 --- a/csaps/_sspndg.py +++ b/csaps/_sspndg.py @@ -62,11 +62,11 @@ def coeffs(self) -> np.ndarray: @property def order(self) -> Tuple[int, ...]: - return self.c.shape[:self.c.ndim // 2] + return self.c.shape[: self.c.ndim // 2] @property def pieces(self) -> Tuple[int, ...]: - return self.c.shape[self.c.ndim // 2:] + return self.c.shape[self.c.ndim // 2 :] @property def ndim(self) -> int: @@ -112,7 +112,7 @@ def __call__( raise ValueError(f"'x' sequence must have length {self.ndim} according to 'breaks'") if nu is None: - nu = (0, ) * len(x) + nu = (0,) * len(x) if extrapolate is None: extrapolate = True @@ -210,7 +210,6 @@ def __init__( smooth: Optional[Union[float, Sequence[Optional[float]]]] = None, normalizedsmooth: bool = False, ) -> None: - x, y, w, s = self._prepare_data(xdata, ydata, weights, smooth) coeffs, smooth = self._make_spline(x, y, w, s, normalizedsmooth) @@ -306,8 +305,7 @@ def _prepare_data(cls, xdata, ydata, weights, smooth): if len(smooth) != data_ndim: raise ValueError( - 'Number of smoothing parameter values must ' - f'be equal number of dimensions ({data_ndim})' + 'Number of smoothing parameter values must ' f'be equal number of dimensions ({data_ndim})' ) return xdata, ydata, weights, smooth @@ -324,7 +322,7 @@ def _make_spline(xdata, ydata, weights, smooth, normalizedsmooth): smooth=smooth[0], normalizedsmooth=normalizedsmooth, ) - return s.spline.coeffs, (s.smooth, ) + return s.spline.coeffs, (s.smooth,) shape = ydata.shape coeffs = ydata diff --git a/csaps/_sspumv.py b/csaps/_sspumv.py index ba486aa..ea94e72 100644 --- a/csaps/_sspumv.py +++ b/csaps/_sspumv.py @@ -58,8 +58,7 @@ def ndim(self) -> int: @property def shape(self) -> Tuple[int, ...]: - """Returns the source data shape - """ + """Returns the source data shape""" shape: List[int] = list(self.c.shape[2:]) shape.insert(self.axis, self.c.shape[1] + 1) @@ -124,7 +123,6 @@ def __init__( axis: int = -1, normalizedsmooth: bool = False, ): - x, y, w, shape, axis = self._prepare_data(xdata, ydata, weights, axis) coeffs, smooth = self._make_spline(x, y, w, smooth, shape, normalizedsmooth) spline = SplinePPForm.construct_fast(coeffs, x, axis=axis) @@ -236,7 +234,7 @@ def _compute_smooth(a, b): def trace(m: sp.dia_matrix): return m.diagonal().sum() - return 1. / (1. + trace(a) / (6. * trace(b))) + return 1.0 / (1.0 + trace(a) / (6.0 * trace(b))) @staticmethod def _normalize_smooth(x: np.ndarray, w: np.ndarray, smooth: Optional[float]): @@ -246,8 +244,8 @@ def _normalize_smooth(x: np.ndarray, w: np.ndarray, smooth: Optional[float]): span = np.ptp(x) - eff_x = 1 + (span**2) / np.sum(np.diff(x)**2) - eff_w = np.sum(w)**2 / np.sum(w**2) + eff_x = 1 + (span**2) / np.sum(np.diff(x) ** 2) + eff_w = np.sum(w) ** 2 / np.sum(w**2) k = 80 * (span**3) * (x.size**-2) * (eff_x**-0.5) * (eff_w**-0.5) s = 0.5 if smooth is None else smooth @@ -281,11 +279,11 @@ def _make_spline(x, y, w, smooth, shape, normalizedsmooth): diags_r = np.vstack((dx[1:], 2 * (dx[1:] + dx[:-1]), dx[:-1])) r = sp.spdiags(diags_r, [-1, 0, 1], pcount - 2, pcount - 2) - dx_recip = 1. / dx + dx_recip = 1.0 / dx diags_qtw = np.vstack((dx_recip[:-1], -(dx_recip[1:] + dx_recip[:-1]), dx_recip[1:])) - diags_sqrw_recip = 1. / np.sqrt(w) + diags_sqrw_recip = 1.0 / np.sqrt(w) - qtw = (sp.diags(diags_qtw, [0, 1, 2], (pcount - 2, pcount)) @ sp.diags(diags_sqrw_recip, 0, (pcount, pcount))) + qtw = sp.diags(diags_qtw, [0, 1, 2], (pcount - 2, pcount)) @ sp.diags(diags_sqrw_recip, 0, (pcount, pcount)) qtw = qtw @ qtw.T p = smooth @@ -295,7 +293,7 @@ def _make_spline(x, y, w, smooth, shape, normalizedsmooth): elif smooth is None: p = CubicSmoothingSpline._compute_smooth(r, qtw) - pp = (6. * (1. - p)) + pp = 6.0 * (1.0 - p) # Solve linear system for the 2nd derivatives a = pp * qtw + p * r @@ -314,15 +312,15 @@ def _make_spline(x, y, w, smooth, shape, normalizedsmooth): d1 = np.diff(vpad(u), axis=0) / dx d2 = np.diff(vpad(d1), axis=0) - diags_w_recip = 1. / w + diags_w_recip = 1.0 / w w = sp.diags(diags_w_recip, 0, (pcount, pcount)) yi = y.T - (pp * w) @ d2 pu = vpad(p * u) c1 = np.diff(pu, axis=0) / dx - c2 = 3. * pu[:-1, :] - c3 = np.diff(yi, axis=0) / dx - dx * (2. * pu[:-1, :] + pu[1:, :]) + c2 = 3.0 * pu[:-1, :] + c3 = np.diff(yi, axis=0) / dx - dx * (2.0 * pu[:-1, :] + pu[1:, :]) c4 = yi[:-1, :] c_shape = (4, pcount - 1) + shape[1:] diff --git a/docs/conf.py b/docs/conf.py index 393e297..3c943fb 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -25,6 +25,7 @@ def _get_version(): from csaps import __version__ + return __version__ @@ -54,10 +55,10 @@ def _get_version(): 'figure.autolayout': 'True', 'figure.figsize': '5, 3.5', 'savefig.bbox': 'tight', - 'savefig.facecolor': "None", + 'savefig.facecolor': 'None', } -plot_formats = [("png", 90)] +plot_formats = [('png', 90)] plot_include_source = True plot_html_show_source_link = False plot_html_show_formats = False diff --git a/tests/conftest.py b/tests/conftest.py index 43cd7fe..77ac540 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -18,8 +18,7 @@ class UnivariateData(NamedTuple): @pytest.fixture(scope='session') def univariate_data() -> UnivariateData: - """Univariate exponential noisy data sample - """ + """Univariate exponential noisy data sample""" # yapf: disable @@ -151,107 +150,218 @@ def ndgrid_2d_data() -> NdGrid2dData: z = np.array( [ [ - -0.153527183790132, 0.360477327564227, -0.400800187993851, -0.661751768834967, 1.39827150034968, - 1.044246054228617, 0.069681364921588 + -0.153527183790132, + 0.360477327564227, + -0.400800187993851, + -0.661751768834967, + 1.39827150034968, + 1.044246054228617, + 0.069681364921588, ], [ - 0.211217178485871, 0.592683030706752, 1.294599451385471, -4.924883983709012, -2.641771353280953, - 0.245330967159293, 0.171928943618129 + 0.211217178485871, + 0.592683030706752, + 1.294599451385471, + -4.924883983709012, + -2.641771353280953, + 0.245330967159293, + 0.171928943618129, ], [ - 1.012132959440344, 0.132792505223302, -3.970096642307903, 0.702129940268655, 4.729521910567126, - 0.208213433055832, -0.40275495492284 + 1.012132959440344, + 0.132792505223302, + -3.970096642307903, + 0.702129940268655, + 4.729521910567126, + 0.208213433055832, + -0.40275495492284, ], [ - 0.35749708646856, 2.409904780478664, 0.892801916808247, 7.563804764350773, 2.510824654279176, - 0.317303593544217, 0.393080231785911 + 0.35749708646856, + 2.409904780478664, + 0.892801916808247, + 7.563804764350773, + 2.510824654279176, + 0.317303593544217, + 0.393080231785911, ], [ - 0.000706314884567, 1.009080744382149, -0.45874273220015, -0.323494125914201, -1.700362064179427, - -1.394209767885332, -0.645566364768713 - ] + 0.000706314884567, + 1.009080744382149, + -0.45874273220015, + -0.323494125914201, + -1.700362064179427, + -1.394209767885332, + -0.645566364768713, + ], ] ) zi = np.array( [ [ - -0.055377680470166, 0.195656616225213, -0.295030253111251, -0.830533929888634, 0.193176060095987, - 0.770374649757329, 0.252865339751650 + -0.055377680470166, + 0.195656616225213, + -0.295030253111251, + -0.830533929888634, + 0.193176060095987, + 0.770374649757329, + 0.252865339751650, ], [ - 0.471994652733459, 0.293417006151304, -0.758106516247562, -1.960431309380293, -0.781936045165379, - 0.216341632490716, 0.180333235920312 + 0.471994652733459, + 0.293417006151304, + -0.758106516247562, + -1.960431309380293, + -0.781936045165379, + 0.216341632490716, + 0.180333235920312, ], [ - 0.875919224697303, 0.067344259041702, -0.735889940425535, 0.882313890047783, 2.056305063365266, - 0.896850201038262, -0.190314083560006 + 0.875919224697303, + 0.067344259041702, + -0.735889940425535, + 0.882313890047783, + 2.056305063365266, + 0.896850201038262, + -0.190314083560006, ], [ - 0.606245376082951, 0.941947682137626, 1.225331206624579, 3.379540894700002, 2.581257432070516, - 0.581783850872262, -0.187728390603794 + 0.606245376082951, + 0.941947682137626, + 1.225331206624579, + 3.379540894700002, + 2.581257432070516, + 0.581783850872262, + -0.187728390603794, ], [ - 0.183397630824828, 0.805748594104382, 0.503605325241657, 0.264260721868410, -0.874052860773297, - -1.188420383689933, -0.617919628357980 - ] + 0.183397630824828, + 0.805748594104382, + 0.503605325241657, + 0.264260721868410, + -0.874052860773297, + -1.188420383689933, + -0.617919628357980, + ], ] ) zi_d1 = np.array( [ [ - -0.121812472223565, -0.157326929297246, -0.828962829944406, -0.640465943383180, 0.503884652683063, - 0.662549465069741, 0.501482011524879 + -0.121812472223565, + -0.157326929297246, + -0.828962829944406, + -0.640465943383180, + 0.503884652683063, + 0.662549465069741, + 0.501482011524879, ], [ - -0.470497745190257, -0.466533613272337, 0.403062598673842, 0.767903075058928, -0.334118185393139, - -0.545086449738045, -0.154825057274055 + -0.470497745190257, + -0.466533613272337, + 0.403062598673842, + 0.767903075058928, + -0.334118185393139, + -0.545086449738045, + -0.154825057274055, ], [ - 0.194607321700336, 0.192434581435788, 1.293210437573223, 0.562712202846881, -1.370259457802591, - -0.823157992133989, -0.176531696944242 + 0.194607321700336, + 0.192434581435788, + 1.293210437573223, + 0.562712202846881, + -1.370259457802591, + -0.823157992133989, + -0.176531696944242, ], [ - 0.607431089728563, 0.510938352696447, -0.237734672001804, -1.058160086418725, -0.269494123744448, - 0.632430110330214, 0.577443254979813 + 0.607431089728563, + 0.510938352696447, + -0.237734672001804, + -1.058160086418725, + -0.269494123744448, + 0.632430110330214, + 0.577443254979813, ], [ - 0.006464517899505, -0.138732754726110, -1.426802191857966, -1.065472485030174, 1.029409644646945, - 1.158453840382574, 0.696817777775121 - ] + 0.006464517899505, + -0.138732754726110, + -1.426802191857966, + -1.065472485030174, + 1.029409644646945, + 1.158453840382574, + 0.696817777775121, + ], ] ) zi_d2 = np.array( [ - [0., 0., 0., 0., 0., 0., 0.], - [0., 0.090236774837945, 3.432579482518258, -3.029508420063717, -2.105055823406707, 1.260180219448802, 0.], - [0., -0.104263911255016, -2.890141730806884, -0.016560671330926, 3.251809714350141, -0.674203298932788, 0.], - [0., -0.111324652785139, -1.121581432777390, 3.822735995622450, -0.837099042473098, -0.929483902301833, 0.], - [0., 0., 0., 0., 0., 0., 0.] + [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + [0.0, 0.090236774837945, 3.432579482518258, -3.029508420063717, -2.105055823406707, 1.260180219448802, 0.0], + [ + 0.0, + -0.104263911255016, + -2.890141730806884, + -0.016560671330926, + 3.251809714350141, + -0.674203298932788, + 0.0, + ], + [ + 0.0, + -0.111324652785139, + -1.121581432777390, + 3.822735995622450, + -0.837099042473098, + -0.929483902301833, + 0.0, + ], + [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], ] ) zi_ad1 = np.array( [ - [0., 0., 0., 0., 0., 0., 0.], + [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [ - 0., 0.509395864624591, 0.476401125691113, -1.598603993938397, -3.760699480840437, -3.750794105947393, - -3.076469947082991 + 0.0, + 0.509395864624591, + 0.476401125691113, + -1.598603993938397, + -3.760699480840437, + -3.750794105947393, + -3.076469947082991, ], [ - 0., 1.318187655218603, 0.563946491827388, -3.255188072198998, -5.625801866969895, -4.504932326883326, - -3.364137445816383 + 0.0, + 1.318187655218603, + 0.563946491827388, + -3.255188072198998, + -5.625801866969895, + -4.504932326883326, + -3.364137445816383, ], [ - 0., 2.511070517473814, 2.161223166080562, 0.664448782633726, 3.261109214575526, 7.566477396430049, - 9.182402413317154 + 0.0, + 2.511070517473814, + 2.161223166080562, + 0.664448782633726, + 3.261109214575526, + 7.566477396430049, + 9.182402413317154, ], [ - 0., 3.799550963870154, 5.127806810771760, 6.567161731071815, 12.269550101243563, 17.158134933110624, - 18.133537415972746 - ] + 0.0, + 3.799550963870154, + 5.127806810771760, + 6.567161731071815, + 12.269550101243563, + 17.158134933110624, + 18.133537415972746, + ], ] ) @@ -268,18 +378,18 @@ class SurfaceData(NamedTuple): @pytest.fixture(scope='session') def surface_data() -> SurfaceData: - """2-d surface data sample - """ + """2-d surface data sample""" np.random.seed(12345) xy = (np.linspace(-3.0, 3.0, 61), np.linspace(-3.5, 3.5, 51)) i, j = np.meshgrid(*xy, indexing='ij') z = ( - 3 * (1 - j)**2. * np.exp(-(j**2) - (i + 1)**2) - 10 * (j / 5 - j**3 - i**5) * np.exp(-j**2 - i**2) - - 1 / 3 * np.exp(-(j + 1)**2 - i**2) + 3 * (1 - j) ** 2.0 * np.exp(-(j**2) - (i + 1) ** 2) + - 10 * (j / 5 - j**3 - i**5) * np.exp(-(j**2) - i**2) + - 1 / 3 * np.exp(-((j + 1) ** 2) - i**2) ) - z += (np.random.randn(*z.shape) * 0.75) + z += np.random.randn(*z.shape) * 0.75 return SurfaceData(xy, z) diff --git a/tests/test_csaps.py b/tests/test_csaps.py index 4808056..c33ddbb 100644 --- a/tests/test_csaps.py +++ b/tests/test_csaps.py @@ -8,8 +8,8 @@ def curve(): np.random.seed(12345) - x = np.linspace(-5., 5., 25) - y = np.exp(-(x / 2.5)**2) + (np.random.rand(25) - 0.2) * 0.3 + x = np.linspace(-5.0, 5.0, 25) + y = np.exp(-((x / 2.5) ** 2)) + (np.random.rand(25) - 0.2) * 0.3 return x, y @@ -22,8 +22,9 @@ def surface(): i, j = np.meshgrid(*x, indexing='ij') y = ( - 3 * (1 - j)**2. * np.exp(-(j**2) - (i + 1)**2) - 10 * (j / 5 - j**3 - i**5) * np.exp(-j**2 - i**2) - - 1 / 3 * np.exp(-(j + 1)**2 - i**2) + 3 * (1 - j) ** 2.0 * np.exp(-(j**2) - (i + 1) ** 2) + - 10 * (j / 5 - j**3 - i**5) * np.exp(-(j**2) - i**2) + - 1 / 3 * np.exp(-((j + 1) ** 2) - i**2) ) y += np.random.randn(*y.shape) * 0.75 @@ -43,10 +44,14 @@ def data(curve, surface, request): return x, y, x, [0.85, 0.85], NdGridCubicSmoothingSpline -@pytest.mark.parametrize('data', [ - 'univariate', - 'ndgrid', -], indirect=True) +@pytest.mark.parametrize( + 'data', + [ + 'univariate', + 'ndgrid', + ], + indirect=True, +) @pytest.mark.parametrize('tolist', [True, False]) def test_shortcut_output(data, tolist): x, y, xi, smooth, sp_cls = data @@ -76,14 +81,15 @@ def test_shortcut_output(data, tolist): @pytest.mark.parametrize( - 'smooth, cls', [ + 'smooth, cls', + [ (0.85, np.ndarray), ([0.85, 0.85], np.ndarray), (None, AutoSmoothingResult), ([None, 0.85], AutoSmoothingResult), ([0.85, None], AutoSmoothingResult), ([None, None], AutoSmoothingResult), - ] + ], ) def test_shortcut_ndgrid_smooth_output(surface, smooth, cls): x, y = surface @@ -99,12 +105,14 @@ def test_normalized_smooth(data, smooth, scale): x, y, xi, *_ = data x2 = ( - [scale * np.array(xx, dtype=np.float64) - for xx in x] if isinstance(x, list) else scale * np.array(x, dtype=np.float64) + [scale * np.array(xx, dtype=np.float64) for xx in x] + if isinstance(x, list) + else scale * np.array(x, dtype=np.float64) ) xi2 = ( - [scale * np.array(xx, dtype=np.float64) - for xx in xi] if isinstance(x, list) else scale * np.array(xi, dtype=np.float64) + [scale * np.array(xx, dtype=np.float64) for xx in xi] + if isinstance(x, list) + else scale * np.array(xi, dtype=np.float64) ) smoothed_data_a = csaps(x, y, xi, smooth=smooth, normalizedsmooth=True) diff --git a/tests/test_ndg.py b/tests/test_ndg.py index 0fab16c..3635fc5 100644 --- a/tests/test_ndg.py +++ b/tests/test_ndg.py @@ -6,7 +6,8 @@ @pytest.mark.parametrize( - 'x,y,w,p', [ + 'x,y,w,p', + [ ([1, 2, 3], np.ones((10, 10)), None, None), ([[1], [1]], np.ones((1, 1)), None, None), ([[1, 2, 3], [1, 2, 3]], np.ones((4, 3)), None, None), @@ -17,7 +18,7 @@ ([[1, 2, 3], [1, 2, 3]], np.ones((3, 3)), None, [0.5, 0.4, 0.2]), (np.array([[1, 2, 3], [4, 5, 6]]), np.ones((3, 3)), None, None), ([np.arange(6).reshape(2, 3), np.arange(6).reshape(2, 3)], np.ones((6, 6)), None, None), - ] + ], ) def test_invalid_data(x, y, w, p): with pytest.raises((ValueError, TypeError)): @@ -25,12 +26,13 @@ def test_invalid_data(x, y, w, p): @pytest.mark.parametrize( - 'x, xi', [ - (([1, 2, 3], ), ([], )), + 'x, xi', + [ + (([1, 2, 3],), ([],)), (([1, 2, 3], [1, 2, 3]), ([1, 2], [])), (([1, 2, 3], [1, 2, 3], [1, 2, 3]), ([1, 2, 3], [1, 2, 3])), (([1, 2, 3], [1, 2, 3]), ([1, 2, 3], [1, 2, 3], [1, 2, 3])), - ] + ], ) def test_invalid_evaluate_data(x, xi): np.random.seed(1234) @@ -43,10 +45,11 @@ def test_invalid_evaluate_data(x, xi): @pytest.mark.parametrize( - 'shape, coeffs_shape, order, pieces, ndim', [ - ((2, ), (2, 1), (2, ), (1, ), 1), - ((3, ), (4, 2), (4, ), (2, ), 1), - ((4, ), (4, 3), (4, ), (3, ), 1), + 'shape, coeffs_shape, order, pieces, ndim', + [ + ((2,), (2, 1), (2,), (1,), 1), + ((3,), (4, 2), (4,), (2,), 1), + ((4,), (4, 3), (4,), (3,), 1), ((2, 4), (2, 4, 1, 3), (2, 4), (1, 3), 2), ((3, 4), (4, 4, 2, 3), (4, 4), (2, 3), 2), ((4, 4), (4, 4, 3, 3), (4, 4), (3, 3), 2), @@ -54,7 +57,7 @@ def test_invalid_evaluate_data(x, xi): ((3, 4, 5), (4, 4, 4, 2, 3, 4), (4, 4, 4), (2, 3, 4), 3), ((2, 3, 2, 6), (2, 4, 2, 4, 1, 2, 1, 5), (2, 4, 2, 4), (1, 2, 1, 5), 4), ((3, 4, 5, 6), (4, 4, 4, 4, 2, 3, 4, 5), (4, 4, 4, 4), (2, 3, 4, 5), 4), - ] + ], ) def test_ndsplineppform(shape, coeffs_shape, order, pieces, ndim): x = tuple(np.arange(s) for s in shape) @@ -83,13 +86,14 @@ def test_surface(surface_data): @pytest.mark.parametrize( - 'shape, smooth', [ - ((4, ), 0.0), - ((4, ), 0.5), - ((4, ), 1.0), - ((4, ), (0.0, )), - ((4, ), (0.5, )), - ((4, ), (1.0, )), + 'shape, smooth', + [ + ((4,), 0.0), + ((4,), 0.5), + ((4,), 1.0), + ((4,), (0.0,)), + ((4,), (0.5,)), + ((4,), (1.0,)), ((4, 5), 0.0), ((4, 5), 0.5), ((4, 5), 1.0), @@ -118,7 +122,7 @@ def test_surface(surface_data): ((4, 5, 6, 7), (0.0, 0.5, 0.6, 0.0)), ((4, 5, 6, 7), (0.0, 0.5, 0.6, 0.7)), ((4, 5, 6, 7), (0.4, 0.5, 0.6, 0.7)), - ] + ], ) def test_smooth_factor(shape, smooth): x = [np.arange(s) for s in shape] @@ -135,8 +139,9 @@ def test_smooth_factor(shape, smooth): @pytest.mark.parametrize( - 'shape', [ - (2, ), + 'shape', + [ + (2,), (2, 3), (2, 2), (2, 3, 4), @@ -151,7 +156,7 @@ def test_smooth_factor(shape, smooth): (2, 2, 2, 3, 4), (2, 2, 2, 2, 3), (2, 2, 2, 2, 2), - ] + ], ) def test_nd_2pt_array(shape: tuple): xdata = [np.arange(s) for s in shape] @@ -165,9 +170,10 @@ def test_nd_2pt_array(shape: tuple): @pytest.mark.parametrize( - 'shape', [ - (2, ), - (3, ), + 'shape', + [ + (2,), + (3,), (2, 3), (3, 4), (3, 2, 4), @@ -176,7 +182,7 @@ def test_nd_2pt_array(shape: tuple): (3, 4, 5, 6), (3, 2, 2, 6, 2), (3, 4, 5, 6, 7), - ] + ], ) def test_nd_array(shape: tuple): xdata = [np.arange(s) for s in shape] @@ -201,17 +207,23 @@ def test_auto_smooth_2d(ndgrid_2d_data): assert zi == pytest.approx(zi_expected) -@pytest.mark.parametrize('nu', [ - None, - (0, 0), - (1, 1), - (2, 2), -]) -@pytest.mark.parametrize('extrapolate', [ - None, - True, - False, -]) +@pytest.mark.parametrize( + 'nu', + [ + None, + (0, 0), + (1, 1), + (2, 2), + ], +) +@pytest.mark.parametrize( + 'extrapolate', + [ + None, + True, + False, + ], +) def test_evaluate_nu_extrapolate(nu: tuple, extrapolate: bool): x = ([1, 2, 3, 4], [1, 2, 3, 4]) xi = ([0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]) diff --git a/tests/test_reshape.py b/tests/test_reshape.py index 5a1f71e..059bbfb 100644 --- a/tests/test_reshape.py +++ b/tests/test_reshape.py @@ -10,7 +10,8 @@ @pytest.mark.parametrize( - 'shape_canonical, shape_flatten, pieces', [ + 'shape_canonical, shape_flatten, pieces', + [ ((2, 1), (1, 2), 1), ((3, 6), (1, 18), 6), ((4, 3), (1, 12), 3), @@ -18,7 +19,7 @@ ((4, 5, 2), (2, 20), 5), ((4, 6, 3), (3, 24), 6), ((4, 120, 53), (53, 480), 120), - ] + ], ) def test_umv_coeffs_reshape(shape_canonical: tuple, shape_flatten: tuple, pieces: int): np.random.seed(1234) @@ -35,33 +36,28 @@ def test_umv_coeffs_reshape(shape_canonical: tuple, shape_flatten: tuple, pieces 'shape_canonical, shape_flatten, pieces', [ # 1-d 2-ordered - ((2, 3), (2, 3), (3, )), - ((2, 4), (2, 4), (4, )), - ((2, 5), (2, 5), (5, )), - + ((2, 3), (2, 3), (3,)), + ((2, 4), (2, 4), (4,)), + ((2, 5), (2, 5), (5,)), # 1-d 3-ordered - ((3, 3), (3, 3), (3, )), - ((3, 4), (3, 4), (4, )), - ((3, 5), (3, 5), (5, )), - + ((3, 3), (3, 3), (3,)), + ((3, 4), (3, 4), (4,)), + ((3, 5), (3, 5), (5,)), # 1-d 4-ordered - ((4, 3), (4, 3), (3, )), - ((4, 4), (4, 4), (4, )), - ((4, 5), (4, 5), (5, )), - + ((4, 3), (4, 3), (3,)), + ((4, 4), (4, 4), (4,)), + ((4, 5), (4, 5), (5,)), # 2-d {2,4}-ordered ((2, 4, 3, 4), (6, 16), (3, 4)), ((4, 2, 3, 3), (12, 6), (3, 3)), ((4, 2, 4, 3), (16, 6), (4, 3)), ((2, 4, 4, 4), (8, 16), (4, 4)), - # 2-d {4,4}-ordered ((4, 4, 3, 3), (12, 12), (3, 3)), - # 3-d {4,4,4}-ordered ((4, 4, 4, 3, 3, 3), (12, 12, 12), (3, 3, 3)), ((4, 4, 4, 3, 5, 7), (12, 20, 28), (3, 5, 7)), - ] + ], ) def test_ndg_coeffs_reshape(shape_canonical: tuple, shape_flatten: tuple, pieces: tuple): np.random.seed(1234) diff --git a/tests/test_umv.py b/tests/test_umv.py index 07346f6..f491c99 100644 --- a/tests/test_umv.py +++ b/tests/test_umv.py @@ -8,14 +8,20 @@ @pytest.mark.parametrize( - 'x,y,w', [ - ([1], [2], None), ([1, 2, 3], [1, 2], None), ([(1, 2, 3), (1, 2, 3)], [1, 2, 3], None), - ([1, 2, 3], [1, 2, 3], [1, 1]), ([1, 2, 3], [1, 2, 3], [1, 1, 1, 1]), - ([1, 2, 3], [1, 2, 3], [(1, 1, 1), (1, 1, 1)]), ([1, 2, 3], [(1, 2, 3, 4), (1, 2, 3, 4)], None), - ([1, 2, 3], np.ones((2, 4, 5)), None), ([1, 2, 3], np.ones((2, 4, 3)), np.ones((2, 4, 4))), + 'x,y,w', + [ + ([1], [2], None), + ([1, 2, 3], [1, 2], None), + ([(1, 2, 3), (1, 2, 3)], [1, 2, 3], None), + ([1, 2, 3], [1, 2, 3], [1, 1]), + ([1, 2, 3], [1, 2, 3], [1, 1, 1, 1]), + ([1, 2, 3], [1, 2, 3], [(1, 1, 1), (1, 1, 1)]), + ([1, 2, 3], [(1, 2, 3, 4), (1, 2, 3, 4)], None), + ([1, 2, 3], np.ones((2, 4, 5)), None), + ([1, 2, 3], np.ones((2, 4, 3)), np.ones((2, 4, 4))), ([1, 2, 3], [(1, 2, 3), (1, 2, 3)], [(1, 1, 1, 1), (1, 1, 1, 1)]), - ([1, 2, 3], [(1, 2, 3), (1, 2, 3)], [(1, 1, 1), (1, 1, 1), (1, 1, 1)]) - ] + ([1, 2, 3], [(1, 2, 3), (1, 2, 3)], [(1, 1, 1), (1, 1, 1), (1, 1, 1)]), + ], ) def test_invalid_data(x, y, w): with pytest.raises(ValueError): @@ -27,73 +33,55 @@ def test_invalid_data(x, y, w): [ # 1D (2, ) [2, 4], - # 2D (2, 2) [(2, 4), (3, 5)], - # 2D (3, 2) [(2, 4), (3, 5), (4, 6)], - # 3D (2, 2, 2) [[(1, 2), (3, 4)], [(5, 6), (7, 8)]], - # 1D (3, ) [2, 4, 6], - # 2D (2, 5) [(1, 2, 3, 4, 5), (3, 4, 5, 6, 7)], - # 2D (3, 3) [(2, 4, 6), (3, 5, 7), (4, 6, 8)], - # 3D (2, 2, 3) [[(2, 4, 6), (3, 5, 7)], [(2, 4, 6), (3, 5, 7)]], - # 1D (4, ) [2, 4, 6, 8], - # 2D (2, 4) [(2, 4, 6, 8), (3, 5, 7, 9)], - # 2D (3, 4) [(2, 4, 6, 8), (3, 5, 7, 9), (4, 6, 8, 10)], - # 3D (2, 2, 4) [[(2, 4, 6, 8), (3, 5, 7, 9)], [(2, 4, 6, 8), (3, 5, 7, 9)]], - # 3D (2, 3, 4) [[(2, 4, 6, 8), (3, 5, 7, 9), (4, 6, 8, 10)], [(2, 4, 6, 8), (3, 5, 7, 9), (4, 6, 8, 10)]], - # 3D (3, 2, 4) [[(2, 4, 6, 8), (3, 5, 7, 9)], [(2, 4, 6, 8), (3, 5, 7, 9)], [(2, 4, 6, 8), (3, 5, 7, 9)]], - # 3D (3, 3, 4) [ [(2, 4, 6, 8), (3, 5, 7, 9), (4, 6, 8, 10)], [(2, 4, 6, 8), (3, 5, 7, 9), (4, 6, 8, 10)], [(2, 4, 6, 8), (3, 5, 7, 9), (4, 6, 8, 10)], ], - # 4D (2, 2, 2, 4) [ [[(2, 4, 6, 8), (3, 5, 7, 9)], [(2, 4, 6, 8), (3, 5, 7, 9)]], [[(2, 4, 6, 8), (3, 5, 7, 9)], [(2, 4, 6, 8), (3, 5, 7, 9)]], ], - # 4D (3, 2, 2, 4) [ [[(2, 4, 6, 8), (3, 5, 7, 9)], [(2, 4, 6, 8), (3, 5, 7, 9)]], [[(2, 4, 6, 8), (3, 5, 7, 9)], [(2, 4, 6, 8), (3, 5, 7, 9)]], [[(2, 4, 6, 8), (3, 5, 7, 9)], [(2, 4, 6, 8), (3, 5, 7, 9)]], ], - # 4D (3, 2, 3, 4) [ [[(2, 4, 6, 8), (3, 5, 7, 9), (4, 6, 8, 10)], [(2, 4, 6, 8), (3, 5, 7, 9), (4, 6, 8, 10)]], [[(2, 4, 6, 8), (3, 5, 7, 9), (4, 6, 8, 10)], [(2, 4, 6, 8), (3, 5, 7, 9), (4, 6, 8, 10)]], [[(2, 4, 6, 8), (3, 5, 7, 9), (4, 6, 8, 10)], [(2, 4, 6, 8), (3, 5, 7, 9), (4, 6, 8, 10)]], ], - # 4D (3, 3, 3, 4) [ [ @@ -112,7 +100,7 @@ def test_invalid_data(x, y, w): [(2, 4, 6, 8), (3, 5, 7, 9), (4, 6, 8, 10)], ], ], - ] + ], ) def test_vectorize(y): x = np.arange(np.array(y).shape[-1]) @@ -128,7 +116,7 @@ def test_vectorize(y): product, [ # shape - [(2, ), (4, )], + [(2,), (4,)], permutations((2, 4), 2), permutations((3, 4, 5), 3), permutations((3, 4, 5, 6), 4), @@ -139,9 +127,9 @@ def test_vectorize(y): range(-2, 2), range(-3, 3), range(-4, 4), - ] + ], ) - ) + ), ) def test_axis(shape, axis): y = np.arange(int(np.prod(shape))).reshape(shape) @@ -157,7 +145,7 @@ def test_axis(shape, axis): ndim = int(np.prod(shape)) // shape[axis] order = 2 if len(x) < 3 else 4 pieces = len(x) - 1 - coeffs_shape = (order, pieces) + shape[:axis] + shape[axis + 1:] + coeffs_shape = (order, pieces) + shape[:axis] + shape[axis + 1 :] assert ss.breaks == pytest.approx(x) assert ss.coeffs.shape == coeffs_shape @@ -169,12 +157,12 @@ def test_axis(shape, axis): def test_zero_smooth(): - x = [1., 2., 4., 6.] - y = [2., 4., 5., 7.] + x = [1.0, 2.0, 4.0, 6.0] + y = [2.0, 4.0, 5.0, 7.0] - sp = csaps.CubicSmoothingSpline(x, y, smooth=0.) + sp = csaps.CubicSmoothingSpline(x, y, smooth=0.0) - assert sp.smooth == pytest.approx(0.) + assert sp.smooth == pytest.approx(0.0) ys = sp(x) @@ -192,16 +180,28 @@ def test_auto_smooth(univariate_data): @pytest.mark.parametrize( - 'x,y,xi,yid', [ - ([1., 2.], [3., 4.], [1., 1.5, 2.], [3., 3.5, 4.]), - ([1., 2., 3.], [3., 4., 5.], [1., 1.5, 2., 2.5, 3.], [3., 3.5, 4., 4.5, 5.]), + 'x,y,xi,yid', + [ + ([1.0, 2.0], [3.0, 4.0], [1.0, 1.5, 2.0], [3.0, 3.5, 4.0]), + ([1.0, 2.0, 3.0], [3.0, 4.0, 5.0], [1.0, 1.5, 2.0, 2.5, 3.0], [3.0, 3.5, 4.0, 4.5, 5.0]), ( - [1., 2., 4., 6.], [2., 4., 5., 7.], np.linspace(1., 6., 10), [ - 2.2579392157892, 3.0231172855707, 3.6937304019483, 4.21971044584031, 4.65026761247821, 5.04804510368134, - 5.47288175793241, 5.94265482897362, 6.44293945952166, 6.95847986982311 - ] + [1.0, 2.0, 4.0, 6.0], + [2.0, 4.0, 5.0, 7.0], + np.linspace(1.0, 6.0, 10), + [ + 2.2579392157892, + 3.0231172855707, + 3.6937304019483, + 4.21971044584031, + 4.65026761247821, + 5.04804510368134, + 5.47288175793241, + 5.94265482897362, + 6.44293945952166, + 6.95847986982311, + ], ), - ] + ], ) def test_npoints(x, y, xi, yid): sp = csaps.CubicSmoothingSpline(x, y) @@ -211,19 +211,29 @@ def test_npoints(x, y, xi, yid): @pytest.mark.parametrize( - 'w,yid', [ + 'w,yid', + [ ( - [0.5, 1, 0.7, 1.2], [ - 2.39572102230177, 3.13781163365086, 3.78568993197139, 4.28992448591238, 4.7009959256016, - 5.08290363789967, 5.49673867759808, 5.9600748344541, 6.45698622142886, 6.97068522346297 - ] + [0.5, 1, 0.7, 1.2], + [ + 2.39572102230177, + 3.13781163365086, + 3.78568993197139, + 4.28992448591238, + 4.7009959256016, + 5.08290363789967, + 5.49673867759808, + 5.9600748344541, + 6.45698622142886, + 6.97068522346297, + ], ) - ] + ], ) def test_weighted(w, yid): - x = [1., 2., 4., 6.] - y = [2., 4., 5., 7.] - xi = np.linspace(1., 6., 10) + x = [1.0, 2.0, 4.0, 6.0] + y = [2.0, 4.0, 5.0, 7.0] + xi = np.linspace(1.0, 6.0, 10) sp = csaps.CubicSmoothingSpline(x, y, weights=w) yi = sp(xi)