summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Berg <sebastian@sipsolutions.net>2017-03-26 14:17:25 +0200
committerSebastian Berg <sebastian@sipsolutions.net>2017-04-29 18:22:02 +0200
commitbfb41d6a93b92b6a0aa92075d6163690bb6ed71c (patch)
treeb495b264f8f2171654e44d51a337b5fbc32243bb
parentef2cfe12c49ab377cfbf2f54993699b92229b907 (diff)
downloadnumpy-bfb41d6a93b92b6a0aa92075d6163690bb6ed71c.tar.gz
ENH: Allow removal of 0-sized axes from nditer and empty gufunc calls
The caller should take of not using pointers given in such a case
-rw-r--r--doc/release/1.13.0-notes.rst18
-rw-r--r--numpy/core/src/multiarray/nditer_api.c6
-rw-r--r--numpy/core/src/umath/ufunc_object.c37
3 files changed, 18 insertions, 43 deletions
diff --git a/doc/release/1.13.0-notes.rst b/doc/release/1.13.0-notes.rst
index bf4f1c815..f802b4c12 100644
--- a/doc/release/1.13.0-notes.rst
+++ b/doc/release/1.13.0-notes.rst
@@ -99,6 +99,24 @@ now issue a DeprecationWarning - ``.__getitem__(slice(start, end))`` should be
used instead.
+C API
+-----
+
+GUfuncs on empty arrays and NpyIter axis removal
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+It is now allowed to remove a zero-sized axis from NpyIter. Which may mean
+that code removing axes from NpyIter has to add an additional check when
+accessing the removed dimensions later on.
+
+The largest followup change is that gufuncs are now allowed to have zero-sized
+inner dimensions. This means that a gufunc now has to anticipate an empty inner
+dimension, while this was never possible and an error raised instead.
+
+For most gufuncs no change should be necessary. However, it is now possible
+for gufuncs with a signature such as ``(..., N, M) -> (..., M)`` to return
+a valid result if ``N=0`` without further wrapping code.
+
+
New Features
============
diff --git a/numpy/core/src/multiarray/nditer_api.c b/numpy/core/src/multiarray/nditer_api.c
index da3c85ae0..f2bc23715 100644
--- a/numpy/core/src/multiarray/nditer_api.c
+++ b/numpy/core/src/multiarray/nditer_api.c
@@ -106,12 +106,6 @@ NpyIter_RemoveAxis(NpyIter *iter, int axis)
return NPY_FAIL;
}
- if (NAD_SHAPE(axisdata_del) == 0) {
- PyErr_SetString(PyExc_ValueError,
- "cannot remove a zero-sized axis from an iterator");
- return NPY_FAIL;
- }
-
/* Adjust the permutation */
for (idim = 0; idim < ndim-1; ++idim) {
npy_int8 p = (idim < xdim) ? perm[idim] : perm[idim+1];
diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c
index caa36bd2d..52c2a6454 100644
--- a/numpy/core/src/umath/ufunc_object.c
+++ b/numpy/core/src/umath/ufunc_object.c
@@ -3269,14 +3269,6 @@ PyUFunc_Accumulate(PyUFuncObject *ufunc, PyArrayObject *arr, PyArrayObject *out,
op[0] = NpyIter_GetOperandArray(iter)[0];
op[1] = NpyIter_GetOperandArray(iter)[1];
- if (PyArray_SIZE(op[0]) == 0) {
- if (out == NULL) {
- out = op[0];
- Py_INCREF(out);
- }
- goto finish;
- }
-
if (NpyIter_RemoveAxis(iter, axis) != NPY_SUCCEED) {
goto fail;
}
@@ -3623,35 +3615,6 @@ PyUFunc_Reduceat(PyUFuncObject *ufunc, PyArrayObject *arr, PyArrayObject *ind,
need_outer_iterator = 1;
}
- /* Special case when the index array's size is zero */
- if (ind_size == 0) {
- if (out == NULL) {
- npy_intp out_shape[NPY_MAXDIMS];
- memcpy(out_shape, PyArray_SHAPE(arr),
- PyArray_NDIM(arr) * NPY_SIZEOF_INTP);
- out_shape[axis] = 0;
- Py_INCREF(op_dtypes[0]);
- op[0] = out = (PyArrayObject *)PyArray_NewFromDescr(
- &PyArray_Type, op_dtypes[0],
- PyArray_NDIM(arr), out_shape, NULL, NULL,
- 0, NULL);
- if (out == NULL) {
- goto fail;
- }
- }
- else {
- /* Allow any zero-sized output array in this case */
- if (PyArray_SIZE(out) != 0) {
- PyErr_SetString(PyExc_ValueError,
- "output operand shape for reduceat is "
- "incompatible with index array of shape (0,)");
- goto fail;
- }
- }
-
- goto finish;
- }
-
if (need_outer_iterator) {
npy_uint32 flags = NPY_ITER_ZEROSIZE_OK|
NPY_ITER_REFS_OK|