Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

don't copy data when changing shape #145

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion numpy/core/include/numpy/ndarraytypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,10 @@ typedef enum {
/* Fortran order */
NPY_FORTRANORDER=1,
/* An order as close to the inputs as possible */
NPY_KEEPORDER=2
NPY_KEEPORDER=2,
/* Don't copy data, so order obviously is kept.
* used as special value in PyArray_Newshape */
NPY_NOCOPY=3
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this may be a bad idea. This is a general enum in the publicly exposed API, so a special value for one API function isn't appropriate. Further, NOCOPY seems to have roughly the same meaning as KEEPORDER.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, NOCOPY has a very different meaning from KEEPORDER. The latter means that the order ought to
be kept (hence the name) while copying, while NOCOPY means that the data should not be copied.

} NPY_ORDER;

/* For specifying allowed casting in operations which support it */
Expand Down
13 changes: 6 additions & 7 deletions numpy/core/src/multiarray/getset.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,16 @@ array_shape_set(PyArrayObject *self, PyObject *val)
{
int nd;
PyArrayObject *ret;
PyArray_Dims newdims;

/* Assumes C-order */
ret = (PyArrayObject *)PyArray_Reshape(self, val);
if (ret == NULL) {
if (!PyArray_IntpConverter(val, &newdims)) {
return -1;
}
if (PyArray_DATA(ret) != PyArray_DATA(self)) {
Py_DECREF(ret);
PyErr_SetString(PyExc_AttributeError,
"incompatible shape for a non-contiguous "\
"array");
ret = (PyArrayObject *)PyArray_Newshape(self, &newdims, NPY_NOCOPY);
PyDimMem_FREE(newdims.ptr);

if (ret == NULL) {
return -1;
}

Expand Down
20 changes: 15 additions & 5 deletions numpy/core/src/multiarray/shape.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,11 @@ PyArray_Resize(PyArrayObject *self, PyArray_Dims *newshape, int refcheck,
* Returns a new array
* with the new shape from the data
* in the old array --- order-perspective depends on order argument.
* copy-only-if-necessary
* The data is copied only if it is necessary. Otherwise a view
* on the original array is returned. Copying can be prevented by setting
* `order` to the special value `NPY_NOCOPY`, which is equivalent to
* `NPY_CORDER`, just that an `AttributeError` is flagged if reshaping
* is impossible without copying.
*/

/*NUMPY_API
Expand Down Expand Up @@ -236,16 +240,17 @@ PyArray_Newshape(PyArrayObject *self, PyArray_Dims *newdims,
(((PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS) &&
order == NPY_FORTRANORDER) ||
(PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS) &&
order == NPY_CORDER)) && (PyArray_NDIM(self) > 1))) {
(order == NPY_CORDER || order == NPY_NOCOPY)
)) && (PyArray_NDIM(self) > 1))) {
int success = 0;
success = _attempt_nocopy_reshape(self,n,dimensions,
newstrides,order);
success = _attempt_nocopy_reshape(self,n,dimensions, newstrides,
order == NPY_NOCOPY ? NPY_CORDER : order);
if (success) {
/* no need to copy the array after all */
strides = newstrides;
flags = PyArray_FLAGS(self);
}
else {
else if (order != NPY_NOCOPY) {
PyObject *new;
new = PyArray_NewCopy(self, order);
if (new == NULL) {
Expand All @@ -255,6 +260,11 @@ PyArray_Newshape(PyArrayObject *self, PyArray_Dims *newdims,
self = (PyArrayObject *)new;
flags = PyArray_FLAGS(self);
}
else {
PyErr_SetString(PyExc_AttributeError,
"incompatible shape for a non-contiguous array");
return NULL;
}
}

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