import unittest import warnings import numpy import pytest import cupy from cupy import testing @testing.parameterize( *testing.product({ 'array': [numpy.arange(6).reshape([2, 3])], 'pad_width': [1, [1, 2], [[1, 2], [3, 4]]], # mode 'mean' is non-exact, so it is tested in a separate class 'mode': ['constant', 'edge', 'linear_ramp', 'maximum', 'minimum', 'reflect', 'symmetric', 'wrap'], }) ) class TestPadDefault(unittest.TestCase): @testing.for_all_dtypes(no_bool=True) @testing.numpy_cupy_array_equal() def test_pad_default(self, xp, dtype): array = xp.array(self.array, dtype=dtype) if (xp.dtype(dtype).kind in ['i', 'u'] and self.mode == 'linear_ramp'): # TODO: can remove this skip once cupy/cupy/#2330 is merged return array # Older version of NumPy(<1.12) can emit ComplexWarning def f(): return xp.pad(array, self.pad_width, mode=self.mode) if xp is numpy: with warnings.catch_warnings(): warnings.simplefilter('ignore', numpy.ComplexWarning) return f() else: return f() @testing.parameterize( *testing.product({ 'array': [numpy.arange(6).reshape([2, 3])], 'pad_width': [1, [1, 2], [[1, 2], [3, 4]]], }) ) class TestPadDefaultMean(unittest.TestCase): @testing.for_all_dtypes(no_bool=True) @testing.numpy_cupy_array_almost_equal(decimal=5) def test_pad_default(self, xp, dtype): array = xp.array(self.array, dtype=dtype) if xp.dtype(dtype).kind in ['i', 'u']: # TODO: can remove this skip once cupy/cupy/#2330 is merged return array # Older version of NumPy(<1.12) can emit ComplexWarning def f(): return xp.pad(array, self.pad_width, mode='mean') if xp is numpy: with warnings.catch_warnings(): warnings.simplefilter('ignore', numpy.ComplexWarning) return f() else: return f() @testing.parameterize( # mode='constant' {'array': numpy.arange(6).reshape([2, 3]), 'pad_width': 1, 'mode': 'constant', 'constant_values': 3}, {'array': numpy.arange(6).reshape([2, 3]), 'pad_width': [1, 2], 'mode': 'constant', 'constant_values': [3, 4]}, {'array': numpy.arange(6).reshape([2, 3]), 'pad_width': [[1, 2], [3, 4]], 'mode': 'constant', 'constant_values': [[3, 4], [5, 6]]}, # mode='reflect' {'array': numpy.arange(6).reshape([2, 3]), 'pad_width': 1, 'mode': 'reflect', 'reflect_type': 'odd'}, {'array': numpy.arange(6).reshape([2, 3]), 'pad_width': [1, 2], 'mode': 'reflect', 'reflect_type': 'odd'}, {'array': numpy.arange(6).reshape([2, 3]), 'pad_width': [[1, 2], [3, 4]], 'mode': 'reflect', 'reflect_type': 'odd'}, # mode='symmetric' {'array': numpy.arange(6).reshape([2, 3]), 'pad_width': 1, 'mode': 'symmetric', 'reflect_type': 'odd'}, {'array': numpy.arange(6).reshape([2, 3]), 'pad_width': [1, 2], 'mode': 'symmetric', 'reflect_type': 'odd'}, {'array': numpy.arange(6).reshape([2, 3]), 'pad_width': [[1, 2], [3, 4]], 'mode': 'symmetric', 'reflect_type': 'odd'}, # mode='minimum' {'array': numpy.arange(60).reshape([5, 12]), 'pad_width': 1, 'mode': 'minimum', 'stat_length': 2}, {'array': numpy.arange(60).reshape([5, 12]), 'pad_width': [1, 2], 'mode': 'minimum', 'stat_length': (2, 4)}, {'array': numpy.arange(60).reshape([5, 12]), 'pad_width': [[1, 2], [3, 4]], 'mode': 'minimum', 'stat_length': ((2, 4), (3, 5))}, {'array': numpy.arange(60).reshape([5, 12]), 'pad_width': [[1, 2], [3, 4]], 'mode': 'minimum', 'stat_length': None}, # mode='maximum' {'array': numpy.arange(60).reshape([5, 12]), 'pad_width': 1, 'mode': 'maximum', 'stat_length': 2}, {'array': numpy.arange(60).reshape([5, 12]), 'pad_width': [1, 2], 'mode': 'maximum', 'stat_length': (2, 4)}, {'array': numpy.arange(60).reshape([5, 12]), 'pad_width': [[1, 2], [3, 4]], 'mode': 'maximum', 'stat_length': ((2, 4), (3, 5))}, {'array': numpy.arange(60).reshape([5, 12]), 'pad_width': [[1, 2], [3, 4]], 'mode': 'maximum', 'stat_length': None}, ) # Old numpy does not work with multi-dimensional constant_values class TestPad(unittest.TestCase): @testing.for_all_dtypes(no_bool=True) @testing.numpy_cupy_array_equal() def test_pad(self, xp, dtype): array = xp.array(self.array, dtype=dtype) # Older version of NumPy(<1.12) can emit ComplexWarning def f(): if self.mode == 'constant': return xp.pad(array, self.pad_width, mode=self.mode, constant_values=self.constant_values) elif self.mode in ['minimum', 'maximum']: return xp.pad(array, self.pad_width, mode=self.mode, stat_length=self.stat_length) elif self.mode in ['reflect', 'symmetric']: return xp.pad(array, self.pad_width, mode=self.mode, reflect_type=self.reflect_type) if xp is numpy: with warnings.catch_warnings(): warnings.simplefilter('ignore', numpy.ComplexWarning) return f() else: return f() @testing.parameterize( # mode='mean' {'array': numpy.arange(60).reshape([5, 12]), 'pad_width': 1, 'mode': 'mean', 'stat_length': 2}, {'array': numpy.arange(60).reshape([5, 12]), 'pad_width': [1, 2], 'mode': 'mean', 'stat_length': (2, 4)}, {'array': numpy.arange(60).reshape([5, 12]), 'pad_width': [[1, 2], [3, 4]], 'mode': 'mean', 'stat_length': ((2, 4), (3, 5))}, {'array': numpy.arange(60).reshape([5, 12]), 'pad_width': [[1, 2], [3, 4]], 'mode': 'mean', 'stat_length': None}, ) # Old numpy does not work with multi-dimensional constant_values class TestPadMean(unittest.TestCase): @testing.for_all_dtypes(no_bool=True) @testing.numpy_cupy_array_almost_equal(decimal=5) def test_pad(self, xp, dtype): array = xp.array(self.array, dtype=dtype) if xp.dtype(dtype).kind in ['i', 'u']: # TODO: can remove this skip once cupy/cupy/#2330 is merged return array # Older version of NumPy(<1.12) can emit ComplexWarning def f(): return xp.pad(array, self.pad_width, mode=self.mode, stat_length=self.stat_length) if xp is numpy: with warnings.catch_warnings(): warnings.simplefilter('ignore', numpy.ComplexWarning) return f() else: return f() class TestPadNumpybug(unittest.TestCase): @testing.for_all_dtypes(no_bool=True, no_complex=True) @testing.numpy_cupy_array_equal() def test_pad_highdim_default(self, xp, dtype): array = xp.arange(6, dtype=dtype).reshape([2, 3]) pad_width = [[1, 2], [3, 4]] constant_values = [[1, 2], [3, 4]] a = xp.pad(array, pad_width, mode='constant', constant_values=constant_values) return a class TestPadEmpty(unittest.TestCase): @testing.with_requires('numpy>=1.17') @testing.for_all_dtypes(no_bool=True) @testing.numpy_cupy_array_equal() def test_pad_empty(self, xp, dtype): array = xp.arange(6, dtype=dtype).reshape([2, 3]) pad_width = 2 a = xp.pad(array, pad_width=pad_width, mode='empty') # omit uninitialized "empty" boundary from the comparison return a[pad_width:-pad_width, pad_width:-pad_width] class TestPadCustomFunction(unittest.TestCase): @testing.for_all_dtypes(no_bool=True) @testing.numpy_cupy_array_equal() def test_pad_via_func(self, xp, dtype): def _padwithtens(vector, pad_width, iaxis, kwargs): vector[:pad_width[0]] = 10 vector[-pad_width[1]:] = 10 a = xp.arange(6, dtype=dtype).reshape(2, 3) a = xp.pad(a, 2, _padwithtens) return a @testing.parameterize( # mode='constant' {'array': [], 'pad_width': 1, 'mode': 'constant', 'constant_values': 3}, {'array': 1, 'pad_width': 1, 'mode': 'constant', 'constant_values': 3}, {'array': [0, 1, 2, 3], 'pad_width': 1, 'mode': 'constant', 'constant_values': 3}, {'array': [0, 1, 2, 3], 'pad_width': [1, 2], 'mode': 'constant', 'constant_values': 3}, # mode='edge' {'array': 1, 'pad_width': 1, 'mode': 'edge'}, {'array': [0, 1, 2, 3], 'pad_width': 1, 'mode': 'edge'}, {'array': [0, 1, 2, 3], 'pad_width': [1, 2], 'mode': 'edge'}, # mode='reflect' {'array': 1, 'pad_width': 1, 'mode': 'reflect'}, {'array': [0, 1, 2, 3], 'pad_width': 1, 'mode': 'reflect'}, {'array': [0, 1, 2, 3], 'pad_width': [1, 2], 'mode': 'reflect'}, ) class TestPadSpecial(unittest.TestCase): @testing.numpy_cupy_array_equal() def test_pad_special(self, xp): array = xp.array(self.array) if self.mode == 'constant': a = xp.pad(array, self.pad_width, mode=self.mode, constant_values=self.constant_values) elif self.mode in ['edge', 'reflect']: a = xp.pad(array, self.pad_width, mode=self.mode) return a @testing.parameterize( {'array': [0, 1, 2, 3], 'pad_width': [-1, 1], 'mode': 'constant', 'kwargs': {'constant_values': 3}}, {'array': [0, 1, 2, 3], 'pad_width': [[3, 4], [5, 6]], 'mode': 'constant', 'kwargs': {'constant_values': 3}}, {'array': [0, 1, 2, 3], 'pad_width': [1], 'mode': 'constant', 'kwargs': {'notallowedkeyword': 3}}, # edge {'array': [], 'pad_width': 1, 'mode': 'edge', 'kwargs': {}}, {'array': [0, 1, 2, 3], 'pad_width': [-1, 1], 'mode': 'edge', 'kwargs': {}}, {'array': [0, 1, 2, 3], 'pad_width': [[3, 4], [5, 6]], 'mode': 'edge', 'kwargs': {}}, {'array': [0, 1, 2, 3], 'pad_width': [1], 'mode': 'edge', 'kwargs': {'notallowedkeyword': 3}}, # mode='reflect' {'array': [], 'pad_width': 1, 'mode': 'reflect', 'kwargs': {}}, {'array': [0, 1, 2, 3], 'pad_width': [-1, 1], 'mode': 'reflect', 'kwargs': {}}, {'array': [0, 1, 2, 3], 'pad_width': [[3, 4], [5, 6]], 'mode': 'reflect', 'kwargs': {}}, {'array': [0, 1, 2, 3], 'pad_width': [1], 'mode': 'reflect', 'kwargs': {'notallowedkeyword': 3}}, ) @testing.with_requires('numpy>=1.17') class TestPadValueError(unittest.TestCase): def test_pad_failure(self): for xp in (numpy, cupy): array = xp.array(self.array) with pytest.raises(ValueError): xp.pad(array, self.pad_width, self.mode, **self.kwargs) @testing.parameterize( {'array': [0, 1, 2, 3], 'pad_width': [], 'mode': 'constant', 'kwargs': {'constant_values': 3}}, # edge {'array': [0, 1, 2, 3], 'pad_width': [], 'mode': 'edge', 'kwargs': {}}, # mode='reflect' {'array': [0, 1, 2, 3], 'pad_width': [], 'mode': 'reflect', 'kwargs': {}}, ) class TestPadTypeError(unittest.TestCase): def test_pad_failure(self): for xp in (numpy, cupy): array = xp.array(self.array) with pytest.raises(TypeError): xp.pad(array, self.pad_width, self.mode, **self.kwargs)