diff options
-rw-r--r-- | doc/release/2.0.0-notes.rst | 12 | ||||
-rw-r--r-- | doc/source/reference/routines.padding.rst | 9 | ||||
-rw-r--r-- | doc/source/reference/routines.rst | 45 | ||||
-rw-r--r-- | numpy/lib/__init__.py | 2 | ||||
-rw-r--r-- | numpy/lib/arraypad.py | 767 | ||||
-rw-r--r-- | numpy/lib/tests/test_arraypad.py | 530 |
6 files changed, 1343 insertions, 22 deletions
diff --git a/doc/release/2.0.0-notes.rst b/doc/release/2.0.0-notes.rst index e9fd7f90a..b25643364 100644 --- a/doc/release/2.0.0-notes.rst +++ b/doc/release/2.0.0-notes.rst @@ -129,6 +129,18 @@ Support for mask-based NA values in the polynomial package fits The fitting functions recognize and remove masked data from the fit. +Ability to pad rank-n arrays +---------------------------- + +A pad module containing functions for padding n-dimensional arrays has +been added. The various private padding functions are exposed as options to +a public 'pad' function. Example: + +pad(a, 5, mode='mean') + +Current modes are 'constant', 'edge', 'linear_ramp', 'maximum', 'mean', +'median', 'minimum', 'reflect', 'symmetric', 'wrap', and <function> + New argument to searchsorted ---------------------------- diff --git a/doc/source/reference/routines.padding.rst b/doc/source/reference/routines.padding.rst new file mode 100644 index 000000000..38706edea --- /dev/null +++ b/doc/source/reference/routines.padding.rst @@ -0,0 +1,9 @@ +Padding Arrays +============== + +.. currentmodule:: numpy + +.. autosummary:: + :toctree: generated/ + + pad diff --git a/doc/source/reference/routines.rst b/doc/source/reference/routines.rst index 14b4f4d04..10d12330c 100644 --- a/doc/source/reference/routines.rst +++ b/doc/source/reference/routines.rst @@ -17,33 +17,34 @@ indentation. routines.array-creation routines.array-manipulation - routines.indexing + routines.bitwise + routines.char + routines.ctypeslib + routines.datetime routines.dtype - routines.io + routines.dual + routines.emath + routines.err routines.fft + routines.financial + routines.functional + routines.help + routines.indexing + routines.io routines.linalg - routines.random - routines.sort routines.logic - routines.bitwise - routines.statistics - routines.math - routines.functional - routines.polynomials - routines.datetime - routines.financial - routines.set - routines.window - routines.err - routines.maskna routines.ma - routines.help - routines.other - routines.testing - routines.emath + routines.maskna + routines.math routines.matlib - routines.dual routines.numarray routines.oldnumeric - routines.ctypeslib - routines.char + routines.other + routines.padding + routines.polynomials + routines.random + routines.set + routines.sort + routines.statistics + routines.testing + routines.window diff --git a/numpy/lib/__init__.py b/numpy/lib/__init__.py index 1fd94a013..17557605d 100644 --- a/numpy/lib/__init__.py +++ b/numpy/lib/__init__.py @@ -18,6 +18,7 @@ from npyio import * from financial import * import math from arrayterator import * +from arraypad import * __all__ = ['emath','math'] __all__ += type_check.__all__ @@ -27,6 +28,7 @@ __all__ += shape_base.__all__ __all__ += stride_tricks.__all__ __all__ += twodim_base.__all__ __all__ += ufunclike.__all__ +__all__ += arraypad.__all__ __all__ += polynomial.__all__ __all__ += utils.__all__ __all__ += arraysetops.__all__ diff --git a/numpy/lib/arraypad.py b/numpy/lib/arraypad.py new file mode 100644 index 000000000..df2034b58 --- /dev/null +++ b/numpy/lib/arraypad.py @@ -0,0 +1,767 @@ +""" +The pad.py module contains a group of functions to pad values onto the edges +of an n-dimensional array. +""" + +import numpy as np + +__all__ = ['pad'] + + +################################################################################ +# Private utility functions. + + +def _create_vector(vector, pad_tuple, before_val, after_val): + ''' + Private function which creates the padded vector. + + Parameters + ---------- + vector : ndarray of rank 1, length N + pad_tuple[0] + pad_tuple[1] + Input vector including blank padded values. `N` is the lenth of the + original vector. + pad_tuple : tuple + This tuple represents the (before, after) width of the padding along + this particular iaxis. + before_val : scalar or ndarray of rank 1, length pad_tuple[0] + This is the value(s) that will pad the beginning of `vector`. + after_val : scalar or ndarray of rank 1, length pad_tuple[1] + This is the value(s) that will pad the end of the `vector`. + + Returns + ------- + _create_vector : ndarray + Vector with before_val and after_val replacing the blank pad values. + ''' + vector[:pad_tuple[0]] = before_val + if pad_tuple[1] > 0: + vector[-pad_tuple[1]:] = after_val + return vector + + +def _normalize_shape(narray, shape): + ''' + Private function which does some checks and normalizes the possibly much + simpler representations of 'pad_width', 'stat_length', 'constant_values', + 'end_values'. + + Parameters + ---------- + 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). + ((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 all + axes. + + 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), ...) + ''' + normshp = None + shapelen = len(np.shape(narray)) + if (isinstance(shape, int)): + 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: + raise ValueError("Unable to create correctly shaped tuple from %s" + % (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 == None: + raise ValueError("Unable to create correctly shaped tuple from %s" + % (shape,)) + return normshp + + +def _validate_lengths(narray, number_elements): + ''' + Private function which does some checks and reformats pad_width and + stat_length using _normalize_shape. + + Parameters + ---------- + narray : ndarray + Input ndarray + number_elements : {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). + ((before_1, after_1), ... (before_N, after_N)) unique number of + elements for each axis. + ((before, after),) yields same before and after constants for each + axis. + (constant,) or int is a shortcut for before = after = constant for all + axes. + + Returns + ------- + _validate_lengths : 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), ...) + ''' + shapelen = len(np.shape(narray)) + normshp = _normalize_shape(narray, number_elements) + for i in normshp: + if i[0] < 0 or i[1] < 0: + raise ValueError( + "Cannot have negative values in %s to represent number of elements." + % (number_elements,)) + return normshp + + +def _create_stat_vectors(vector, pad_tuple, iaxis, kwargs): + ''' + Returns the portion of the vector required for any statistic. + + Parameters + ---------- + vector : ndarray + Input vector that already includes empty padded values. + pad_tuple : tuple + This tuple represents the (before, after) width of the padding along + this particular iaxis. + iaxis : int + The axis currently being looped across. + kwargs : keyword arguments + Keyword arguments. Only 'stat_length' is used. 'stat_length' + defaults to the entire vector if not supplied. + + Return + ------ + _create_stat_vectors : ndarray + The values from the original vector that will be used to calculate the + statistic. + ''' + + # Can't have 0 represent the end if a slice... a[1:0] doesnt' work + pt1 = -pad_tuple[1] + if pt1 == 0: + pt1 = None + + # Default is the entire vector from the original array. + sbvec = vector[pad_tuple[0]:pt1] + savec = vector[pad_tuple[0]:pt1] + + if kwargs['stat_length']: + stat_length = kwargs['stat_length'][iaxis] + sl0 = min(stat_length[0], len(sbvec)) + sl1 = min(stat_length[1], len(savec)) + sbvec = np.arange(0) + savec = np.arange(0) + if pad_tuple[0] > 0: + sbvec = vector[pad_tuple[0]:pad_tuple[0] + sl0] + if pad_tuple[1] > 0: + savec = vector[-pad_tuple[1] - sl1:pt1] + return (sbvec, savec) + + +def _maximum(vector, pad_tuple, iaxis, kwargs): + ''' + Private function to calculate the before/after vectors for pad_maximum. + + Parameters + ---------- + vector : ndarray + Input vector that already includes empty padded values. + pad_tuple : tuple + This tuple represents the (before, after) width of the padding along + this particular iaxis. + iaxis : int + The axis currently being looped across. + kwargs : keyword arguments + Keyword arguments. Only 'stat_length' is used. 'stat_length' + defaults to the entire vector if not supplied. + + Return + ------ + _maximum : ndarray + Padded vector + ''' + sbvec, savec = _create_stat_vectors(vector, pad_tuple, iaxis, kwargs) + return _create_vector(vector, pad_tuple, max(sbvec), max(savec)) + + +def _minimum(vector, pad_tuple, iaxis, kwargs): + ''' + Private function to calculate the before/after vectors for pad_minimum. + + Parameters + ---------- + vector : ndarray + Input vector that already includes empty padded values. + pad_tuple : tuple + This tuple represents the (before, after) width of the padding along + this particular iaxis. + iaxis : int + The axis currently being looped across. + kwargs : keyword arguments + Keyword arguments. Only 'stat_length' is used. 'stat_length' + defaults to the entire vector if not supplied. + + Return + ------ + _minimum : ndarray + Padded vector + ''' + sbvec, savec = _create_stat_vectors(vector, pad_tuple, iaxis, kwargs) + return _create_vector(vector, pad_tuple, min(sbvec), min(savec)) + + +def _median(vector, pad_tuple, iaxis, kwargs): + ''' + Private function to calculate the before/after vectors for pad_median. + + Parameters + ---------- + vector : ndarray + Input vector that already includes empty padded values. + pad_tuple : tuple + This tuple represents the (before, after) width of the padding along + this particular iaxis. + iaxis : int + The axis currently being looped across. + kwargs : keyword arguments + Keyword arguments. Only 'stat_length' is used. 'stat_length' + defaults to the entire vector if not supplied. + + Return + ------ + _median : ndarray + Padded vector + ''' + sbvec, savec = _create_stat_vectors(vector, pad_tuple, iaxis, kwargs) + return _create_vector(vector, pad_tuple, np.median(sbvec), + np.median(savec)) + + +def _mean(vector, pad_tuple, iaxis, kwargs): + ''' + Private function to calculate the before/after vectors for pad_mean. + + Parameters + ---------- + vector : ndarray + Input vector that already includes empty padded values. + pad_tuple : tuple + This tuple represents the (before, after) width of the padding along + this particular iaxis. + iaxis : int + The axis currently being looped across. + kwargs : keyword arguments + Keyword arguments. Only 'stat_length' is used. 'stat_length' + defaults to the entire vector if not supplied. + + Return + ------ + _mean : ndarray + Padded vector + ''' + sbvec, savec = _create_stat_vectors(vector, pad_tuple, iaxis, kwargs) + return _create_vector(vector, pad_tuple, np.average(sbvec), + np.average(savec)) + + +def _constant(vector, pad_tuple, iaxis, kwargs): + ''' + Private function to calculate the before/after vectors for pad_constant. + + Parameters + ---------- + vector : ndarray + Input vector that already includes empty padded values. + pad_tuple : tuple + This tuple represents the (before, after) width of the padding along + this particular iaxis. + iaxis : int + The axis currently being looped across. + kwargs : keyword arguments + Keyword arguments. Need 'constant_values' keyword argument. + + Return + ------ + _constant : ndarray + Padded vector + ''' + nconstant = kwargs['constant_values'][iaxis] + return _create_vector(vector, pad_tuple, nconstant[0], nconstant[1]) + + +def _linear_ramp(vector, pad_tuple, iaxis, kwargs): + ''' + Private function to calculate the before/after vectors for pad_linear_ramp. + + Parameters + ---------- + vector : ndarray + Input vector that already includes empty padded values. + pad_tuple : tuple + This tuple represents the (before, after) width of the padding along + this particular iaxis. + iaxis : int + The axis currently being looped across. Not used in _linear_ramp. + kwargs : keyword arguments + Keyword arguments. Not used in _linear_ramp. + + Return + ------ + _linear_ramp : ndarray + Padded vector + ''' + end_values = kwargs['end_values'][iaxis] + before_delta = ((vector[pad_tuple[0]] - end_values[0]) + / float(pad_tuple[0])) + after_delta = ((vector[-pad_tuple[1] - 1] - end_values[1]) + / float(pad_tuple[1])) + + before_vector = np.ones((pad_tuple[0], )) * end_values[0] + before_vector = before_vector.astype(vector.dtype) + for i in range(len(before_vector)): + before_vector[i] = before_vector[i] + i * before_delta + + after_vector = np.ones((pad_tuple[1], )) * end_values[1] + after_vector = after_vector.astype(vector.dtype) + for i in range(len(after_vector)): + after_vector[i] = after_vector[i] + i * after_delta + after_vector = after_vector[::-1] + + return _create_vector(vector, pad_tuple, before_vector, after_vector) + + +def _reflect(vector, pad_tuple, iaxis, kwargs): + ''' + Private function to calculate the before/after vectors for pad_reflect. + + Parameters + ---------- + vector : ndarray + Input vector that already includes empty padded values. + pad_tuple : tuple + This tuple represents the (before, after) width of the padding along + this particular iaxis. + iaxis : int + The axis currently being looped across. Not used in _reflect. + kwargs : keyword arguments + Keyword arguments. Not used in _reflect. + + Return + ------ + _reflect : ndarray + Padded vector + ''' + # Can't have pad_tuple[1] be used in the slice if == to 0. + if pad_tuple[1] == 0: + after_vector = vector[pad_tuple[0]:None] + else: + after_vector = vector[pad_tuple[0]:-pad_tuple[1]] + + reverse = after_vector[::-1] + + before_vector = np.resize( + np.concatenate( + (after_vector[1:-1], reverse)), pad_tuple[0])[::-1] + after_vector = np.resize( + np.concatenate( + (reverse[1:-1], after_vector)), pad_tuple[1]) + + if kwargs['reflect_type'] == 'even': + pass + elif kwargs['reflect_type'] == 'odd': + before_vector = 2 * vector[pad_tuple[0]] - before_vector + after_vector = 2 * vector[-pad_tuple[-1] - 1] - after_vector + else: + raise ValueError("The keyword '%s' cannot have the value '%s'." + % ('reflect_type', kwargs['reflect_type'])) + return _create_vector(vector, pad_tuple, before_vector, after_vector) + + +def _symmetric(vector, pad_tuple, iaxis, kwargs): + ''' + Private function to calculate the before/after vectors for pad_symmetric. + + Parameters + ---------- + vector : ndarray + Input vector that already includes empty padded values. + pad_tuple : tuple + This tuple represents the (before, after) width of the padding along + this particular iaxis. + iaxis : int + The axis currently being looped across. Not used in _symmetric. + kwargs : keyword arguments + Keyword arguments. Not used in _symmetric. + + Return + ------ + _symmetric : ndarray + Padded vector + ''' + if pad_tuple[1] == 0: + after_vector = vector[pad_tuple[0]:None] + else: + after_vector = vector[pad_tuple[0]:-pad_tuple[1]] + + before_vector = np.resize( + np.concatenate( + (after_vector, after_vector[::-1])), pad_tuple[0])[::-1] + after_vector = np.resize( + np.concatenate( + (after_vector[::-1], after_vector)), pad_tuple[1]) + + if kwargs['reflect_type'] == 'even': + pass + elif kwargs['reflect_type'] == 'odd': + before_vector = 2 * vector[pad_tuple[0]] - before_vector + after_vector = 2 * vector[-pad_tuple[1] - 1] - after_vector + else: + raise ValueError("The keyword '%s' cannot have the value '%s'." + % ('reflect_type', kwargs['reflect_type'])) + return _create_vector(vector, pad_tuple, before_vector, after_vector) + + +def _wrap(vector, pad_tuple, iaxis, kwargs): + ''' + Private function to calculate the before/after vectors for pad_wrap. + + Parameters + ---------- + vector : ndarray + Input vector that already includes empty padded values. + pad_tuple : tuple + This tuple represents the (before, after) width of the padding along + this particular iaxis. + iaxis : int + The axis currently being looped across. Not used in _wrap. + kwargs : keyword arguments + Keyword arguments. Not used in _wrap. + + Return + ------ + _wrap : ndarray + Padded vector + ''' + if pad_tuple[1] == 0: + after_vector = vector[pad_tuple[0]:None] + else: + after_vector = vector[pad_tuple[0]:-pad_tuple[1]] + + before_vector = np.resize(after_vector[::-1], pad_tuple[0])[::-1] + after_vector = np.resize(after_vector, pad_tuple[1]) + + return _create_vector(vector, pad_tuple, before_vector, after_vector) + + +def _edge(vector, pad_tuple, iaxis, kwargs): + ''' + Private function to calculate the before/after vectors for pad_edge. + + Parameters + ---------- + vector : ndarray + Input vector that already includes empty padded values. + pad_tuple : tuple + This tuple represents the (before, after) width of the padding along + this particular iaxis. + iaxis : int + The axis currently being looped across. Not used in _edge. + kwargs : keyword arguments + Keyword arguments. Not used in _edge. + + Return + ------ + _edge : ndarray + Padded vector + ''' + return _create_vector(vector, pad_tuple, vector[pad_tuple[0]], + vector[-pad_tuple[1] - 1]) + + +################################################################################ +# Public functions + + +def pad(array, pad_width, mode=None, **kwargs): + """ + Pads an array. + + Parameters + ---------- + mode : {'constant', 'edge', 'linear_ramp', 'maximum', 'mean', 'median', + 'minimum', 'reflect', 'symmetric', 'wrap', function} + One of the following string values or a user supplied function. + 'constant' Pads with a constant value. + 'edge' Pads with the edge values of array. + 'linear_ramp' Pads with the linear ramp between end_value and the + array edge value. + 'maximum' Pads with the maximum value of all or part of the + vector along each axis. + 'mean' Pads with the mean value of all or part of the vector + along each axis. + 'median' Pads with the median value of all or part of the + vector along each axis. + 'minimum' Pads with the minimum value of all or part of the + vector along each axis. + 'reflect' Pads with the reflection of the vector mirrored on the + first and last values of the vector along each axis. + 'symmetric' Pads with the reflection of the vector mirrored along + the edge of the array. + 'wrap' Pads with the wrap of the vector along the axis. The + first values are used to pad the end and the end + values are used to pad the beginning. + function(vector, iaxis_pad_width, iaxis, **kwargs) + if a user supplied function must accept arguments + (vector, iaxis_pad_width, iaxis, **kwargs) and return + a rank 1 array equal in length to `vector` with padded + values replaced. + vector + a rank 1 array already padded with zeros. Padded + values are vector[:pad_tuple[0]] and + vector[-pad_tuple[1]:]. + iaxis_pad_width + a 2-tuple of ints, iaxis_pad_width[0] represents the + number of values padded at the beginning of `vector` + where iaxis_pad_width[1] represents the number of + values padded at the end of `vector`. + iaxis + the axis currently being calculated. + kwargs + any keyword arguments the function requires. + array : array_like of rank N + Input array + pad_width : {sequence, int} + Number of values padded to each edge of each axis. + ((before_1, after_1), ... (before_N, after_N)) unique pad widths for + each axis. + ((before, after),) yields same before and after pad for each axis. + (pad,) or int is a shortcut for before = after = pad width for all + axes. + stat_length : {sequence, int}, optional + Used in 'maximum', 'mean', 'median', and 'minimum'. + Number of values at edge of each axis used to calculate the statistic + value. + ((before_1, after_1), ... (before_N, after_N)) unique statistic + lengths for each axis. + ((before, after),) yields same before and after statistic lengths for + each axis. + (stat_length,) or int is a shortcut for before = after = statistic + length for all axes. + Default is ``None``, to use the entire axis. + constant_values : {sequence, int}, optional + Used in 'constant'. + The values to set the padded values for each axis. + ((before_1, after_1), ... (before_N, after_N)) unique pad constants + for each axis. + ((before, after),) yields same before and after constants for each + axis. + (constant,) or int is a shortcut for before = after = constant for all + axes. + Default is 0. + end_values : {sequence, int}, optional + Used in 'linear_ramp'. + The values used for the ending value of the linear_ramp and that will + form the edge of the padded array. + ((before_1, after_1), ... (before_N, after_N)) unique end values + for each axis. + ((before, after),) yields same before and after end values for each + axis. + (constant,) or int is a shortcut for before = after = end value for all + axes. + Default is 0. + reflect_type : str {'even', 'odd'}, optional + Used in 'reflect', and 'symmetric'. + The 'even' style is the default with an unaltered reflection around + the edge value. For the 'odd' style, the extented part of the array + is created by subtracting the reflected values from two times the edge + value. + + Returns + ------- + pad : ndarray + Padded array of rank equal to `array` with shape increased according + to `pad_width`. + + Notes + ----- + .. versionadded:: 1.7.0 + + For `array` with rank greater than 1, some of the padding of later axes is + calculated from padding of previous axes. This is easiest to think about + with a rank 2 array where the corners of the padded array are calculated + by using padded values from the first axis. + + Examples + -------- + >>> a = [1, 2, 3, 4, 5] + >>> 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') + array([1, 1, 1, 2, 3, 4, 5, 5, 5, 5]) + + >>> 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') + array([5, 5, 1, 2, 3, 4, 5, 5, 5]) + + >>> np.lib.pad(a, (2,), 'mean') + array([3, 3, 1, 2, 3, 4, 5, 3, 3]) + + >>> np.lib.pad(a, (2,), 'median') + array([3, 3, 1, 2, 3, 4, 5, 3, 3]) + + >>> 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], + [1, 1, 1, 2, 1, 1, 1], + [1, 1, 1, 2, 1, 1, 1], + [3, 3, 3, 4, 3, 3, 3], + [1, 1, 1, 2, 1, 1, 1], + [1, 1, 1, 2, 1, 1, 1]]) + + >>> a = [1, 2, 3, 4, 5] + >>> 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') + array([-1, 0, 1, 2, 3, 4, 5, 6, 7, 8]) + + >>> 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') + array([0, 1, 1, 2, 3, 4, 5, 5, 6, 7]) + + >>> 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): + ... vector[:pad_width[0]] = 10 + ... vector[-pad_width[1]:] = 10 + ... return vector + + >>> a = np.arange(6) + >>> a = a.reshape((2,3)) + + >>> np.lib.pad(a, 2, padwithtens) + 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]]) + """ + + + narray = np.array(array) + pad_width = _validate_lengths(narray, pad_width) + + modefunc = { + 'constant': _constant, + 'edge': _edge, + 'linear_ramp': _linear_ramp, + 'maximum': _maximum, + 'mean': _mean, + 'median': _median, + 'minimum': _minimum, + 'reflect': _reflect, + 'symmetric': _symmetric, + 'wrap': _wrap, + } + + allowedkwargs = { + 'constant': ['constant_values'], + 'edge': [], + 'linear_ramp': ['end_values'], + 'maximum': ['stat_length'], + 'mean': ['stat_length'], + 'median': ['stat_length'], + 'minimum': ['stat_length'], + 'reflect': ['reflect_type'], + 'symmetric': ['reflect_type'], + 'wrap': [], + } + + kwdefaults = { + 'stat_length': None, + 'constant_values': 0, + 'end_values': 0, + 'reflect_type': 'even', + } + + if isinstance(mode, str): + function = modefunc[mode] + + # Make sure have allowed kwargs appropriate for mode + for key in kwargs: + if key not in allowedkwargs[mode]: + raise ValueError('%s keyword not in allowed keywords %s' % + (key, allowedkwargs[mode])) + + # Set kwarg defaults + for kw in allowedkwargs[mode]: + kwargs.setdefault(kw, kwdefaults[kw]) + + # Need to only normalize particular keywords. + for i in kwargs: + if i == 'stat_length' and kwargs[i]: + kwargs[i] = _validate_lengths(narray, kwargs[i]) + if i in ['end_values', 'constant_values']: + kwargs[i] = _normalize_shape(narray, kwargs[i]) + elif mode == None: + raise ValueError('Keyword "mode" must be a function or one of %s.' % + (modefunc.keys(),)) + else: + # User supplied function, I hope + function = mode + + # Create a new padded array + rank = range(len(narray.shape)) + total_dim_increase = [np.sum(pad_width[i]) for i in rank] + offset_slices = [slice(pad_width[i][0], + pad_width[i][0] + narray.shape[i]) + for i in rank] + new_shape = np.array(narray.shape) + total_dim_increase + newmat = np.zeros(new_shape).astype(narray.dtype) + + # Insert the original array into the padded array + newmat[offset_slices] = narray + + # This is the core of pad ... + for iaxis in rank: + np.apply_along_axis(function, + iaxis, + newmat, + pad_width[iaxis], + iaxis, + kwargs) + return newmat + diff --git a/numpy/lib/tests/test_arraypad.py b/numpy/lib/tests/test_arraypad.py new file mode 100644 index 000000000..01cb5be4c --- /dev/null +++ b/numpy/lib/tests/test_arraypad.py @@ -0,0 +1,530 @@ +''' +Tests for the pad functions. +''' + +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.lib import pad + + +class TestStatistic(TestCase): + def test_check_mean_stat_length(self): + a = np.arange(100).astype('f') + a = pad(a, ((25, 20), ), 'mean', stat_length=((2, 3), )) + b = np.array([ + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, + + 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., + + 98., 98., 98., 98., 98., 98., 98., 98., 98., 98., + 98., 98., 98., 98., 98., 98., 98., 98., 98., 98.]) + assert_array_equal(a, b) + + def test_check_maximum_1(self): + a = np.arange(100) + a = pad(a, (25, 20), 'maximum') + b = np.array([ + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, + + 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, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99]) + assert_array_equal(a, b) + + def test_check_maximum_2(self): + a = np.arange(100) + 1 + a = pad(a, (25, 20), 'maximum') + b = np.array([ + 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100, 100, 100, 100, + + 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') + 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_minimum_2(self): + a = np.arange(100) + 2 + a = pad(a, (25, 20), 'minimum') + 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, + + 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, + + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]) + assert_array_equal(a, b) + + def test_check_median(self): + a = np.arange(100).astype('f') + a = pad(a, (25, 20), 'median') + b = np.array([ + 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, + 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, + 49.5, 49.5, 49.5, 49.5, 49.5, + + 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., + + 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, + 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5]) + assert_array_equal(a, b) + + def test_check_median_01(self): + a = np.array([[3, 1, 4], [4, 5, 9], [9, 8, 2]]) + a = pad(a, 1, 'median') + b = np.array([ + [4, 4, 5, 4, 4], + + [3, 3, 1, 4, 3], + [5, 4, 5, 9, 5], + [8, 9, 8, 2, 8], + + [4, 4, 5, 4, 4]]) + assert_array_equal(a, b) + + def test_check_median_02(self): + a = np.array([[3, 1, 4], [4, 5, 9], [9, 8, 2]]) + a = pad(a.T, 1, 'median').T + b = np.array([ + [5, 4, 5, 4, 5], + + [3, 3, 1, 4, 3], + [5, 4, 5, 9, 5], + [8, 9, 8, 2, 8], + + [5, 4, 5, 4, 5]]) + 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) + b = np.array([ + [4, 4, 4, 4, 4, 4, 5, 6, 5, 5, 5, 5, 5, 5, 5], + [4, 4, 4, 4, 4, 4, 5, 6, 5, 5, 5, 5, 5, 5, 5], + [4, 4, 4, 4, 4, 4, 5, 6, 5, 5, 5, 5, 5, 5, 5], + [4, 4, 4, 4, 4, 4, 5, 6, 5, 5, 5, 5, 5, 5, 5], + [4, 4, 4, 4, 4, 4, 5, 6, 5, 5, 5, 5, 5, 5, 5], + + [4, 4, 4, 4, 4, 4, 5, 6, 5, 5, 5, 5, 5, 5, 5], + + [4, 4, 4, 4, 4, 4, 5, 6, 5, 5, 5, 5, 5, 5, 5], + [4, 4, 4, 4, 4, 4, 5, 6, 5, 5, 5, 5, 5, 5, 5], + [4, 4, 4, 4, 4, 4, 5, 6, 5, 5, 5, 5, 5, 5, 5], + [4, 4, 4, 4, 4, 4, 5, 6, 5, 5, 5, 5, 5, 5, 5], + [4, 4, 4, 4, 4, 4, 5, 6, 5, 5, 5, 5, 5, 5, 5], + [4, 4, 4, 4, 4, 4, 5, 6, 5, 5, 5, 5, 5, 5, 5], + [4, 4, 4, 4, 4, 4, 5, 6, 5, 5, 5, 5, 5, 5, 5]]) + assert_array_equal(a, b) + + def test_check_mean_2(self): + a = np.arange(100).astype('f') + a = pad(a, (25, 20), 'mean') + b = np.array([ + 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, + 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, + 49.5, 49.5, 49.5, 49.5, 49.5, + + 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., + + 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, + 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5]) + assert_array_equal(a, b) + + +class TestConstant(TestCase): + def test_check_constant(self): + a = np.arange(100) + a = pad(a, (25, 20), 'constant', constant_values=(10, 20)) + 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, + + 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, + + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20]) + assert_array_equal(a, b) + + +class TestLinearRamp(TestCase): + def test_check_simple(self): + a = np.arange(100).astype('f') + a = pad(a, (25, 20), 'linear_ramp', end_values=(4, 5)) + b = np.array([ + 4.00, 3.84, 3.68, 3.52, 3.36, 3.20, 3.04, 2.88, 2.72, 2.56, + 2.40, 2.24, 2.08, 1.92, 1.76, 1.60, 1.44, 1.28, 1.12, 0.96, + 0.80, 0.64, 0.48, 0.32, 0.16, + + 0.00, 1.00, 2.00, 3.00, 4.00, 5.00, 6.00, 7.00, 8.00, 9.00, + 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, + 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, + 30.0, 31.0, 32.0, 33.0, 34.0, 35.0, 36.0, 37.0, 38.0, 39.0, + 40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0, 47.0, 48.0, 49.0, + 50.0, 51.0, 52.0, 53.0, 54.0, 55.0, 56.0, 57.0, 58.0, 59.0, + 60.0, 61.0, 62.0, 63.0, 64.0, 65.0, 66.0, 67.0, 68.0, 69.0, + 70.0, 71.0, 72.0, 73.0, 74.0, 75.0, 76.0, 77.0, 78.0, 79.0, + 80.0, 81.0, 82.0, 83.0, 84.0, 85.0, 86.0, 87.0, 88.0, 89.0, + 90.0, 91.0, 92.0, 93.0, 94.0, 95.0, 96.0, 97.0, 98.0, 99.0, + + 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) + + +class TestReflect(TestCase): + def test_check_simple(self): + a = np.arange(100) + a = pad(a, (25, 20), 'reflect') + 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, + + 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, + 88, 87, 86, 85, 84, 83, 82, 81, 80, 79]) + assert_array_equal(a, b) + + def test_check_large_pad(self): + a = [[4, 5, 6], [6, 7, 8]] + a = pad(a, (5, 7), 'reflect') + b = np.array([ + [7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7], + + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7], + + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5]]) + assert_array_equal(a, b) + + def test_check_shape(self): + a = [[4, 5, 6]] + a = pad(a, (5, 7), 'reflect') + b = np.array([ + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5]]) + assert_array_equal(a, b) + + def test_check_01(self): + a = pad([1, 2, 3], 2, 'reflect') + b = np.array([3, 2, 1, 2, 3, 2, 1]) + assert_array_equal(a, b) + + def test_check_02(self): + a = pad([1, 2, 3], 3, 'reflect') + b = np.array([2, 3, 2, 1, 2, 3, 2, 1, 2]) + assert_array_equal(a, b) + + def test_check_03(self): + a = pad([1, 2, 3], 4, 'reflect') + b = np.array([1, 2, 3, 2, 1, 2, 3, 2, 1, 2, 3]) + assert_array_equal(a, b) + + +class TestWrap(TestCase): + def test_check_simple(self): + a = np.arange(100) + a = pad(a, (25, 20), 'wrap') + b = np.array([ + 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, 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, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]) + assert_array_equal(a, b) + + def test_check_large_pad(self): + a = np.arange(12) + a = np.reshape(a, (3, 4)) + a = pad(a, (10, 12), 'wrap') + b = np.array([ + [10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, + 11, 8, 9, 10, 11, 8, 9, 10, 11], + [2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, + 3, 0, 1, 2, 3, 0, 1, 2, 3], + [6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, + 7, 4, 5, 6, 7, 4, 5, 6, 7], + [10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, + 11, 8, 9, 10, 11, 8, 9, 10, 11], + [2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, + 3, 0, 1, 2, 3, 0, 1, 2, 3], + [6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, + 7, 4, 5, 6, 7, 4, 5, 6, 7], + [10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, + 11, 8, 9, 10, 11, 8, 9, 10, 11], + [2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, + 3, 0, 1, 2, 3, 0, 1, 2, 3], + [6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, + 7, 4, 5, 6, 7, 4, 5, 6, 7], + [10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, + 11, 8, 9, 10, 11, 8, 9, 10, 11], + + [2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, + 3, 0, 1, 2, 3, 0, 1, 2, 3], + [6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, + 7, 4, 5, 6, 7, 4, 5, 6, 7], + [10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, + 11, 8, 9, 10, 11, 8, 9, 10, 11], + + [2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, + 3, 0, 1, 2, 3, 0, 1, 2, 3], + [6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, + 7, 4, 5, 6, 7, 4, 5, 6, 7], + [10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, + 11, 8, 9, 10, 11, 8, 9, 10, 11], + [2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, + 3, 0, 1, 2, 3, 0, 1, 2, 3], + [6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, + 7, 4, 5, 6, 7, 4, 5, 6, 7], + [10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, + 11, 8, 9, 10, 11, 8, 9, 10, 11], + [2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, + 3, 0, 1, 2, 3, 0, 1, 2, 3], + [6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, + 7, 4, 5, 6, 7, 4, 5, 6, 7], + [10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, + 11, 8, 9, 10, 11, 8, 9, 10, 11], + [2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, + 3, 0, 1, 2, 3, 0, 1, 2, 3], + [6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, + 7, 4, 5, 6, 7, 4, 5, 6, 7], + [10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, + 11, 8, 9, 10, 11, 8, 9, 10, 11]]) + assert_array_equal(a, b) + + def test_check_01(self): + a = pad([1, 2, 3], 3, 'wrap') + b = np.array([1, 2, 3, 1, 2, 3, 1, 2, 3]) + assert_array_equal(a, b) + + def test_check_02(self): + a = pad([1, 2, 3], 4, 'wrap') + b = np.array([3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1]) + assert_array_equal(a, b) + + +class TestStatLen(TestCase): + def test_check_simple(self): + a = np.arange(30) + a = np.reshape(a, (6, 5)) + a = pad(a, ((2, 3), (3, 2)), mode='mean', stat_length=(3,)) + b = np.array([[6, 6, 6, 5, 6, 7, 8, 9, 8, 8], + [6, 6, 6, 5, 6, 7, 8, 9, 8, 8], + + [1, 1, 1, 0, 1, 2, 3, 4, 3, 3], + [6, 6, 6, 5, 6, 7, 8, 9, 8, 8], + [11, 11, 11, 10, 11, 12, 13, 14, 13, 13], + [16, 16, 16, 15, 16, 17, 18, 19, 18, 18], + [21, 21, 21, 20, 21, 22, 23, 24, 23, 23], + [26, 26, 26, 25, 26, 27, 28, 29, 28, 28], + + [21, 21, 21, 20, 21, 22, 23, 24, 23, 23], + [21, 21, 21, 20, 21, 22, 23, 24, 23, 23], + [21, 21, 21, 20, 21, 22, 23, 24, 23, 23]]) + assert_array_equal(a, b) + + +class TestEdge(TestCase): + def test_check_simple(self): + a = np.arange(12) + a = np.reshape(a, (4, 3)) + a = pad(a, ((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) + arr = np.reshape(arr, (6, 5)) + kwargs = dict(mode='mean', stat_length=(3, )) + assert_raises(ValueError, pad, arr, ((2, 3), (3, 2), (4, 5)), + **kwargs) + + def test_check_negative_stat_length(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)), + **kwargs) + + def test_check_negative_pad_width(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)), + **kwargs) + + +class ValueError2(TestCase): + def test_check_simple(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)), + **kwargs) + + +class ValueError3(TestCase): + def test_check_simple(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)), + **kwargs) + + +if __name__ == "__main__": + run_module_suite() |