summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortirthasheshpatel <tirthasheshpatel@gmail.com>2019-12-03 17:49:40 +0530
committerSebastian Berg <sebastian@sipsolutions.net>2020-01-17 08:00:51 -0600
commit7ef6b65fa960fcedcef8a27b1c3ef8c67ebb2078 (patch)
tree6954965f8d0c8f93d69e86e83d647f81510f5eb5
parent190ac3e99015ddded029d8811829da1b48b69b97 (diff)
downloadnumpy-7ef6b65fa960fcedcef8a27b1c3ef8c67ebb2078.tar.gz
BUG: `np.resize` negative shape and subclasses edge case fixes
When a negative entry is passed into `np.resize` shape, an error will now be raised reliably. Previously the `-1` semantics of reshape allowed edge cases to pass and return incorrect results. In the corner case of an empty result shape or empty input shape, the result type will now be preserved.
-rw-r--r--numpy/core/fromnumeric.py30
-rw-r--r--numpy/core/tests/test_numeric.py28
2 files changed, 46 insertions, 12 deletions
diff --git a/numpy/core/fromnumeric.py b/numpy/core/fromnumeric.py
index f09f2a465..d63e410f6 100644
--- a/numpy/core/fromnumeric.py
+++ b/numpy/core/fromnumeric.py
@@ -1377,10 +1377,17 @@ def resize(a, new_shape):
See Also
--------
+ np.reshape : Reshape an array without changing the total size.
+ np.pad : Enlarge and pad an array.
+ np.repeat: Repeat elements of an array.
ndarray.resize : resize an array in-place.
Notes
-----
+ When the total size of the array does not change `~numpy.reshape` should
+ be used. In most other cases either indexing (to reduce the size)
+ or padding (to increase the size) may be a more appropriate solution.
+
Warning: This functionality does **not** consider axes separately,
i.e. it does not apply interpolation/extrapolation.
It fills the return array with the required number of elements, taken
@@ -1404,22 +1411,21 @@ def resize(a, new_shape):
"""
if isinstance(new_shape, (int, nt.integer)):
new_shape = (new_shape,)
+
a = ravel(a)
- Na = len(a)
- total_size = um.multiply.reduce(new_shape)
- if Na == 0 or total_size == 0:
- return mu.zeros(new_shape, a.dtype)
- n_copies = int(total_size / Na)
- extra = total_size % Na
+ new_size = 1
+ for dim_length in new_shape:
+ new_size *= dim_length
+ if dim_length < 0:
+ raise ValueError('all elements of `new_shape` must be non-negative')
- if extra != 0:
- n_copies = n_copies + 1
- extra = Na - extra
+ if a.size == 0 or new_size == 0:
+ # First case must zero fill. The second would have repeats == 0.
+ return np.zeros_like(a, shape=new_shape)
- a = concatenate((a,) * n_copies)
- if extra > 0:
- a = a[:-extra]
+ repeats = -(-new_size // a.size) # ceil division
+ a = concatenate((a,) * repeats)[:new_size]
return reshape(a, new_shape)
diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py
index ffebdf648..22706a812 100644
--- a/numpy/core/tests/test_numeric.py
+++ b/numpy/core/tests/test_numeric.py
@@ -29,6 +29,17 @@ class TestResize(object):
Ar3 = np.array([[1, 2, 3], [4, 1, 2], [3, 4, 1], [2, 3, 4]])
assert_equal(np.resize(A, (4, 3)), Ar3)
+ def test_repeats(self):
+ A = np.array([1, 2, 3])
+ Ar1 = np.array([[1, 2, 3, 1], [2, 3, 1, 2]])
+ assert_equal(np.resize(A, (2, 4)), Ar1)
+
+ Ar2 = np.array([[1, 2], [3, 1], [2, 3], [1, 2]])
+ assert_equal(np.resize(A, (4, 2)), Ar2)
+
+ Ar3 = np.array([[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]])
+ assert_equal(np.resize(A, (4, 3)), Ar3)
+
def test_zeroresize(self):
A = np.array([[1, 2], [3, 4]])
Ar = np.resize(A, (0,))
@@ -48,6 +59,23 @@ class TestResize(object):
assert_array_equal(Ar, np.zeros((2, 1), Ar.dtype))
assert_equal(A.dtype, Ar.dtype)
+ def test_negative_resize(self):
+ A = np.arange(0, 10, dtype=np.float32)
+ new_shape = (-10, -1)
+ with pytest.raises(ValueError, match=r"negative"):
+ np.resize(A, new_shape=new_shape)
+
+ def test_subclass(self):
+ class MyArray(np.ndarray):
+ __array_priority__ = 1.
+
+ my_arr = np.array([1]).view(MyArray)
+ assert type(np.resize(my_arr, 5)) is MyArray
+ assert type(np.resize(my_arr, 0)) is MyArray
+
+ my_arr = np.array([]).view(MyArray)
+ assert type(np.resize(my_arr, 5)) is MyArray
+
class TestNonarrayArgs(object):
# check that non-array arguments to functions wrap them in arrays