From c57e6d61ce1f4c1625e903b5a09566954b583e6c Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Sun, 29 Apr 2018 17:21:37 -0700 Subject: MAINT: Remove singleton-dimension insertion in np.pad in favor of not losing the dimension in the first place. `arr[:,:,0,:,:].reshape(arr.shape[:2] + (1,) + arr.shape[3:])` is much more readable as `arr[:,:,0:1,:,:]` (and easier for subclasses to handle) --- numpy/lib/arraypad.py | 79 ++++++++++++--------------------------------------- 1 file changed, 18 insertions(+), 61 deletions(-) (limited to 'numpy/lib/arraypad.py') diff --git a/numpy/lib/arraypad.py b/numpy/lib/arraypad.py index daaa68d06..fa62666b3 100644 --- a/numpy/lib/arraypad.py +++ b/numpy/lib/arraypad.py @@ -164,13 +164,9 @@ def _prepend_edge(arr, pad_amt, axis=-1): if pad_amt == 0: return arr - edge_slice = tuple(slice(None) if i != axis else 0 + edge_slice = tuple(slice(None) if i != axis else slice(0, 1) for (i, x) in enumerate(arr.shape)) - - # Shape to restore singleton dimension after slicing - pad_singleton = tuple(x if i != axis else 1 - for (i, x) in enumerate(arr.shape)) - edge_arr = arr[edge_slice].reshape(pad_singleton) + edge_arr = arr[edge_slice] return np.concatenate((edge_arr.repeat(pad_amt, axis=axis), arr), axis=axis) @@ -198,13 +194,9 @@ def _append_edge(arr, pad_amt, axis=-1): if pad_amt == 0: return arr - edge_slice = tuple(slice(None) if i != axis else arr.shape[axis] - 1 + edge_slice = tuple(slice(None) if i != axis else slice(x - 1, x) for (i, x) in enumerate(arr.shape)) - - # Shape to restore singleton dimension after slicing - pad_singleton = tuple(x if i != axis else 1 - for (i, x) in enumerate(arr.shape)) - edge_arr = arr[edge_slice].reshape(pad_singleton) + edge_arr = arr[edge_slice] return np.concatenate((arr, edge_arr.repeat(pad_amt, axis=axis)), axis=axis) @@ -244,15 +236,11 @@ def _prepend_ramp(arr, pad_amt, end, axis=-1): reverse=True).astype(np.float64) # Appropriate slicing to extract n-dimensional edge along `axis` - edge_slice = tuple(slice(None) if i != axis else 0 + edge_slice = tuple(slice(None) if i != axis else slice(0, 1) for (i, x) in enumerate(arr.shape)) - # Shape to restore singleton dimension after slicing - pad_singleton = tuple(x if i != axis else 1 - for (i, x) in enumerate(arr.shape)) - - # Extract edge, reshape to original rank, and extend along `axis` - edge_pad = arr[edge_slice].reshape(pad_singleton).repeat(pad_amt, axis) + # Extract edge, and extend along `axis` + edge_pad = arr[edge_slice].repeat(pad_amt, axis) # Linear ramp slope = (end - edge_pad) / float(pad_amt) @@ -299,15 +287,11 @@ def _append_ramp(arr, pad_amt, end, axis=-1): reverse=False).astype(np.float64) # Slice a chunk from the edge to calculate stats on - edge_slice = tuple(slice(None) if i != axis else -1 + edge_slice = tuple(slice(None) if i != axis else slice(x - 1, x) for (i, x) in enumerate(arr.shape)) - # Shape to restore singleton dimension after slicing - pad_singleton = tuple(x if i != axis else 1 - for (i, x) in enumerate(arr.shape)) - - # Extract edge, reshape to original rank, and extend along `axis` - edge_pad = arr[edge_slice].reshape(pad_singleton).repeat(pad_amt, axis) + # Extract edge, and extend along `axis` + edge_pad = arr[edge_slice].repeat(pad_amt, axis) # Linear ramp slope = (end - edge_pad) / float(pad_amt) @@ -798,17 +782,11 @@ def _pad_ref(arr, pad_amt, method, axis=-1): ref_chunk1 = arr[ref_slice] - # Shape to restore singleton dimension after slicing - pad_singleton = tuple(x if i != axis else 1 - for (i, x) in enumerate(arr.shape)) - if pad_amt[0] == 1: - ref_chunk1 = ref_chunk1.reshape(pad_singleton) - # Memory/computationally more expensive, only do this if `method='odd'` if 'odd' in method and pad_amt[0] > 0: - edge_slice1 = tuple(slice(None) if i != axis else 0 + edge_slice1 = tuple(slice(None) if i != axis else slice(0, 1) for (i, x) in enumerate(arr.shape)) - edge_chunk = arr[edge_slice1].reshape(pad_singleton) + edge_chunk = arr[edge_slice1] ref_chunk1 = 2 * edge_chunk - ref_chunk1 del edge_chunk @@ -824,13 +802,10 @@ def _pad_ref(arr, pad_amt, method, axis=-1): for (i, x) in enumerate(arr.shape)) ref_chunk2 = arr[ref_slice][rev_idx] - if pad_amt[1] == 1: - ref_chunk2 = ref_chunk2.reshape(pad_singleton) - if 'odd' in method: - edge_slice2 = tuple(slice(None) if i != axis else -1 + edge_slice2 = tuple(slice(None) if i != axis else slice(x - 1, x) for (i, x) in enumerate(arr.shape)) - edge_chunk = arr[edge_slice2].reshape(pad_singleton) + edge_chunk = arr[edge_slice2] ref_chunk2 = 2 * edge_chunk - ref_chunk2 del edge_chunk @@ -884,17 +859,11 @@ def _pad_sym(arr, pad_amt, method, axis=-1): for (i, x) in enumerate(arr.shape)) sym_chunk1 = arr[sym_slice][rev_idx] - # Shape to restore singleton dimension after slicing - pad_singleton = tuple(x if i != axis else 1 - for (i, x) in enumerate(arr.shape)) - if pad_amt[0] == 1: - sym_chunk1 = sym_chunk1.reshape(pad_singleton) - # Memory/computationally more expensive, only do this if `method='odd'` if 'odd' in method and pad_amt[0] > 0: - edge_slice1 = tuple(slice(None) if i != axis else 0 + edge_slice1 = tuple(slice(None) if i != axis else slice(0, 1) for (i, x) in enumerate(arr.shape)) - edge_chunk = arr[edge_slice1].reshape(pad_singleton) + edge_chunk = arr[edge_slice1] sym_chunk1 = 2 * edge_chunk - sym_chunk1 del edge_chunk @@ -908,13 +877,10 @@ def _pad_sym(arr, pad_amt, method, axis=-1): for (i, x) in enumerate(arr.shape)) sym_chunk2 = arr[sym_slice][rev_idx] - if pad_amt[1] == 1: - sym_chunk2 = sym_chunk2.reshape(pad_singleton) - if 'odd' in method: - edge_slice2 = tuple(slice(None) if i != axis else -1 + edge_slice2 = tuple(slice(None) if i != axis else slice(x - 1, x) for (i, x) in enumerate(arr.shape)) - edge_chunk = arr[edge_slice2].reshape(pad_singleton) + edge_chunk = arr[edge_slice2] sym_chunk2 = 2 * edge_chunk - sym_chunk2 del edge_chunk @@ -965,12 +931,6 @@ def _pad_wrap(arr, pad_amt, axis=-1): for (i, x) in enumerate(arr.shape)) wrap_chunk1 = arr[wrap_slice] - # Shape to restore singleton dimension after slicing - pad_singleton = tuple(x if i != axis else 1 - for (i, x) in enumerate(arr.shape)) - if pad_amt[0] == 1: - wrap_chunk1 = wrap_chunk1.reshape(pad_singleton) - ########################################################################## # Appended region @@ -979,9 +939,6 @@ def _pad_wrap(arr, pad_amt, axis=-1): for (i, x) in enumerate(arr.shape)) wrap_chunk2 = arr[wrap_slice] - if pad_amt[1] == 1: - wrap_chunk2 = wrap_chunk2.reshape(pad_singleton) - # Concatenate `arr` with both chunks, extending along `axis` return np.concatenate((wrap_chunk1, arr, wrap_chunk2), axis=axis) -- cgit v1.2.1 From 4bdcbab61d996a1839ee521c0ca92457d00f876e Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Sun, 29 Apr 2018 17:22:07 -0700 Subject: MAINT: Use keepdims in favor of re-inserting dimensions This is safe, because the arguments are always base-class ndarrays, so `keepdims` is guaranteed to be supported --- numpy/lib/arraypad.py | 64 +++++++++++++-------------------------------------- 1 file changed, 16 insertions(+), 48 deletions(-) (limited to 'numpy/lib/arraypad.py') diff --git a/numpy/lib/arraypad.py b/numpy/lib/arraypad.py index fa62666b3..a6d94836f 100644 --- a/numpy/lib/arraypad.py +++ b/numpy/lib/arraypad.py @@ -343,12 +343,8 @@ def _prepend_max(arr, pad_amt, num, axis=-1): max_slice = tuple(slice(None) if i != axis else slice(num) for (i, x) in enumerate(arr.shape)) - # Shape to restore singleton dimension after slicing - pad_singleton = tuple(x if i != axis else 1 - for (i, x) in enumerate(arr.shape)) - - # Extract slice, calculate max, reshape to add singleton dimension back - max_chunk = arr[max_slice].max(axis=axis).reshape(pad_singleton) + # Extract slice, calculate max + max_chunk = arr[max_slice].max(axis=axis, keepdims=True) # Concatenate `arr` with `max_chunk`, extended along `axis` by `pad_amt` return np.concatenate((max_chunk.repeat(pad_amt, axis=axis), arr), @@ -399,12 +395,8 @@ def _append_max(arr, pad_amt, num, axis=-1): else: max_slice = tuple(slice(None) for x in arr.shape) - # Shape to restore singleton dimension after slicing - pad_singleton = tuple(x if i != axis else 1 - for (i, x) in enumerate(arr.shape)) - - # Extract slice, calculate max, reshape to add singleton dimension back - max_chunk = arr[max_slice].max(axis=axis).reshape(pad_singleton) + # Extract slice, calculate max + max_chunk = arr[max_slice].max(axis=axis, keepdims=True) # Concatenate `arr` with `max_chunk`, extended along `axis` by `pad_amt` return np.concatenate((arr, max_chunk.repeat(pad_amt, axis=axis)), @@ -450,12 +442,8 @@ def _prepend_mean(arr, pad_amt, num, axis=-1): mean_slice = tuple(slice(None) if i != axis else slice(num) for (i, x) in enumerate(arr.shape)) - # Shape to restore singleton dimension after slicing - pad_singleton = tuple(x if i != axis else 1 - for (i, x) in enumerate(arr.shape)) - - # Extract slice, calculate mean, reshape to add singleton dimension back - mean_chunk = arr[mean_slice].mean(axis).reshape(pad_singleton) + # Extract slice, calculate mean + mean_chunk = arr[mean_slice].mean(axis, keepdims=True) _round_ifneeded(mean_chunk, arr.dtype) # Concatenate `arr` with `mean_chunk`, extended along `axis` by `pad_amt` @@ -507,12 +495,8 @@ def _append_mean(arr, pad_amt, num, axis=-1): else: mean_slice = tuple(slice(None) for x in arr.shape) - # Shape to restore singleton dimension after slicing - pad_singleton = tuple(x if i != axis else 1 - for (i, x) in enumerate(arr.shape)) - - # Extract slice, calculate mean, reshape to add singleton dimension back - mean_chunk = arr[mean_slice].mean(axis=axis).reshape(pad_singleton) + # Extract slice, calculate mean + mean_chunk = arr[mean_slice].mean(axis=axis, keepdims=True) _round_ifneeded(mean_chunk, arr.dtype) # Concatenate `arr` with `mean_chunk`, extended along `axis` by `pad_amt` @@ -559,12 +543,8 @@ def _prepend_med(arr, pad_amt, num, axis=-1): med_slice = tuple(slice(None) if i != axis else slice(num) for (i, x) in enumerate(arr.shape)) - # Shape to restore singleton dimension after slicing - pad_singleton = tuple(x if i != axis else 1 - for (i, x) in enumerate(arr.shape)) - - # Extract slice, calculate median, reshape to add singleton dimension back - med_chunk = np.median(arr[med_slice], axis=axis).reshape(pad_singleton) + # Extract slice, calculate median + med_chunk = np.median(arr[med_slice], axis=axis, keepdims=True) _round_ifneeded(med_chunk, arr.dtype) # Concatenate `arr` with `med_chunk`, extended along `axis` by `pad_amt` @@ -616,12 +596,8 @@ def _append_med(arr, pad_amt, num, axis=-1): else: med_slice = tuple(slice(None) for x in arr.shape) - # Shape to restore singleton dimension after slicing - pad_singleton = tuple(x if i != axis else 1 - for (i, x) in enumerate(arr.shape)) - - # Extract slice, calculate median, reshape to add singleton dimension back - med_chunk = np.median(arr[med_slice], axis=axis).reshape(pad_singleton) + # Extract slice, calculate median + med_chunk = np.median(arr[med_slice], axis=axis, keepdims=True) _round_ifneeded(med_chunk, arr.dtype) # Concatenate `arr` with `med_chunk`, extended along `axis` by `pad_amt` @@ -669,12 +645,8 @@ def _prepend_min(arr, pad_amt, num, axis=-1): min_slice = tuple(slice(None) if i != axis else slice(num) for (i, x) in enumerate(arr.shape)) - # Shape to restore singleton dimension after slicing - pad_singleton = tuple(x if i != axis else 1 - for (i, x) in enumerate(arr.shape)) - - # Extract slice, calculate min, reshape to add singleton dimension back - min_chunk = arr[min_slice].min(axis=axis).reshape(pad_singleton) + # Extract slice, calculate min + min_chunk = arr[min_slice].min(axis=axis, keepdims=True) # Concatenate `arr` with `min_chunk`, extended along `axis` by `pad_amt` return np.concatenate((min_chunk.repeat(pad_amt, axis=axis), arr), @@ -725,12 +697,8 @@ def _append_min(arr, pad_amt, num, axis=-1): else: min_slice = tuple(slice(None) for x in arr.shape) - # Shape to restore singleton dimension after slicing - pad_singleton = tuple(x if i != axis else 1 - for (i, x) in enumerate(arr.shape)) - - # Extract slice, calculate min, reshape to add singleton dimension back - min_chunk = arr[min_slice].min(axis=axis).reshape(pad_singleton) + # Extract slice, calculate min + min_chunk = arr[min_slice].min(axis=axis, keepdims=True) # Concatenate `arr` with `min_chunk`, extended along `axis` by `pad_amt` return np.concatenate((arr, min_chunk.repeat(pad_amt, axis=axis)), -- cgit v1.2.1 From 51ef0c409e20490829218c4d549a3bd4c9b073a2 Mon Sep 17 00:00:00 2001 From: Lars G Date: Wed, 2 May 2018 12:54:08 +0200 Subject: BUG: Fix padding with large integers The old way of creating the padded array padded with wrong values for large integers because the new prepended / appended array was implicitly created with dtype float64: >>> (np.zeros(1) + (2 ** 64 - 1)).astype(np.uint64) array([0], np.uint64) >>> (np.zeros(1) + (2 ** 63 - 1)).astype(np.int64) array([-9223372036854775808]) --- numpy/lib/arraypad.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'numpy/lib/arraypad.py') diff --git a/numpy/lib/arraypad.py b/numpy/lib/arraypad.py index daaa68d06..9f33753b7 100644 --- a/numpy/lib/arraypad.py +++ b/numpy/lib/arraypad.py @@ -104,8 +104,8 @@ def _prepend_const(arr, pad_amt, val, axis=-1): return np.concatenate((np.zeros(padshape, dtype=arr.dtype), arr), axis=axis) else: - return np.concatenate(((np.zeros(padshape) + val).astype(arr.dtype), - arr), axis=axis) + return np.concatenate((np.full(padshape, val, dtype=arr.dtype), arr), + axis=axis) def _append_const(arr, pad_amt, val, axis=-1): @@ -138,8 +138,8 @@ def _append_const(arr, pad_amt, val, axis=-1): return np.concatenate((arr, np.zeros(padshape, dtype=arr.dtype)), axis=axis) else: - return np.concatenate( - (arr, (np.zeros(padshape) + val).astype(arr.dtype)), axis=axis) + return np.concatenate((arr, np.full(padshape, val, dtype=arr.dtype)), + axis=axis) def _prepend_edge(arr, pad_amt, axis=-1): -- cgit v1.2.1 From a5f94a90adc15a4a5fb417a1fb5c6d4338b899a0 Mon Sep 17 00:00:00 2001 From: Lars G Date: Wed, 2 May 2018 17:39:24 +0200 Subject: MAINT: Simplify workflow in _append_const and _prepend_const --- numpy/lib/arraypad.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'numpy/lib/arraypad.py') diff --git a/numpy/lib/arraypad.py b/numpy/lib/arraypad.py index 9f33753b7..97ba12348 100644 --- a/numpy/lib/arraypad.py +++ b/numpy/lib/arraypad.py @@ -100,12 +100,8 @@ def _prepend_const(arr, pad_amt, val, axis=-1): return arr padshape = tuple(x if i != axis else pad_amt for (i, x) in enumerate(arr.shape)) - if val == 0: - return np.concatenate((np.zeros(padshape, dtype=arr.dtype), arr), - axis=axis) - else: - return np.concatenate((np.full(padshape, val, dtype=arr.dtype), arr), - axis=axis) + return np.concatenate((np.full(padshape, val, dtype=arr.dtype), arr), + axis=axis) def _append_const(arr, pad_amt, val, axis=-1): @@ -134,12 +130,8 @@ def _append_const(arr, pad_amt, val, axis=-1): return arr padshape = tuple(x if i != axis else pad_amt for (i, x) in enumerate(arr.shape)) - if val == 0: - return np.concatenate((arr, np.zeros(padshape, dtype=arr.dtype)), - axis=axis) - else: - return np.concatenate((arr, np.full(padshape, val, dtype=arr.dtype)), - axis=axis) + return np.concatenate((arr, np.full(padshape, val, dtype=arr.dtype)), + axis=axis) def _prepend_edge(arr, pad_amt, axis=-1): -- cgit v1.2.1