diff options
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/core/src/multiarray/common.c | 3 | ||||
-rw-r--r-- | numpy/core/src/umath/ufunc_object.c | 17 | ||||
-rw-r--r-- | numpy/core/tests/test_multiarray.py | 14 | ||||
-rw-r--r-- | numpy/core/tests/test_ufunc.py | 16 | ||||
-rw-r--r-- | numpy/lib/function_base.py | 74 | ||||
-rw-r--r-- | numpy/lib/stride_tricks.py | 2 | ||||
-rw-r--r-- | numpy/lib/tests/test_function_base.py | 83 | ||||
-rw-r--r-- | numpy/lib/twodim_base.py | 8 |
8 files changed, 208 insertions, 9 deletions
diff --git a/numpy/core/src/multiarray/common.c b/numpy/core/src/multiarray/common.c index c216daa95..bd566b77b 100644 --- a/numpy/core/src/multiarray/common.c +++ b/numpy/core/src/multiarray/common.c @@ -476,6 +476,9 @@ PyArray_DTypeFromObjectHelper(PyObject *obj, int maxdims, * __len__ is not defined. */ if (maxdims == 0 || !PySequence_Check(obj) || PySequence_Size(obj) < 0) { + // clear any PySequence_Size error, which corrupts further calls to it + PyErr_Clear(); + if (*out_dtype == NULL || (*out_dtype)->type_num != NPY_OBJECT) { Py_XDECREF(*out_dtype); *out_dtype = PyArray_DescrFromType(NPY_OBJECT); diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c index a472cf9f0..c4a2b8560 100644 --- a/numpy/core/src/umath/ufunc_object.c +++ b/numpy/core/src/umath/ufunc_object.c @@ -3270,17 +3270,22 @@ PyUFunc_Accumulate(PyUFuncObject *ufunc, PyArrayObject *arr, PyArrayObject *out, NPY_BEGIN_THREADS_NDITER(iter); do { - dataptr_copy[0] = dataptr[0]; dataptr_copy[1] = dataptr[1]; dataptr_copy[2] = dataptr[0]; /* Copy the first element to start the reduction */ if (otype == NPY_OBJECT) { + /* + * Input (dataptr[0]) and output (dataptr[1]) may point + * to the same memory (i.e. np.add.accumulate(a, out=a)). + * In that case need to incref before decref to avoid the + * possibility of the reference count being zero temporarily. + */ + Py_XINCREF(*(PyObject **)dataptr_copy[1]); Py_XDECREF(*(PyObject **)dataptr_copy[0]); *(PyObject **)dataptr_copy[0] = *(PyObject **)dataptr_copy[1]; - Py_XINCREF(*(PyObject **)dataptr_copy[0]); } else { memcpy(dataptr_copy[0], dataptr_copy[1], itemsize); @@ -3333,10 +3338,16 @@ PyUFunc_Accumulate(PyUFuncObject *ufunc, PyArrayObject *arr, PyArrayObject *out, /* Copy the first element to start the reduction */ if (otype == NPY_OBJECT) { + /* + * Input (dataptr[0]) and output (dataptr[1]) may point + * to the same memory (i.e. np.add.accumulate(a, out=a, axis=0)). + * In that case need to incref before decref to avoid the + * possibility of the reference count being zero temporarily. + */ + Py_XINCREF(*(PyObject **)dataptr_copy[1]); Py_XDECREF(*(PyObject **)dataptr_copy[0]); *(PyObject **)dataptr_copy[0] = *(PyObject **)dataptr_copy[1]; - Py_XINCREF(*(PyObject **)dataptr_copy[0]); } else { memcpy(dataptr_copy[0], dataptr_copy[1], itemsize); diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index a6c8489ef..14a902b9c 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -716,6 +716,20 @@ class TestCreation(TestCase): assert_raises(ValueError, np.array, C()) # segfault? + def test_failed_len_sequence(self): + # gh-7393 + class A(object): + def __init__(self, data): + self._data = data + def __getitem__(self, item): + return type(self)(self._data[item]) + def __len__(self): + return len(self._data) + + # len(d) should give 3, but len(d[0]) will fail + d = A([1,2,3]) + assert_equal(len(np.array(d)), 3) + class TestStructured(TestCase): def test_subarray_field_access(self): diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py index eb0985386..ab8cecff0 100644 --- a/numpy/core/tests/test_ufunc.py +++ b/numpy/core/tests/test_ufunc.py @@ -649,6 +649,22 @@ class TestUfunc(TestCase): assert_equal(np.array([[1]], dtype=object).sum(), 1) assert_equal(np.array([[[1, 2]]], dtype=object).sum((0, 1)), [1, 2]) + def test_object_array_accumulate_inplace(self): + # Checks that in-place accumulates work, see also gh-7402 + arr = np.ones(4, dtype=object) + arr[:] = [[1] for i in range(4)] + # Twice reproduced also for tuples: + np.add.accumulate(arr, out=arr) + np.add.accumulate(arr, out=arr) + assert_array_equal(arr, np.array([[1]*i for i in [1, 3, 6, 10]])) + + # And the same if the axis argument is used + arr = np.ones((2, 4), dtype=object) + arr[0, :] = [[2] for i in range(4)] + np.add.accumulate(arr, out=arr, axis=-1) + np.add.accumulate(arr, out=arr, axis=-1) + assert_array_equal(arr[0, :], np.array([[2]*i for i in [1, 3, 6, 10]])) + def test_object_scalar_multiply(self): # Tickets #2469 and #4482 arr = np.matrix([1, 2], dtype=object) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index efa51173a..a2a24618b 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -36,7 +36,7 @@ if sys.version_info[0] < 3: __all__ = [ 'select', 'piecewise', 'trim_zeros', 'copy', 'iterable', 'percentile', - 'diff', 'gradient', 'angle', 'unwrap', 'sort_complex', 'disp', + 'diff', 'gradient', 'angle', 'unwrap', 'sort_complex', 'disp', 'flip', 'extract', 'place', 'vectorize', 'asarray_chkfinite', 'average', 'histogram', 'histogramdd', 'bincount', 'digitize', 'cov', 'corrcoef', 'msort', 'median', 'sinc', 'hamming', 'hanning', 'bartlett', @@ -45,6 +45,78 @@ __all__ = [ ] +def flip(m, axis): + """ + Reverse the order of elements in an array along the given axis. + + The shape of the array is preserved, but the elements are reordered. + + .. versionadded:: 1.12.0 + + Parameters + ---------- + m : array_like + Input array. + axis: integer + Axis in array, which entries are reversed. + + + Returns + ------- + out : array_like + A view of `m` with the entries of axis reversed. Since a view is + returned, this operation is done in constant time. + + See Also + -------- + flipud : Flip an array vertically (axis=0). + fliplr : Flip an array horizontally (axis=1). + + Notes + ----- + flip(m, 0) is equivalent to flipud(m). + flip(m, 1) is equivalent to fliplr(m). + flip(m, n) corresponds to ``m[...,::-1,...]`` with ``::-1`` at position n. + + Examples + -------- + >>> A = np.arange(8).reshape((2,2,2)) + >>> A + array([[[0, 1], + [2, 3]], + + [[4, 5], + [6, 7]]]) + + >>> flip(A, 0) + array([[[4, 5], + [6, 7]], + + [[0, 1], + [2, 3]]]) + + >>> flip(A, 1) + array([[[2, 3], + [0, 1]], + + [[6, 7], + [4, 5]]]) + + >>> A = np.random.randn(3,4,5) + >>> np.all(flip(A,2) == A[:,:,::-1,...]) + True + """ + if not hasattr(m, 'ndim'): + m = asarray(m) + indexer = [slice(None)] * m.ndim + try: + indexer[axis] = slice(None, None, -1) + except IndexError: + raise ValueError("axis=%i is invalid for the %i-dimensional input array" + % (axis, m.ndim)) + return m[tuple(indexer)] + + def iterable(y): """ Check whether or not an object can be iterated over. diff --git a/numpy/lib/stride_tricks.py b/numpy/lib/stride_tricks.py index af09fd373..a87c34fb5 100644 --- a/numpy/lib/stride_tricks.py +++ b/numpy/lib/stride_tricks.py @@ -175,7 +175,7 @@ def broadcast_to(array, shape, subok=False): def _broadcast_shape(*args): - """Returns the shape of the ararys that would result from broadcasting the + """Returns the shape of the arrays that would result from broadcasting the supplied arrays against each other. """ if not args: diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index 943544dd5..91ead0998 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -23,6 +23,89 @@ from numpy.lib import ( from numpy.compat import long +def get_mat(n): + data = np.arange(n) + data = np.add.outer(data, data) + return data + + +class TestFlip(TestCase): + def test_axes(self): + self.assertRaises(ValueError, np.flip, np.ones(4), axis=1) + self.assertRaises(ValueError, np.flip, np.ones((4, 4)), axis=2) + self.assertRaises(ValueError, np.flip, np.ones((4, 4)), axis=-3) + + def test_basic_lr(self): + a = get_mat(4) + b = a[:, ::-1] + assert_equal(np.flip(a, 1), b) + a = [[0, 1, 2], + [3, 4, 5]] + b = [[2, 1, 0], + [5, 4, 3]] + assert_equal(np.flip(a, 1), b) + + def test_basic_ud(self): + a = get_mat(4) + b = a[::-1, :] + assert_equal(np.flip(a, 0), b) + a = [[0, 1, 2], + [3, 4, 5]] + b = [[3, 4, 5], + [0, 1, 2]] + assert_equal(np.flip(a, 0), b) + + def test_3d_swap_axis0(self): + a = np.array([[[0, 1], + [2, 3]], + + [[4, 5], + [6, 7]]]) + + b = np.array([[[4, 5], + [6, 7]], + + [[0, 1], + [2, 3]]]) + + assert_equal(np.flip(a, 0), b) + + def test_3d_swap_axis1(self): + a = np.array([[[0, 1], + [2, 3]], + + [[4, 5], + [6, 7]]]) + + b = np.array([[[2, 3], + [0, 1]], + + [[6, 7], + [4, 5]]]) + + assert_equal(np.flip(a, 1), b) + + def test_3d_swap_axis2(self): + a = np.array([[[0, 1], + [2, 3]], + + [[4, 5], + [6, 7]]]) + + b = np.array([[[1, 0], + [3, 2]], + + [[5, 4], + [7, 6]]]) + + assert_equal(np.flip(a, 2), b) + + def test_4d(self): + a = np.arange(2 * 3 * 4 * 5).reshape(2, 3, 4, 5) + for i in range(a.ndim): + assert_equal(np.flip(a, i), np.flipud(a.swapaxes(0, i)).swapaxes(i, 0)) + + class TestAny(TestCase): def test_basic(self): diff --git a/numpy/lib/twodim_base.py b/numpy/lib/twodim_base.py index 6728ab7ec..aefe8d64b 100644 --- a/numpy/lib/twodim_base.py +++ b/numpy/lib/twodim_base.py @@ -57,7 +57,7 @@ def fliplr(m): Notes ----- - Equivalent to A[:,::-1]. Requires the array to be at least 2-D. + Equivalent to m[:,::-1]. Requires the array to be at least 2-D. Examples -------- @@ -72,7 +72,7 @@ def fliplr(m): [ 3., 0., 0.]]) >>> A = np.random.randn(2,3,5) - >>> np.all(np.fliplr(A)==A[:,::-1,...]) + >>> np.all(np.fliplr(A) == A[:,::-1,...]) True """ @@ -107,7 +107,7 @@ def flipud(m): Notes ----- - Equivalent to ``A[::-1,...]``. + Equivalent to ``m[::-1,...]``. Does not require the array to be two-dimensional. Examples @@ -123,7 +123,7 @@ def flipud(m): [ 1., 0., 0.]]) >>> A = np.random.randn(2,3,5) - >>> np.all(np.flipud(A)==A[::-1,...]) + >>> np.all(np.flipud(A) == A[::-1,...]) True >>> np.flipud([1,2]) |