summaryrefslogtreecommitdiff
path: root/numpy/core
diff options
context:
space:
mode:
authorSebastian Berg <sebastian@sipsolutions.net>2015-09-27 17:27:29 +0200
committerSebastian Berg <sebastian@sipsolutions.net>2015-09-27 17:27:29 +0200
commite06bad5fb0dc377da54412a0d127461f21cf8553 (patch)
tree514b16753a4e701ac8f844921dc20b53d0995397 /numpy/core
parent97c35365beda55c6dead8c50df785eb857f843f0 (diff)
downloadnumpy-e06bad5fb0dc377da54412a0d127461f21cf8553.tar.gz
REV: Make sure ravel returns a contiguous array
This is a bit more then it used to do, so it is not a complete revert. Some of the "weird" cases where a copy was unnecessarily done will now only be gone with RELAXED_STRIDES_CHECKING.
Diffstat (limited to 'numpy/core')
-rw-r--r--numpy/core/src/multiarray/shape.c36
-rw-r--r--numpy/core/tests/test_multiarray.py56
2 files changed, 50 insertions, 42 deletions
diff --git a/numpy/core/src/multiarray/shape.c b/numpy/core/src/multiarray/shape.c
index b679d6d5d..f46f820ca 100644
--- a/numpy/core/src/multiarray/shape.c
+++ b/numpy/core/src/multiarray/shape.c
@@ -940,55 +940,51 @@ PyArray_Ravel(PyArrayObject *arr, NPY_ORDER order)
order = NPY_FORTRANORDER;
}
}
+ else if (order == NPY_ANYORDER) {
+ order = PyArray_ISFORTRAN(arr) ? NPY_FORTRANORDER : NPY_CORDER;
+ }
- if (order != NPY_KEEPORDER) {
- return PyArray_Newshape(arr, &newdim, order);
+ if (order == NPY_CORDER && PyArray_IS_C_CONTIGUOUS(arr)) {
+ return PyArray_Newshape(arr, &newdim, NPY_CORDER);
+ }
+ else if (order == NPY_FORTRANORDER && PyArray_IS_F_CONTIGUOUS(arr)) {
+ return PyArray_Newshape(arr, &newdim, NPY_FORTRANORDER);
}
/* For KEEPORDER, check if we can make a flattened view */
- else {
+ else if (order == NPY_KEEPORDER) {
npy_stride_sort_item strideperm[NPY_MAXDIMS];
- npy_intp stride = 0, base_stride = NPY_MIN_INTP;
+ npy_intp stride;
int i, ndim = PyArray_NDIM(arr);
PyArray_CreateSortedStridePerm(PyArray_NDIM(arr),
PyArray_STRIDES(arr), strideperm);
+ /* The output array must be contiguous, so the first stride is fixed */
+ stride = PyArray_ITEMSIZE(arr);
+
for (i = ndim-1; i >= 0; --i) {
if (PyArray_DIM(arr, strideperm[i].perm) == 1) {
/* A size one dimension does not matter */
continue;
}
- if (base_stride == NPY_MIN_INTP) {
- stride = strideperm[i].stride;
- base_stride = stride;
- }
- else if (strideperm[i].stride != stride) {
+ if (strideperm[i].stride != stride) {
break;
}
stride *= PyArray_DIM(arr, strideperm[i].perm);
}
-#if NPY_RELAXED_STRIDES_CHECKING == 0
- /*
- * For tidyness, cannot be reached with relaxed strides checking
- * since the array is guaranteed contiguous (without, not sure...)
- */
- if (base_stride == NPY_MIN_INTP) {
- base_stride = PyArray_ITEMSIZE(arr);
- }
-#endif
-
/* If all the strides matched a contiguous layout, return a view */
if (i < 0) {
PyArrayObject *ret;
+ stride = PyArray_ITEMSIZE(arr);
val[0] = PyArray_SIZE(arr);
Py_INCREF(PyArray_DESCR(arr));
ret = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(arr),
PyArray_DESCR(arr),
1, val,
- &base_stride,
+ &stride,
PyArray_BYTES(arr),
PyArray_FLAGS(arr),
(PyObject *)arr);
diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py
index a2667172c..5a73aa935 100644
--- a/numpy/core/tests/test_multiarray.py
+++ b/numpy/core/tests/test_multiarray.py
@@ -2075,41 +2075,37 @@ class TestMethods(TestCase):
assert_equal(a.ravel(order='K'), [2, 3, 0, 1])
assert_(a.ravel(order='K').flags.owndata)
+ # Test simple 1-d copy behaviour:
+ a = np.arange(10)[::2]
+ assert_(a.ravel('K').flags.owndata)
+ assert_(a.ravel('C').flags.owndata)
+ assert_(a.ravel('F').flags.owndata)
+
# Not contiguous and 1-sized axis with non matching stride
a = np.arange(2**3 * 2)[::2]
a = a.reshape(2, 1, 2, 2).swapaxes(-1, -2)
strides = list(a.strides)
strides[1] = 123
a.strides = strides
- assert_(np.may_share_memory(a.ravel(order='K'), a))
+ assert_(a.ravel(order='K').flags.owndata)
assert_equal(a.ravel('K'), np.arange(0, 15, 2))
- # General case of possible ravel that is not contiguous but
- # works and includes a 1-sized axis with non matching stride
- a = a.swapaxes(-1, -2) # swap back to C-order
- assert_(np.may_share_memory(a.ravel(order='C'), a))
- assert_(np.may_share_memory(a.ravel(order='K'), a))
-
- a = a.T # swap all to Fortran order
- assert_(np.may_share_memory(a.ravel(order='F'), a))
+ # contiguous and 1-sized axis with non matching stride works:
+ a = np.arange(2**3)
+ a = a.reshape(2, 1, 2, 2).swapaxes(-1, -2)
+ strides = list(a.strides)
+ strides[1] = 123
+ a.strides = strides
assert_(np.may_share_memory(a.ravel(order='K'), a))
+ assert_equal(a.ravel(order='K'), np.arange(2**3))
- # Test negative strides:
+ # Test negative strides (not very interesting since non-contiguous):
a = np.arange(4)[::-1].reshape(2, 2)
- assert_(np.may_share_memory(a.ravel(order='C'), a))
- assert_(np.may_share_memory(a.ravel(order='K'), a))
+ assert_(a.ravel(order='C').flags.owndata)
+ assert_(a.ravel(order='K').flags.owndata)
assert_equal(a.ravel('C'), [3, 2, 1, 0])
assert_equal(a.ravel('K'), [3, 2, 1, 0])
- # Test keeporder with weirdly strided 1-sized dims (1-d first stride)
- a = np.arange(8)[::2].reshape(1, 2, 2, 1) # neither C, nor F order
- strides = list(a.strides)
- strides[0] = -12
- strides[-1] = 0
- a.strides = strides
- assert_(np.may_share_memory(a.ravel(order='K'), a))
- assert_equal(a.ravel('K'), a.ravel('C'))
-
# 1-element tidy strides test (NPY_RELAXED_STRIDES_CHECKING):
a = np.array([[1]])
a.strides = (123, 432)
@@ -2125,7 +2121,7 @@ class TestMethods(TestCase):
assert_equal(a.ravel(order), [0])
assert_(np.may_share_memory(a.ravel(order), a))
- #Test that certain non-inplace ravels work right (mostly) for 'K':
+ # Test that certain non-inplace ravels work right (mostly) for 'K':
b = np.arange(2**4 * 2)[::2].reshape(2, 2, 2, 2)
a = b[..., ::2]
assert_equal(a.ravel('K'), [0, 4, 8, 12, 16, 20, 24, 28])
@@ -2139,6 +2135,22 @@ class TestMethods(TestCase):
assert_equal(a.ravel('A'), [0, 2, 4, 6, 8, 10, 12, 14])
assert_equal(a.ravel('F'), [0, 8, 4, 12, 2, 10, 6, 14])
+ def test_ravel_subclass(self):
+ class ArraySubclass(np.ndarray):
+ pass
+
+ a = np.arange(10).view(ArraySubclass)
+ assert_(isinstance(a.ravel('C'), ArraySubclass))
+ assert_(isinstance(a.ravel('F'), ArraySubclass))
+ assert_(isinstance(a.ravel('A'), ArraySubclass))
+ assert_(isinstance(a.ravel('K'), ArraySubclass))
+
+ a = np.arange(10)[::2].view(ArraySubclass)
+ assert_(isinstance(a.ravel('C'), ArraySubclass))
+ assert_(isinstance(a.ravel('F'), ArraySubclass))
+ assert_(isinstance(a.ravel('A'), ArraySubclass))
+ assert_(isinstance(a.ravel('K'), ArraySubclass))
+
def test_swapaxes(self):
a = np.arange(1*2*3*4).reshape(1, 2, 3, 4).copy()
idx = np.indices(a.shape)