diff options
author | Marten van Kerkwijk <mhvk@astro.utoronto.ca> | 2018-08-04 15:15:42 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-08-04 15:15:42 +0200 |
commit | 9d0225b800df3c2b0bffee9960df87b15527509c (patch) | |
tree | 5d8116dd77dcc89c5df42b7d3ef28b0eda28e62d /numpy/core | |
parent | b5e01bcb668da0413170a886c258e00d2540e752 (diff) | |
parent | 537135661dd2b589bca1969f1cef24525b4a95d0 (diff) | |
download | numpy-9d0225b800df3c2b0bffee9960df87b15527509c.tar.gz |
Merge pull request #11615 from seberg/clip_order
BUG: Clip uses wrong memory order in output
Diffstat (limited to 'numpy/core')
-rw-r--r-- | numpy/core/src/multiarray/calculation.c | 33 | ||||
-rw-r--r-- | numpy/core/tests/test_numeric.py | 20 |
2 files changed, 39 insertions, 14 deletions
diff --git a/numpy/core/src/multiarray/calculation.c b/numpy/core/src/multiarray/calculation.c index e47dd81b9..90ee2c5b2 100644 --- a/numpy/core/src/multiarray/calculation.c +++ b/numpy/core/src/multiarray/calculation.c @@ -5,6 +5,7 @@ #define NPY_NO_DEPRECATED_API NPY_API_VERSION #define _MULTIARRAYMODULE #include "numpy/arrayobject.h" +#include "lowlevel_strided_loops.h" #include "npy_config.h" @@ -1102,7 +1103,18 @@ PyArray_Clip(PyArrayObject *self, PyObject *min, PyObject *max, PyArrayObject *o if (out == newin) { outgood = 1; } - if (!outgood && PyArray_ISONESEGMENT(out) && + + + /* make sure the shape of the output array is the same */ + if (!PyArray_SAMESHAPE(newin, out)) { + PyErr_SetString(PyExc_ValueError, "clip: Output array must have the" + "same shape as the input."); + goto fail; + } + + if (!outgood && PyArray_EQUIVALENTLY_ITERABLE( + self, out, PyArray_TRIVIALLY_ITERABLE_OP_READ, + PyArray_TRIVIALLY_ITERABLE_OP_NOREAD) && PyArray_CHKFLAGS(out, NPY_ARRAY_ALIGNED) && PyArray_ISNOTSWAPPED(out) && PyArray_EquivTypes(PyArray_DESCR(out), indescr)) { @@ -1111,15 +1123,19 @@ PyArray_Clip(PyArrayObject *self, PyObject *min, PyObject *max, PyArrayObject *o /* * Do we still not have a suitable output array? - * Create one, now + * Create one, now. No matter why the array is not suitable a copy has + * to be made. This may be just to avoid memory overlap though. */ if (!outgood) { int oflags; - if (PyArray_ISFORTRAN(out)) + if (PyArray_ISFORTRAN(self)) { oflags = NPY_ARRAY_FARRAY; - else + } + else { oflags = NPY_ARRAY_CARRAY; - oflags |= NPY_ARRAY_WRITEBACKIFCOPY | NPY_ARRAY_FORCECAST; + } + oflags |= (NPY_ARRAY_WRITEBACKIFCOPY | NPY_ARRAY_FORCECAST | + NPY_ARRAY_ENSURECOPY); Py_INCREF(indescr); newout = (PyArrayObject*)PyArray_FromArray(out, indescr, oflags); if (newout == NULL) { @@ -1131,13 +1147,6 @@ PyArray_Clip(PyArrayObject *self, PyObject *min, PyObject *max, PyArrayObject *o Py_INCREF(newout); } - /* make sure the shape of the output array is the same */ - if (!PyArray_SAMESHAPE(newin, newout)) { - PyErr_SetString(PyExc_ValueError, "clip: Output array must have the" - "same shape as the input."); - goto fail; - } - /* Now we can call the fast-clip function */ min_data = max_data = NULL; if (mina != NULL) { diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py index 53486dc51..a1a92ef32 100644 --- a/numpy/core/tests/test_numeric.py +++ b/numpy/core/tests/test_numeric.py @@ -1530,7 +1530,7 @@ class TestClip(object): m = -0.5 M = 0.6 self.fastclip(a, m, M, a) - self.clip(a, m, M, ac) + self.clip(ac, m, M, ac) assert_array_strict_equal(a, ac) def test_noncontig_inplace(self): @@ -1543,7 +1543,7 @@ class TestClip(object): m = -0.5 M = 0.6 self.fastclip(a, m, M, a) - self.clip(a, m, M, ac) + self.clip(ac, m, M, ac) assert_array_equal(a, ac) def test_type_cast_01(self): @@ -1722,6 +1722,22 @@ class TestClip(object): self.clip(a, m, M, act) assert_array_strict_equal(ac, act) + def test_clip_with_out_transposed(self): + # Test that the out argument works when tranposed + a = np.arange(16).reshape(4, 4) + out = np.empty_like(a).T + a.clip(4, 10, out=out) + expected = self.clip(a, 4, 10) + assert_array_equal(out, expected) + + def test_clip_with_out_memory_overlap(self): + # Test that the out argument works when it has memory overlap + a = np.arange(16).reshape(4, 4) + ac = a.copy() + a[:-1].clip(4, 10, out=a[1:]) + expected = self.clip(ac[:-1], 4, 10) + assert_array_equal(a[1:], expected) + def test_clip_inplace_array(self): # Test native double input with array min/max a = self._generate_data(self.nr, self.nc) |