Skip to content

Commit

Permalink
Merge pull request numpy#2702 from seberg/issue2700
Browse files Browse the repository at this point in the history
BUG: Reshape of 0-sized arrays failed to work without copy.
  • Loading branch information
stefanv committed Nov 7, 2012
2 parents 526b764 + 0d275f1 commit 93be7c0
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 95 deletions.
136 changes: 41 additions & 95 deletions numpy/core/src/multiarray/shape.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@

#include "shape.h"

static int
_check_ones(PyArrayObject *self, int newnd,
npy_intp* newdims, npy_intp *strides);

static int
_fix_unknown_dimension(PyArray_Dims *newshape, npy_intp s_original);

Expand Down Expand Up @@ -187,6 +183,11 @@ PyArray_Newshape(PyArrayObject *self, PyArray_Dims *newdims,
if (order == NPY_ANYORDER) {
order = PyArray_ISFORTRAN(self);
}
else if (order == NPY_KEEPORDER) {
PyErr_SetString(PyExc_ValueError,
"order 'K' is not permitted for reshaping");
return NULL;
}
/* Quick check to make sure anything actually needs to be done */
if (ndim == PyArray_NDIM(self)) {
same = NPY_TRUE;
Expand All @@ -203,68 +204,48 @@ PyArray_Newshape(PyArrayObject *self, PyArray_Dims *newdims,
}

/*
* Returns a pointer to an appropriate strides array
* if all we are doing is inserting ones into the shape,
* or removing ones from the shape
* or doing a combination of the two
* In this case we don't need to do anything but update strides and
* dimensions. So, we can handle non single-segment cases.
* fix any -1 dimensions and check new-dimensions against old size
*/
i = _check_ones(self, ndim, dimensions, newstrides);
if (i == 0) {
strides = newstrides;
if (_fix_unknown_dimension(newdims, PyArray_SIZE(self)) < 0) {
return NULL;
}
flags = PyArray_FLAGS(self);

if (strides == NULL) {
/*
* we are really re-shaping not just adding ones to the shape somewhere
* fix any -1 dimensions and check new-dimensions against old size
*/
if (_fix_unknown_dimension(newdims, PyArray_SIZE(self)) < 0) {
return NULL;
/*
* sometimes we have to create a new copy of the array
* in order to get the right orientation and
* because we can't just re-use the buffer with the
* data in the order it is in.
*/
if ((order == NPY_CORDER && !PyArray_IS_C_CONTIGUOUS(self)) ||
(order == NPY_FORTRANORDER && !PyArray_IS_F_CONTIGUOUS(self))) {
int success = 0;
success = _attempt_nocopy_reshape(self, ndim, dimensions,
newstrides, order);
if (success) {
/* no need to copy the array after all */
strides = newstrides;
}
/*
* sometimes we have to create a new copy of the array
* in order to get the right orientation and
* because we can't just re-use the buffer with the
* data in the order it is in.
*/
if (!(PyArray_ISONESEGMENT(self)) ||
(((PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS) &&
order == NPY_FORTRANORDER) ||
(PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS) &&
order == NPY_CORDER)) && (PyArray_NDIM(self) > 1))) {
int success = 0;
success = _attempt_nocopy_reshape(self, ndim, dimensions,
newstrides, order);
if (success) {
/* no need to copy the array after all */
strides = newstrides;
}
else {
PyObject *newcopy;
newcopy = PyArray_NewCopy(self, order);
if (newcopy == NULL) {
return NULL;
}
incref = NPY_FALSE;
self = (PyArrayObject *)newcopy;
else {
PyObject *newcopy;
newcopy = PyArray_NewCopy(self, order);
if (newcopy == NULL) {
return NULL;
}
incref = NPY_FALSE;
self = (PyArrayObject *)newcopy;
}
}
/* We always have to interpret the contiguous buffer correctly */

/* We always have to interpret the contiguous buffer correctly */

/* Make sure the flags argument is set. */
if (ndim > 1) {
if (order == NPY_FORTRANORDER) {
flags &= ~NPY_ARRAY_C_CONTIGUOUS;
flags |= NPY_ARRAY_F_CONTIGUOUS;
}
else {
flags &= ~NPY_ARRAY_F_CONTIGUOUS;
flags |= NPY_ARRAY_C_CONTIGUOUS;
}
/* Make sure the flags argument is set. */
flags = PyArray_FLAGS(self);
if (ndim > 1) {
if (order == NPY_FORTRANORDER) {
flags &= ~NPY_ARRAY_C_CONTIGUOUS;
flags |= NPY_ARRAY_F_CONTIGUOUS;
}
else {
flags &= ~NPY_ARRAY_F_CONTIGUOUS;
flags |= NPY_ARRAY_C_CONTIGUOUS;
}
}

Expand Down Expand Up @@ -319,41 +300,6 @@ PyArray_Reshape(PyArrayObject *self, PyObject *shape)
return ret;
}

/* inserts 0 for strides where dimension will be 1 */
static int
_check_ones(PyArrayObject *self, int newnd,
npy_intp* newdims, npy_intp *strides)
{
int nd;
npy_intp *dims;
npy_bool done=NPY_FALSE;
int j, k;

nd = PyArray_NDIM(self);
dims = PyArray_DIMS(self);

for (k = 0, j = 0; !done && (j < nd || k < newnd);) {
if ((j<nd) && (k<newnd) && (newdims[k] == dims[j])) {
strides[k] = PyArray_STRIDES(self)[j];
j++;
k++;
}
else if ((k < newnd) && (newdims[k] == 1)) {
strides[k] = 0;
k++;
}
else if ((j<nd) && (dims[j] == 1)) {
j++;
}
else {
done = NPY_TRUE;
}
}
if (done) {
return -1;
}
return 0;
}

static void
_putzero(char *optr, PyObject *zero, PyArray_Descr *dtype)
Expand Down
5 changes: 5 additions & 0 deletions numpy/core/tests/test_regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,11 @@ def test_reshape_zero_strides(self, level=rlevel):
a = np.lib.stride_tricks.as_strided(a, shape=(5,), strides=(0,))
assert_(a.reshape(5,1).strides[0] == 0)

def test_reshape_zero_size(self, level=rlevel):
"""Github Issue #2700, setting shape failed for 0-sized arrays"""
a = np.ones((0,2))
a.shape = (-1,2)

def test_repeat_discont(self, level=rlevel):
"""Ticket #352"""
a = np.arange(12).reshape(4,3)[:,2]
Expand Down

0 comments on commit 93be7c0

Please sign in to comment.