summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorCharles Harris <charlesr.harris@gmail.com>2015-01-13 12:08:32 -0500
committerCharles Harris <charlesr.harris@gmail.com>2015-01-13 12:08:32 -0500
commit25ee91be314dff9fe072bcd0c9b7c315fa0f2c65 (patch)
tree6abe9f91d9efaa272d0176ec3b557d0d605c9365 /numpy
parent615bcd163d1c557b88c5f8a7d50128e3cccfd5a6 (diff)
parent29464a96941b61b91d703dc20c3f426466df0c2a (diff)
downloadnumpy-25ee91be314dff9fe072bcd0c9b7c315fa0f2c65.tar.gz
Merge pull request #5361 from JDWarner/arraypad_fixes
ENH: Improve arg handling & enhance test suite for `np.pad`
Diffstat (limited to 'numpy')
-rw-r--r--numpy/lib/arraypad.py134
-rw-r--r--numpy/lib/tests/test_arraypad.py505
2 files changed, 574 insertions, 65 deletions
diff --git a/numpy/lib/arraypad.py b/numpy/lib/arraypad.py
index a48199a82..f70297f48 100644
--- a/numpy/lib/arraypad.py
+++ b/numpy/lib/arraypad.py
@@ -6,7 +6,6 @@ of an n-dimensional array.
from __future__ import division, absolute_import, print_function
import numpy as np
-from numpy.compat import long
__all__ = ['pad']
@@ -47,7 +46,7 @@ def _arange_ndarray(arr, shape, axis, reverse=False):
"""
initshape = tuple(1 if i != axis else shape[axis]
- for (i, x) in enumerate(arr.shape))
+ for (i, x) in enumerate(arr.shape))
if not reverse:
padarr = np.arange(1, shape[axis] + 1)
else:
@@ -779,7 +778,7 @@ def _pad_ref(arr, pad_amt, method, axis=-1):
Notes
-----
This algorithm does not pad with repetition, i.e. the edges are not
- repeated in the reflection. For that behavior, use `method='symmetric'`.
+ repeated in the reflection. For that behavior, use `mode='symmetric'`.
The modes 'reflect', 'symmetric', and 'wrap' must be padded with a
single function, lest the indexing tricks in non-integer multiples of the
@@ -864,7 +863,7 @@ def _pad_sym(arr, pad_amt, method, axis=-1):
Notes
-----
This algorithm DOES pad with repetition, i.e. the edges are repeated.
- For a method that does not repeat edges, use `method='reflect'`.
+ For padding without repeated edges, use `mode='reflect'`.
The modes 'reflect', 'symmetric', and 'wrap' must be padded with a
single function, lest the indexing tricks in non-integer multiples of the
@@ -987,7 +986,7 @@ def _pad_wrap(arr, pad_amt, axis=-1):
return np.concatenate((wrap_chunk1, arr, wrap_chunk2), axis=axis)
-def _normalize_shape(narray, shape):
+def _normalize_shape(ndarray, shape, cast_to_int=True):
"""
Private function which does some checks and normalizes the possibly
much simpler representations of 'pad_width', 'stat_length',
@@ -997,52 +996,77 @@ def _normalize_shape(narray, shape):
----------
narray : ndarray
Input ndarray
- shape : {sequence, int}, optional
- The width of padding (pad_width) or the number of elements on the
- edge of the narray used for statistics (stat_length).
+ shape : {sequence, array_like, float, int}, optional
+ The width of padding (pad_width), the number of elements on the
+ edge of the narray used for statistics (stat_length), the constant
+ value(s) to use when filling padded regions (constant_values), or the
+ endpoint target(s) for linear ramps (end_values).
((before_1, after_1), ... (before_N, after_N)) unique number of
elements for each axis where `N` is rank of `narray`.
((before, after),) yields same before and after constants for each
axis.
- (constant,) or int is a shortcut for before = after = constant for
+ (constant,) or val is a shortcut for before = after = constant for
all axes.
+ cast_to_int : bool, optional
+ Controls if values in ``shape`` will be rounded and cast to int
+ before being returned.
Returns
-------
- _normalize_shape : tuple of tuples
- int => ((int, int), (int, int), ...)
- [[int1, int2], [int3, int4], ...] => ((int1, int2), (int3, int4), ...)
- ((int1, int2), (int3, int4), ...) => no change
- [[int1, int2], ] => ((int1, int2), (int1, int2), ...)
- ((int1, int2), ) => ((int1, int2), (int1, int2), ...)
- [[int , ], ] => ((int, int), (int, int), ...)
- ((int , ), ) => ((int, int), (int, int), ...)
+ normalized_shape : tuple of tuples
+ val => ((val, val), (val, val), ...)
+ [[val1, val2], [val3, val4], ...] => ((val1, val2), (val3, val4), ...)
+ ((val1, val2), (val3, val4), ...) => no change
+ [[val1, val2], ] => ((val1, val2), (val1, val2), ...)
+ ((val1, val2), ) => ((val1, val2), (val1, val2), ...)
+ [[val , ], ] => ((val, val), (val, val), ...)
+ ((val , ), ) => ((val, val), (val, val), ...)
"""
- normshp = None
- shapelen = len(np.shape(narray))
- if (isinstance(shape, int)) or shape is None:
- normshp = ((shape, shape), ) * shapelen
- elif (isinstance(shape, (tuple, list))
- and isinstance(shape[0], (tuple, list))
- and len(shape) == shapelen):
- normshp = shape
- for i in normshp:
- if len(i) != 2:
- fmt = "Unable to create correctly shaped tuple from %s"
- raise ValueError(fmt % (normshp,))
- elif (isinstance(shape, (tuple, list))
- and isinstance(shape[0], (int, float, long))
- and len(shape) == 1):
- normshp = ((shape[0], shape[0]), ) * shapelen
- elif (isinstance(shape, (tuple, list))
- and isinstance(shape[0], (int, float, long))
- and len(shape) == 2):
- normshp = (shape, ) * shapelen
- if normshp is None:
+ ndims = ndarray.ndim
+
+ # Shortcut shape=None
+ if shape is None:
+ return ((None, None), ) * ndims
+
+ # Convert any input `info` to a NumPy array
+ arr = np.asarray(shape)
+
+ # Switch based on what input looks like
+ if arr.ndim <= 1:
+ if arr.shape == () or arr.shape == (1,):
+ # Single scalar input
+ # Create new array of ones, multiply by the scalar
+ arr = np.ones((ndims, 2), dtype=ndarray.dtype) * arr
+ elif arr.shape == (2,):
+ # Apply padding (before, after) each axis
+ # Create new axis 0, repeat along it for every axis
+ arr = arr[np.newaxis, :].repeat(ndims, axis=0)
+ else:
+ fmt = "Unable to create correctly shaped tuple from %s"
+ raise ValueError(fmt % (shape,))
+
+ elif arr.ndim == 2:
+ if arr.shape[1] == 1 and arr.shape[0] == ndims:
+ # Padded before and after by the same amount
+ arr = arr.repeat(2, axis=1)
+ elif arr.shape[0] == ndims:
+ # Input correctly formatted, pass it on as `arr`
+ arr = shape
+ else:
+ fmt = "Unable to create correctly shaped tuple from %s"
+ raise ValueError(fmt % (shape,))
+
+ else:
fmt = "Unable to create correctly shaped tuple from %s"
raise ValueError(fmt % (shape,))
- return normshp
+
+ # Cast if necessary
+ if cast_to_int is True:
+ arr = np.round(arr).astype(int)
+
+ # Convert list of lists to tuple of tuples
+ return tuple(tuple(axis) for axis in arr.tolist())
def _validate_lengths(narray, number_elements):
@@ -1098,7 +1122,7 @@ def pad(array, pad_width, mode=None, **kwargs):
----------
array : array_like of rank N
Input array
- pad_width : {sequence, int}
+ pad_width : {sequence, array_like, int}
Number of values padded to the edges of each axis.
((before_1, after_1), ... (before_N, after_N)) unique pad widths
for each axis.
@@ -1227,13 +1251,13 @@ def pad(array, pad_width, mode=None, **kwargs):
Examples
--------
>>> a = [1, 2, 3, 4, 5]
- >>> np.lib.pad(a, (2,3), 'constant', constant_values=(4,6))
+ >>> np.lib.pad(a, (2,3), 'constant', constant_values=(4, 6))
array([4, 4, 1, 2, 3, 4, 5, 6, 6, 6])
- >>> np.lib.pad(a, (2,3), 'edge')
+ >>> np.lib.pad(a, (2, 3), 'edge')
array([1, 1, 1, 2, 3, 4, 5, 5, 5, 5])
- >>> np.lib.pad(a, (2,3), 'linear_ramp', end_values=(5,-4))
+ >>> np.lib.pad(a, (2, 3), 'linear_ramp', end_values=(5, -4))
array([ 5, 3, 1, 2, 3, 4, 5, 2, -1, -4])
>>> np.lib.pad(a, (2,), 'maximum')
@@ -1245,7 +1269,7 @@ def pad(array, pad_width, mode=None, **kwargs):
>>> np.lib.pad(a, (2,), 'median')
array([3, 3, 1, 2, 3, 4, 5, 3, 3])
- >>> a = [[1,2], [3,4]]
+ >>> a = [[1, 2], [3, 4]]
>>> np.lib.pad(a, ((3, 2), (2, 3)), 'minimum')
array([[1, 1, 1, 2, 1, 1, 1],
[1, 1, 1, 2, 1, 1, 1],
@@ -1256,19 +1280,19 @@ def pad(array, pad_width, mode=None, **kwargs):
[1, 1, 1, 2, 1, 1, 1]])
>>> a = [1, 2, 3, 4, 5]
- >>> np.lib.pad(a, (2,3), 'reflect')
+ >>> np.lib.pad(a, (2, 3), 'reflect')
array([3, 2, 1, 2, 3, 4, 5, 4, 3, 2])
- >>> np.lib.pad(a, (2,3), 'reflect', reflect_type='odd')
+ >>> np.lib.pad(a, (2, 3), 'reflect', reflect_type='odd')
array([-1, 0, 1, 2, 3, 4, 5, 6, 7, 8])
- >>> np.lib.pad(a, (2,3), 'symmetric')
+ >>> np.lib.pad(a, (2, 3), 'symmetric')
array([2, 1, 1, 2, 3, 4, 5, 5, 4, 3])
- >>> np.lib.pad(a, (2,3), 'symmetric', reflect_type='odd')
+ >>> np.lib.pad(a, (2, 3), 'symmetric', reflect_type='odd')
array([0, 1, 1, 2, 3, 4, 5, 5, 6, 7])
- >>> np.lib.pad(a, (2,3), 'wrap')
+ >>> np.lib.pad(a, (2, 3), 'wrap')
array([4, 5, 1, 2, 3, 4, 5, 1, 2, 3])
>>> def padwithtens(vector, pad_width, iaxis, kwargs):
@@ -1277,7 +1301,7 @@ def pad(array, pad_width, mode=None, **kwargs):
... return vector
>>> a = np.arange(6)
- >>> a = a.reshape((2,3))
+ >>> a = a.reshape((2, 3))
>>> np.lib.pad(a, 2, padwithtens)
array([[10, 10, 10, 10, 10, 10, 10],
@@ -1287,6 +1311,8 @@ def pad(array, pad_width, mode=None, **kwargs):
[10, 10, 10, 10, 10, 10, 10],
[10, 10, 10, 10, 10, 10, 10]])
"""
+ if not np.asarray(pad_width).dtype.kind == 'i':
+ raise TypeError('`pad_width` must be of integral type.')
narray = np.array(array)
pad_width = _validate_lengths(narray, pad_width)
@@ -1327,7 +1353,8 @@ def pad(array, pad_width, mode=None, **kwargs):
if i == 'stat_length':
kwargs[i] = _validate_lengths(narray, kwargs[i])
if i in ['end_values', 'constant_values']:
- kwargs[i] = _normalize_shape(narray, kwargs[i])
+ kwargs[i] = _normalize_shape(narray, kwargs[i],
+ cast_to_int=False)
elif mode is None:
raise ValueError('Keyword "mode" must be a function or one of %s.' %
(list(allowedkwargs.keys()),))
@@ -1420,7 +1447,6 @@ def pad(array, pad_width, mode=None, **kwargs):
method = kwargs['reflect_type']
safe_pad = newmat.shape[axis] - 1
while ((pad_before > safe_pad) or (pad_after > safe_pad)):
- offset = 0
pad_iter_b = min(safe_pad,
safe_pad * (pad_before // safe_pad))
pad_iter_a = min(safe_pad, safe_pad * (pad_after // safe_pad))
@@ -1428,10 +1454,6 @@ def pad(array, pad_width, mode=None, **kwargs):
pad_iter_a), method, axis)
pad_before -= pad_iter_b
pad_after -= pad_iter_a
- if pad_iter_b > 0:
- offset += 1
- if pad_iter_a > 0:
- offset += 1
safe_pad += pad_iter_b + pad_iter_a
newmat = _pad_ref(newmat, (pad_before, pad_after), method, axis)
diff --git a/numpy/lib/tests/test_arraypad.py b/numpy/lib/tests/test_arraypad.py
index f8ba8643a..11d2c70b1 100644
--- a/numpy/lib/tests/test_arraypad.py
+++ b/numpy/lib/tests/test_arraypad.py
@@ -1,14 +1,57 @@
-"""Tests for the pad functions.
+"""Tests for the array padding functions.
"""
from __future__ import division, absolute_import, print_function
-from numpy.testing import TestCase, run_module_suite, assert_array_equal
-from numpy.testing import assert_raises, assert_array_almost_equal
import numpy as np
+from numpy.testing import (assert_array_equal, assert_raises, assert_allclose,
+ TestCase)
from numpy.lib import pad
+class TestConditionalShortcuts(TestCase):
+ def test_zero_padding_shortcuts(self):
+ test = np.arange(120).reshape(4, 5, 6)
+ pad_amt = [(0, 0) for axis in test.shape]
+ modes = ['constant',
+ 'edge',
+ 'linear_ramp',
+ 'maximum',
+ 'mean',
+ 'median',
+ 'minimum',
+ 'reflect',
+ 'symmetric',
+ 'wrap',
+ ]
+ for mode in modes:
+ assert_array_equal(test, pad(test, pad_amt, mode=mode))
+
+ def test_shallow_statistic_range(self):
+ test = np.arange(120).reshape(4, 5, 6)
+ pad_amt = [(1, 1) for axis in test.shape]
+ modes = ['maximum',
+ 'mean',
+ 'median',
+ 'minimum',
+ ]
+ for mode in modes:
+ assert_array_equal(pad(test, pad_amt, mode='edge'),
+ pad(test, pad_amt, mode=mode, stat_length=1))
+
+ def test_clip_statistic_range(self):
+ test = np.arange(30).reshape(5, 6)
+ pad_amt = [(3, 3) for axis in test.shape]
+ modes = ['maximum',
+ 'mean',
+ 'median',
+ 'minimum',
+ ]
+ for mode in modes:
+ assert_array_equal(pad(test, pad_amt, mode=mode),
+ pad(test, pad_amt, mode=mode, stat_length=30))
+
+
class TestStatistic(TestCase):
def test_check_mean_stat_length(self):
a = np.arange(100).astype('f')
@@ -82,6 +125,30 @@ class TestStatistic(TestCase):
)
assert_array_equal(a, b)
+ def test_check_maximum_stat_length(self):
+ a = np.arange(100) + 1
+ a = pad(a, (25, 20), 'maximum', stat_length=10)
+ b = np.array(
+ [10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10,
+
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+ 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
+ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
+ 91, 92, 93, 94, 95, 96, 97, 98, 99, 100,
+
+ 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
+ 100, 100, 100, 100, 100, 100, 100, 100, 100, 100]
+ )
+ assert_array_equal(a, b)
+
def test_check_minimum_1(self):
a = np.arange(100)
a = pad(a, (25, 20), 'minimum')
@@ -130,6 +197,30 @@ class TestStatistic(TestCase):
)
assert_array_equal(a, b)
+ def test_check_minimum_stat_length(self):
+ a = np.arange(100) + 1
+ a = pad(a, (25, 20), 'minimum', stat_length=10)
+ b = np.array(
+ [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1,
+
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+ 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
+ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
+ 91, 92, 93, 94, 95, 96, 97, 98, 99, 100,
+
+ 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
+ 91, 91, 91, 91, 91, 91, 91, 91, 91, 91]
+ )
+ assert_array_equal(a, b)
+
def test_check_median(self):
a = np.arange(100).astype('f')
a = pad(a, (25, 20), 'median')
@@ -182,6 +273,32 @@ class TestStatistic(TestCase):
)
assert_array_equal(a, b)
+ def test_check_median_stat_length(self):
+ a = np.arange(100).astype('f')
+ a[1] = 2.
+ a[97] = 96.
+ a = pad(a, (25, 20), 'median', stat_length=(3, 5))
+ b = np.array(
+ [ 2., 2., 2., 2., 2., 2., 2., 2., 2., 2.,
+ 2., 2., 2., 2., 2., 2., 2., 2., 2., 2.,
+ 2., 2., 2., 2., 2.,
+
+ 0., 2., 2., 3., 4., 5., 6., 7., 8., 9.,
+ 10., 11., 12., 13., 14., 15., 16., 17., 18., 19.,
+ 20., 21., 22., 23., 24., 25., 26., 27., 28., 29.,
+ 30., 31., 32., 33., 34., 35., 36., 37., 38., 39.,
+ 40., 41., 42., 43., 44., 45., 46., 47., 48., 49.,
+ 50., 51., 52., 53., 54., 55., 56., 57., 58., 59.,
+ 60., 61., 62., 63., 64., 65., 66., 67., 68., 69.,
+ 70., 71., 72., 73., 74., 75., 76., 77., 78., 79.,
+ 80., 81., 82., 83., 84., 85., 86., 87., 88., 89.,
+ 90., 91., 92., 93., 94., 95., 96., 96., 98., 99.,
+
+ 96., 96., 96., 96., 96., 96., 96., 96., 96., 96.,
+ 96., 96., 96., 96., 96., 96., 96., 96., 96., 96.]
+ )
+ assert_array_equal(a, b)
+
def test_check_mean_shape_one(self):
a = [[4, 5, 6]]
a = pad(a, (5, 7), 'mean', stat_length=2)
@@ -254,6 +371,112 @@ class TestConstant(TestCase):
)
assert_array_equal(a, b)
+ def test_check_constant_zeros(self):
+ a = np.arange(100)
+ a = pad(a, (25, 20), 'constant')
+ b = 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, 0, 0,
+
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
+ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+ )
+ assert_array_equal(a, b)
+
+ def test_check_constant_float(self):
+ # If input array is int, but constant_values are float, the dtype of
+ # the array to be padded is kept
+ arr = np.arange(30).reshape(5, 6)
+ test = pad(arr, (1, 2), mode='constant',
+ constant_values=1.1)
+ expected = np.array(
+ [[ 1, 1, 1, 1, 1, 1, 1, 1, 1],
+
+ [ 1, 0, 1, 2, 3, 4, 5, 1, 1],
+ [ 1, 6, 7, 8, 9, 10, 11, 1, 1],
+ [ 1, 12, 13, 14, 15, 16, 17, 1, 1],
+ [ 1, 18, 19, 20, 21, 22, 23, 1, 1],
+ [ 1, 24, 25, 26, 27, 28, 29, 1, 1],
+
+ [ 1, 1, 1, 1, 1, 1, 1, 1, 1],
+ [ 1, 1, 1, 1, 1, 1, 1, 1, 1]]
+ )
+ assert_allclose(test, expected)
+
+ def test_check_constant_float2(self):
+ # If input array is float, and constant_values are float, the dtype of
+ # the array to be padded is kept - here retaining the float constants
+ arr = np.arange(30).reshape(5, 6)
+ arr_float = arr.astype(np.float64)
+ test = pad(arr_float, ((1, 2), (1, 2)), mode='constant',
+ constant_values=1.1)
+ expected = np.array(
+ [[ 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1],
+
+ [ 1.1, 0. , 1. , 2. , 3. , 4. , 5. , 1.1, 1.1],
+ [ 1.1, 6. , 7. , 8. , 9. , 10. , 11. , 1.1, 1.1],
+ [ 1.1, 12. , 13. , 14. , 15. , 16. , 17. , 1.1, 1.1],
+ [ 1.1, 18. , 19. , 20. , 21. , 22. , 23. , 1.1, 1.1],
+ [ 1.1, 24. , 25. , 26. , 27. , 28. , 29. , 1.1, 1.1],
+
+ [ 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1],
+ [ 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1]]
+ )
+ assert_allclose(test, expected)
+
+ def test_check_constant_float3(self):
+ a = np.arange(100, dtype=float)
+ a = pad(a, (25, 20), 'constant', constant_values=(-1.1, -1.2))
+ b = np.array(
+ [-1.1, -1.1, -1.1, -1.1, -1.1, -1.1, -1.1, -1.1, -1.1, -1.1,
+ -1.1, -1.1, -1.1, -1.1, -1.1, -1.1, -1.1, -1.1, -1.1, -1.1,
+ -1.1, -1.1, -1.1, -1.1, -1.1,
+
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
+ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+
+ -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2,
+ -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2]
+ )
+ assert_allclose(a, b)
+
+ def test_check_constant_odd_pad_amount(self):
+ arr = np.arange(30).reshape(5, 6)
+ test = pad(arr, ((1,), (2,)), mode='constant',
+ constant_values=3)
+ expected = np.array(
+ [[ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
+
+ [ 3, 3, 0, 1, 2, 3, 4, 5, 3, 3],
+ [ 3, 3, 6, 7, 8, 9, 10, 11, 3, 3],
+ [ 3, 3, 12, 13, 14, 15, 16, 17, 3, 3],
+ [ 3, 3, 18, 19, 20, 21, 22, 23, 3, 3],
+ [ 3, 3, 24, 25, 26, 27, 28, 29, 3, 3],
+
+ [ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]]
+ )
+ assert_allclose(test, expected)
+
class TestLinearRamp(TestCase):
def test_check_simple(self):
@@ -278,7 +501,21 @@ class TestLinearRamp(TestCase):
94.3, 89.6, 84.9, 80.2, 75.5, 70.8, 66.1, 61.4, 56.7, 52.0,
47.3, 42.6, 37.9, 33.2, 28.5, 23.8, 19.1, 14.4, 9.7, 5.]
)
- assert_array_almost_equal(a, b, decimal=5)
+ assert_allclose(a, b, rtol=1e-5, atol=1e-5)
+
+ def test_check_2d(self):
+ arr = np.arange(20).reshape(4, 5).astype(np.float64)
+ test = pad(arr, (2, 2), mode='linear_ramp', end_values=(0, 0))
+ expected = np.array(
+ [[0., 0., 0., 0., 0., 0., 0., 0., 0.],
+ [0., 0., 0., 0.5, 1., 1.5, 2., 1., 0.],
+ [0., 0., 0., 1., 2., 3., 4., 2., 0.],
+ [0., 2.5, 5., 6., 7., 8., 9., 4.5, 0.],
+ [0., 5., 10., 11., 12., 13., 14., 7., 0.],
+ [0., 7.5, 15., 16., 17., 18., 19., 9.5, 0.],
+ [0., 3.75, 7.5, 8., 8.5, 9., 9.5, 4.75, 0.],
+ [0., 0., 0., 0., 0., 0., 0., 0., 0.]])
+ assert_allclose(test, expected)
class TestReflect(TestCase):
@@ -306,6 +543,30 @@ class TestReflect(TestCase):
)
assert_array_equal(a, b)
+ def test_check_odd_method(self):
+ a = np.arange(100)
+ a = pad(a, (25, 20), 'reflect', reflect_type='odd')
+ b = np.array(
+ [-25, -24, -23, -22, -21, -20, -19, -18, -17, -16,
+ -15, -14, -13, -12, -11, -10, -9, -8, -7, -6,
+ -5, -4, -3, -2, -1,
+
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
+ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+
+ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 112, 113, 114, 115, 116, 117, 118, 119]
+ )
+ assert_array_equal(a, b)
+
def test_check_large_pad(self):
a = [[4, 5, 6], [6, 7, 8]]
a = pad(a, (5, 7), 'reflect')
@@ -367,6 +628,140 @@ class TestReflect(TestCase):
assert_array_equal(a, b)
+class TestSymmetric(TestCase):
+ def test_check_simple(self):
+ a = np.arange(100)
+ a = pad(a, (25, 20), 'symmetric')
+ b = np.array(
+ [24, 23, 22, 21, 20, 19, 18, 17, 16, 15,
+ 14, 13, 12, 11, 10, 9, 8, 7, 6, 5,
+ 4, 3, 2, 1, 0,
+
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
+ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+
+ 99, 98, 97, 96, 95, 94, 93, 92, 91, 90,
+ 89, 88, 87, 86, 85, 84, 83, 82, 81, 80]
+ )
+ assert_array_equal(a, b)
+
+ def test_check_odd_method(self):
+ a = np.arange(100)
+ a = pad(a, (25, 20), 'symmetric', reflect_type='odd')
+ b = np.array(
+ [-24, -23, -22, -21, -20, -19, -18, -17, -16, -15,
+ -14, -13, -12, -11, -10, -9, -8, -7, -6, -5,
+ -4, -3, -2, -1, 0,
+
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
+ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+
+ 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
+ 109, 110, 111, 112, 113, 114, 115, 116, 117, 118]
+ )
+ assert_array_equal(a, b)
+
+ def test_check_large_pad(self):
+ a = [[4, 5, 6], [6, 7, 8]]
+ a = pad(a, (5, 7), 'symmetric')
+ b = np.array(
+ [[5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6],
+ [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6],
+ [7, 8, 8, 7, 6, 6, 7, 8, 8, 7, 6, 6, 7, 8, 8],
+ [7, 8, 8, 7, 6, 6, 7, 8, 8, 7, 6, 6, 7, 8, 8],
+ [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6],
+
+ [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6],
+ [7, 8, 8, 7, 6, 6, 7, 8, 8, 7, 6, 6, 7, 8, 8],
+
+ [7, 8, 8, 7, 6, 6, 7, 8, 8, 7, 6, 6, 7, 8, 8],
+ [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6],
+ [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6],
+ [7, 8, 8, 7, 6, 6, 7, 8, 8, 7, 6, 6, 7, 8, 8],
+ [7, 8, 8, 7, 6, 6, 7, 8, 8, 7, 6, 6, 7, 8, 8],
+ [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6],
+ [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6]]
+ )
+
+ assert_array_equal(a, b)
+
+ def test_check_large_pad_odd(self):
+ a = [[4, 5, 6], [6, 7, 8]]
+ a = pad(a, (5, 7), 'symmetric', reflect_type='odd')
+ b = np.array(
+ [[-3, -2, -2, -1, 0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6],
+ [-3, -2, -2, -1, 0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6],
+ [-1, 0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8],
+ [-1, 0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8],
+ [ 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10],
+
+ [ 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10],
+ [ 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10, 11, 12, 12],
+
+ [ 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10, 11, 12, 12],
+ [ 5, 6, 6, 7, 8, 8, 9, 10, 10, 11, 12, 12, 13, 14, 14],
+ [ 5, 6, 6, 7, 8, 8, 9, 10, 10, 11, 12, 12, 13, 14, 14],
+ [ 7, 8, 8, 9, 10, 10, 11, 12, 12, 13, 14, 14, 15, 16, 16],
+ [ 7, 8, 8, 9, 10, 10, 11, 12, 12, 13, 14, 14, 15, 16, 16],
+ [ 9, 10, 10, 11, 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18],
+ [ 9, 10, 10, 11, 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18]]
+ )
+ assert_array_equal(a, b)
+
+ def test_check_shape(self):
+ a = [[4, 5, 6]]
+ a = pad(a, (5, 7), 'symmetric')
+ b = np.array(
+ [[5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6],
+ [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6],
+ [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6],
+ [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6],
+ [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6],
+
+ [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6],
+ [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6],
+
+ [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6],
+ [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6],
+ [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6],
+ [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6],
+ [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6],
+ [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6]]
+ )
+ assert_array_equal(a, b)
+
+ def test_check_01(self):
+ a = pad([1, 2, 3], 2, 'symmetric')
+ b = np.array([2, 1, 1, 2, 3, 3, 2])
+ assert_array_equal(a, b)
+
+ def test_check_02(self):
+ a = pad([1, 2, 3], 3, 'symmetric')
+ b = np.array([3, 2, 1, 1, 2, 3, 3, 2, 1])
+ assert_array_equal(a, b)
+
+ def test_check_03(self):
+ a = pad([1, 2, 3], 6, 'symmetric')
+ b = np.array([1, 2, 3, 3, 2, 1, 1, 2, 3, 3, 2, 1, 1, 2, 3])
+ assert_array_equal(a, b)
+
+
class TestWrap(TestCase):
def test_check_simple(self):
a = np.arange(100)
@@ -515,6 +910,49 @@ class TestZeroPadWidth(TestCase):
assert_array_equal(arr, pad(arr, pad_width, mode='constant'))
+class TestLegacyVectorFunction(TestCase):
+ def test_legacy_vector_functionality(self):
+ def _padwithtens(vector, pad_width, iaxis, kwargs):
+ vector[:pad_width[0]] = 10
+ vector[-pad_width[1]:] = 10
+ return vector
+
+ a = np.arange(6).reshape(2, 3)
+ a = pad(a, 2, _padwithtens)
+ b = np.array(
+ [[10, 10, 10, 10, 10, 10, 10],
+ [10, 10, 10, 10, 10, 10, 10],
+
+ [10, 10, 0, 1, 2, 10, 10],
+ [10, 10, 3, 4, 5, 10, 10],
+
+ [10, 10, 10, 10, 10, 10, 10],
+ [10, 10, 10, 10, 10, 10, 10]]
+ )
+ assert_array_equal(a, b)
+
+
+class TestNdarrayPadWidth(TestCase):
+ def test_check_simple(self):
+ a = np.arange(12)
+ a = np.reshape(a, (4, 3))
+ a = pad(a, np.array(((2, 3), (3, 2))), 'edge')
+ b = np.array(
+ [[0, 0, 0, 0, 1, 2, 2, 2],
+ [0, 0, 0, 0, 1, 2, 2, 2],
+
+ [0, 0, 0, 0, 1, 2, 2, 2],
+ [3, 3, 3, 3, 4, 5, 5, 5],
+ [6, 6, 6, 6, 7, 8, 8, 8],
+ [9, 9, 9, 9, 10, 11, 11, 11],
+
+ [9, 9, 9, 9, 10, 11, 11, 11],
+ [9, 9, 9, 9, 10, 11, 11, 11],
+ [9, 9, 9, 9, 10, 11, 11, 11]]
+ )
+ assert_array_equal(a, b)
+
+
class ValueError1(TestCase):
def test_check_simple(self):
arr = np.arange(30)
@@ -539,22 +977,71 @@ class ValueError1(TestCase):
class ValueError2(TestCase):
- def test_check_simple(self):
+ def test_check_negative_pad_amount(self):
arr = np.arange(30)
arr = np.reshape(arr, (6, 5))
kwargs = dict(mode='mean', stat_length=(3, ))
- assert_raises(ValueError, pad, arr, ((2, 3, 4), (3, 2)),
+ assert_raises(ValueError, pad, arr, ((-2, 3), (3, 2)),
**kwargs)
class ValueError3(TestCase):
- def test_check_simple(self):
+ def test_check_kwarg_not_allowed(self):
+ arr = np.arange(30).reshape(5, 6)
+ assert_raises(ValueError, pad, arr, 4, mode='mean',
+ reflect_type='odd')
+
+ def test_mode_not_set(self):
+ arr = np.arange(30).reshape(5, 6)
+ assert_raises(ValueError, pad, arr, 4)
+
+ def test_malformed_pad_amount(self):
+ arr = np.arange(30).reshape(5, 6)
+ assert_raises(ValueError, pad, arr, (4, 5, 6, 7), mode='constant')
+
+ def test_malformed_pad_amount2(self):
+ arr = np.arange(30).reshape(5, 6)
+ assert_raises(ValueError, pad, arr, ((3, 4, 5), (0, 1, 2)),
+ mode='constant')
+
+ def test_pad_too_many_axes(self):
+ arr = np.arange(30).reshape(5, 6)
+
+ # Attempt to pad using a 3D array equivalent
+ bad_shape = (((3,), (4,), (5,)), ((0,), (1,), (2,)))
+ assert_raises(ValueError, pad, arr, bad_shape,
+ mode='constant')
+
+
+class TypeError1(TestCase):
+ def test_float(self):
+ arr = np.arange(30)
+ assert_raises(TypeError, pad, arr, ((-2.1, 3), (3, 2)))
+ assert_raises(TypeError, pad, arr, np.array(((-2.1, 3), (3, 2))))
+
+ def test_str(self):
+ arr = np.arange(30)
+ assert_raises(TypeError, pad, arr, 'foo')
+ assert_raises(TypeError, pad, arr, np.array('foo'))
+
+ def test_object(self):
+ class FooBar(object):
+ pass
+ arr = np.arange(30)
+ assert_raises(TypeError, pad, arr, FooBar())
+
+ def test_complex(self):
+ arr = np.arange(30)
+ assert_raises(TypeError, pad, arr, complex(1, -1))
+ assert_raises(TypeError, pad, arr, np.array(complex(1, -1)))
+
+ def test_check_wrong_pad_amount(self):
arr = np.arange(30)
arr = np.reshape(arr, (6, 5))
kwargs = dict(mode='mean', stat_length=(3, ))
- assert_raises(ValueError, pad, arr, ((-2, 3), (3, 2)),
+ assert_raises(TypeError, pad, arr, ((2, 3, 4), (3, 2)),
**kwargs)
if __name__ == "__main__":
- run_module_suite()
+ np.testing.run_module_suite()