summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authornjsmith <njs@pobox.com>2013-04-12 07:12:27 -0700
committernjsmith <njs@pobox.com>2013-04-12 07:12:27 -0700
commit6ffa2ea9744e01129382b902649edfd50e848401 (patch)
tree0e3d603bc848c02977c083e8a888a011d0a5d64a /numpy
parentf1b20f92f8a959359d01de5cf05f3d6babe8e145 (diff)
parent1f8443764550ec4626469f6afd8e78de10e62b2e (diff)
downloadnumpy-6ffa2ea9744e01129382b902649edfd50e848401.tar.gz
Merge pull request #3225 from seberg/cleanup_subscript-merge
Cleanup subscript rebased
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/src/multiarray/arrayobject.c4
-rw-r--r--numpy/core/src/multiarray/convert_datatype.c2
-rw-r--r--numpy/core/src/multiarray/mapping.c668
-rw-r--r--numpy/core/src/multiarray/mapping.h14
-rw-r--r--numpy/core/src/multiarray/sequence.c4
-rw-r--r--numpy/core/tests/test_indexing.py110
6 files changed, 482 insertions, 320 deletions
diff --git a/numpy/core/src/multiarray/arrayobject.c b/numpy/core/src/multiarray/arrayobject.c
index b559d4aba..ad196e010 100644
--- a/numpy/core/src/multiarray/arrayobject.c
+++ b/numpy/core/src/multiarray/arrayobject.c
@@ -1172,12 +1172,12 @@ _void_compare(PyArrayObject *self, PyArrayObject *other, int cmp_op)
if NPY_TITLE_KEY(key, value) {
continue;
}
- a = PyArray_EnsureAnyArray(array_subscript(self, key));
+ a = array_subscript_asarray(self, key);
if (a == NULL) {
Py_XDECREF(res);
return NULL;
}
- b = array_subscript(other, key);
+ b = array_subscript_asarray(other, key);
if (b == NULL) {
Py_XDECREF(res);
Py_DECREF(a);
diff --git a/numpy/core/src/multiarray/convert_datatype.c b/numpy/core/src/multiarray/convert_datatype.c
index 586b85b1e..e1483f4e1 100644
--- a/numpy/core/src/multiarray/convert_datatype.c
+++ b/numpy/core/src/multiarray/convert_datatype.c
@@ -1817,7 +1817,7 @@ PyArray_ConvertToCommonType(PyObject *op, int *retn)
if (PyArray_Check(op)) {
for (i = 0; i < n; i++) {
- mps[i] = (PyArrayObject *) array_big_item((PyArrayObject *)op, i);
+ mps[i] = (PyArrayObject *) array_item_asarray((PyArrayObject *)op, i);
}
if (!PyArray_ISCARRAY((PyArrayObject *)op)) {
for (i = 0; i < n; i++) {
diff --git a/numpy/core/src/multiarray/mapping.c b/numpy/core/src/multiarray/mapping.c
index 6cc00edab..0b4022874 100644
--- a/numpy/core/src/multiarray/mapping.c
+++ b/numpy/core/src/multiarray/mapping.c
@@ -42,8 +42,29 @@ array_length(PyArrayObject *self)
}
}
+/* Get array item as scalar type */
NPY_NO_EXPORT PyObject *
-array_big_item(PyArrayObject *self, npy_intp i)
+array_item_asscalar(PyArrayObject *self, npy_intp i)
+{
+ char *item;
+ npy_intp dim0;
+
+ /* Bounds check and get the data pointer */
+ dim0 = PyArray_DIM(self, 0);
+ if (i < 0) {
+ i += dim0;
+ }
+ if (i < 0 || i >= dim0) {
+ PyErr_SetString(PyExc_IndexError, "index out of bounds");
+ return NULL;
+ }
+ item = PyArray_BYTES(self) + i * PyArray_STRIDE(self, 0);
+ return PyArray_Scalar(item, PyArray_DESCR(self), (PyObject *)self);
+}
+
+/* Get array item as ndarray type */
+NPY_NO_EXPORT PyObject *
+array_item_asarray(PyArrayObject *self, npy_intp i)
{
char *item;
PyArrayObject *ret;
@@ -86,40 +107,23 @@ array_big_item(PyArrayObject *self, npy_intp i)
return (PyObject *)ret;
}
-NPY_NO_EXPORT int
-_array_ass_item(PyArrayObject *self, Py_ssize_t i, PyObject *v)
-{
- return array_ass_big_item(self, (npy_intp) i, v);
-}
-
-/* contains optimization for 1-d arrays */
+/* Get array item at given index */
NPY_NO_EXPORT PyObject *
-array_item_nice(PyArrayObject *self, Py_ssize_t _i)
+array_item(PyArrayObject *self, Py_ssize_t _i)
{
/* Workaround Python 2.4: Py_ssize_t not the same as npyint_p */
npy_intp i = _i;
if (PyArray_NDIM(self) == 1) {
- char *item;
- npy_intp dim0;
-
- /* Bounds check and get the data pointer */
- dim0 = PyArray_DIM(self, 0);
- if (check_and_adjust_index(&i, dim0, 0) < 0) {
- return NULL;
- }
- item = PyArray_BYTES(self) + i * PyArray_STRIDE(self, 0);
-
- return PyArray_Scalar(item, PyArray_DESCR(self), (PyObject *)self);
+ return array_item_asscalar(self, (npy_intp) i);
}
else {
- return PyArray_Return(
- (PyArrayObject *) array_big_item(self, (npy_intp) i));
+ return array_item_asarray(self, (npy_intp) i);
}
}
NPY_NO_EXPORT int
-array_ass_big_item(PyArrayObject *self, npy_intp i, PyObject *v)
+array_ass_item_object(PyArrayObject *self, npy_intp i, PyObject *v)
{
PyArrayObject *tmp;
char *item;
@@ -138,14 +142,14 @@ array_ass_big_item(PyArrayObject *self, npy_intp i, PyObject *v)
if (PyArray_NDIM(self) == 0) {
PyErr_SetString(PyExc_IndexError,
- "0-d arrays can't be indexed.");
+ "0-d arrays can't be indexed");
return -1;
}
/* For multi-dimensional arrays, use CopyObject */
if (PyArray_NDIM(self) > 1) {
- tmp = (PyArrayObject *)array_big_item(self, i);
+ tmp = (PyArrayObject *)array_item_asarray(self, i);
if(tmp == NULL) {
return -1;
}
@@ -161,7 +165,7 @@ array_ass_big_item(PyArrayObject *self, npy_intp i, PyObject *v)
}
item = PyArray_BYTES(self) + i * PyArray_STRIDE(self, 0);
- return PyArray_DESCR(self)->f->setitem(v, item, self);
+ return PyArray_SETITEM(self, item, v);
}
/* -------------------------------------------------------------- */
@@ -306,6 +310,12 @@ PyArray_GetMap(PyArrayMapIterObject *mit)
return (PyObject *)ret;
}
+NPY_NO_EXPORT int
+array_ass_item(PyArrayObject *self, Py_ssize_t i, PyObject *v)
+{
+ return array_ass_item_object(self, (npy_intp) i, v);
+}
+
static int
PyArray_SetMap(PyArrayMapIterObject *mit, PyObject *op)
{
@@ -562,23 +572,31 @@ array_subscript_simple(PyArrayObject *self, PyObject *op)
* Unfortunately, SciPy and possibly other code seems to rely
* on the lenient coercion. :(
*/
+ if (!(PyArray_Check(op) && (PyArray_SIZE((PyArrayObject*)op) > 1))) {
#if 0 /*PY_VERSION_HEX >= 0x02050000*/
- PyObject *ind = PyNumber_Index(op);
- if (ind != NULL) {
- value = PyArray_PyIntAsIntp(ind);
- Py_DECREF(ind);
- }
- else {
- value = -1;
- }
+ PyObject *ind = PyNumber_Index(op);
+ if (ind != NULL) {
+ value = PyArray_PyIntAsIntp(ind);
+ Py_DECREF(ind);
+ }
+ else {
+ value = -1;
+ }
#else
- value = PyArray_PyIntAsIntp(op);
+ value = PyArray_PyIntAsIntp(op);
#endif
- if (value == -1 && PyErr_Occurred()) {
- PyErr_Clear();
- }
- else {
- return array_big_item(self, value);
+ if (value == -1 && PyErr_Occurred()) {
+ if (PyErr_ExceptionMatches(PyExc_TypeError)) {
+ /* Operand is not an integer type */
+ PyErr_Clear();
+ }
+ else {
+ return NULL;
+ }
+ }
+ else {
+ return array_item_asarray(self, value);
+ }
}
/* Standard (view-based) Indexing */
@@ -914,17 +932,180 @@ array_ass_boolean_subscript(PyArrayObject *self,
return 0;
}
-NPY_NO_EXPORT PyObject *
-array_subscript(PyArrayObject *self, PyObject *op)
+
+/* Check if ind is a tuple and if it has as many elements as arr has axes. */
+static NPY_INLINE int
+_is_full_index(PyObject *ind, PyArrayObject *arr)
{
- int nd, fancy;
- PyArrayObject *other;
- PyArrayMapIterObject *mit;
+ return PyTuple_Check(ind) && (PyTuple_GET_SIZE(ind) == PyArray_NDIM(arr));
+}
+
+/*
+ * Returns 0 if tuple-object seq is not a tuple of integers.
+ * If the return value is positive, vals will be filled with the elements
+ * from the tuple.
+ * Returns -1 on error.
+ */
+static int
+_tuple_of_integers(PyObject *seq, npy_intp *vals, int maxvals)
+{
+ int i;
PyObject *obj;
+ npy_intp temp;
- if (PyString_Check(op) || PyUnicode_Check(op)) {
+ for(i=0; i<maxvals; i++) {
+ obj = PyTuple_GET_ITEM(seq, i);
+ if ((PyArray_Check(obj) && PyArray_NDIM((PyArrayObject *)obj) > 0)
+ || PyList_Check(obj)) {
+ return 0;
+ }
+ temp = PyArray_PyIntAsIntp(obj);
+ if (error_converting(temp)) {
+ PyErr_Clear();
+ return 0;
+ }
+ if (!PyIndex_Check_Or_Unsupported(obj)) {
+ if (DEPRECATE("non-integer scalar index. In a future numpy "
+ "release, this will raise an error.") < 0) {
+ return -1;
+ }
+ }
+ vals[i] = temp;
+ }
+ return 1;
+}
+
+
+/* return TRUE if ellipses are found else return FALSE */
+static npy_bool
+_check_ellipses(PyObject *op)
+{
+ if ((op == Py_Ellipsis) || PyString_Check(op) || PyUnicode_Check(op)) {
+ return NPY_TRUE;
+ }
+ else if (PyBool_Check(op) || PyArray_IsScalar(op, Bool) ||
+ (PyArray_Check(op) &&
+ (PyArray_DIMS((PyArrayObject *)op)==0) &&
+ PyArray_ISBOOL((PyArrayObject *)op))) {
+ return NPY_TRUE;
+ }
+ else if (PySequence_Check(op)) {
+ Py_ssize_t n, i;
PyObject *temp;
+ n = PySequence_Size(op);
+ i = 0;
+ while (i < n) {
+ temp = PySequence_GetItem(op, i);
+ if (temp == Py_Ellipsis) {
+ Py_DECREF(temp);
+ return NPY_TRUE;
+ }
+ Py_DECREF(temp);
+ i++;
+ }
+ }
+ return NPY_FALSE;
+}
+
+NPY_NO_EXPORT PyObject *
+array_subscript_fancy(PyArrayObject *self, PyObject *op, int fancy)
+ {
+ int oned;
+ PyObject *other;
+ PyArrayMapIterObject *mit;
+
+ oned = ((PyArray_NDIM(self) == 1) &&
+ !(PyTuple_Check(op) && PyTuple_GET_SIZE(op) > 1));
+
+ /* wrap arguments into a mapiter object */
+ mit = (PyArrayMapIterObject *) PyArray_MapIterNew(op, oned, fancy);
+ if (mit == NULL) {
+ return NULL;
+ }
+ if (oned) {
+ PyArrayIterObject *it;
+ PyObject *rval;
+ it = (PyArrayIterObject *) PyArray_IterNew((PyObject *)self);
+ if (it == NULL) {
+ Py_DECREF(mit);
+ return NULL;
+ }
+ rval = iter_subscript(it, mit->indexobj);
+ Py_DECREF(it);
+ Py_DECREF(mit);
+ return rval;
+ }
+ if (PyArray_MapIterBind(mit, self) != 0) {
+ return NULL;
+ }
+ other = (PyObject *)PyArray_GetMap(mit);
+ Py_DECREF(mit);
+ return other;
+}
+
+/* make sure subscript always returns an array object */
+NPY_NO_EXPORT PyObject *
+array_subscript_asarray(PyArrayObject *self, PyObject *op)
+{
+ return PyArray_EnsureAnyArray(array_subscript(self, op));
+}
+
+NPY_NO_EXPORT PyObject *
+array_subscript_fromobject(PyArrayObject *self, PyObject *op)
+{
+ int fancy;
+ npy_intp vals[NPY_MAXDIMS];
+
+ /* Integer index */
+ if (PyArray_IsIntegerScalar(op) || (PyIndex_Check(op) &&
+ !PySequence_Check(op))) {
+ npy_intp value = PyArray_PyIntAsIntp(op);
+ if (value == -1 && PyErr_Occurred()) {
+ /* fail on error */
+ PyErr_SetString(PyExc_IndexError,
+ "cannot convert index to integer");
+ return NULL;
+ }
+ else {
+ return array_item(self, (Py_ssize_t) value);
+ }
+ }
+ /* optimization for a tuple of integers */
+ if (PyArray_NDIM(self) > 1 && _is_full_index(op, self)) {
+ int ret = _tuple_of_integers(op, vals, PyArray_NDIM(self));
+ /* In case an exception occurred (e.g. in PyErr_WarnEx) */
+ if (ret < 0) {
+ return NULL;
+ }
+ else if (ret > 0) {
+ int idim, ndim = PyArray_NDIM(self);
+ npy_intp *shape = PyArray_DIMS(self);
+ npy_intp *strides = PyArray_STRIDES(self);
+ char *item = PyArray_BYTES(self);
+ for (idim = 0; idim < ndim; idim++) {
+ npy_intp v = vals[idim];
+ if (check_and_adjust_index(&v, shape[idim], idim) < 0) {
+ return NULL;
+ }
+ item += v * strides[idim];
+ }
+ return PyArray_Scalar(item, PyArray_DESCR(self), (PyObject *)self);
+ }
+ }
+
+ if ((PyNumber_Check(op) || PyArray_IsScalar(op, Number)) &&
+ !PyIndex_Check_Or_Unsupported(op)) {
+ if (DEPRECATE("non-integer scalar index. In a future numpy "
+ "release, this will raise an error.") < 0) {
+ return NULL;
+ }
+ }
+
+ /* Check for single field access */
+ if (PyString_Check(op) || PyUnicode_Check(op)) {
+ PyObject *temp, *obj;
+
if (PyDataType_HASFIELDS(PyArray_DESCR(self))) {
obj = PyDict_GetItem(PyArray_DESCR(self)->fields, op);
if (obj != NULL) {
@@ -944,7 +1125,7 @@ array_subscript(PyArrayObject *self, PyObject *op)
temp = PyUnicode_AsUnicodeEscapeString(op);
}
PyErr_Format(PyExc_ValueError,
- "field named %s not found.",
+ "field named %s not found",
PyBytes_AsString(temp));
if (temp != op) {
Py_DECREF(temp);
@@ -957,6 +1138,7 @@ array_subscript(PyArrayObject *self, PyObject *op)
PySequence_Check(op) &&
!PyTuple_Check(op)) {
int seqlen, i;
+ PyObject *obj;
seqlen = PySequence_Size(op);
for (i = 0; i < seqlen; i++) {
obj = PySequence_GetItem(op, i);
@@ -967,7 +1149,7 @@ array_subscript(PyArrayObject *self, PyObject *op)
Py_DECREF(obj);
}
/*
- * extract multiple fields if all elements in sequence
+ * Extract multiple fields if all elements in sequence
* are either string or unicode (i.e. no break occurred).
*/
fancy = ((seqlen > 0) && (i == seqlen));
@@ -988,15 +1170,19 @@ array_subscript(PyArrayObject *self, PyObject *op)
}
}
+ /* Check for Ellipsis index */
if (op == Py_Ellipsis) {
Py_INCREF(self);
return (PyObject *)self;
}
if (PyArray_NDIM(self) == 0) {
+ int nd;
+ /* Check for None index */
if (op == Py_None) {
return add_new_axes_0d(self, 1);
}
+ /* Check for (empty) tuple index */
if (PyTuple_Check(op)) {
if (0 == PyTuple_GET_SIZE(op)) {
Py_INCREF(self);
@@ -1026,56 +1212,64 @@ array_subscript(PyArrayObject *self, PyObject *op)
NULL);
}
}
- PyErr_SetString(PyExc_IndexError, "0-d arrays can't be indexed.");
+ PyErr_SetString(PyExc_IndexError,
+ "0-dimensional arrays can't be indexed");
return NULL;
}
+ fancy = fancy_indexing_check(op);
+ if (fancy != SOBJ_NOTFANCY) {
+ return array_subscript_fancy(self, op, fancy);
+ }
+ else {
+ return array_subscript_simple(self, op);
+ }
+}
+
+NPY_NO_EXPORT PyObject *
+array_subscript(PyArrayObject *self, PyObject *op)
+{
+ int fancy;
+ PyObject *ret = NULL;
+ if (!PyArray_Check(op)) {
+ ret = array_subscript_fromobject(self, op);
+ }
+
/* Boolean indexing special case */
- /* The SIZE check might be overly cautious */
- if (PyArray_Check(op) && (PyArray_TYPE((PyArrayObject *)op) == NPY_BOOL)
+ /* The SIZE check is to ensure old behaviour for non-matching arrays. */
+ else if (PyArray_ISBOOL((PyArrayObject *)op)
&& (PyArray_NDIM(self) == PyArray_NDIM((PyArrayObject *)op))
&& (PyArray_SIZE((PyArrayObject *)op) == PyArray_SIZE(self))) {
return (PyObject *)array_boolean_subscript(self,
(PyArrayObject *)op, NPY_CORDER);
}
-
- fancy = fancy_indexing_check(op);
- if (fancy != SOBJ_NOTFANCY) {
- int oned;
-
- oned = ((PyArray_NDIM(self) == 1) &&
- !(PyTuple_Check(op) && PyTuple_GET_SIZE(op) > 1));
-
- /* wrap arguments into a mapiter object */
- mit = (PyArrayMapIterObject *) PyArray_MapIterNew(op, oned, fancy);
- if (mit == NULL) {
- return NULL;
- }
- if (oned) {
- PyArrayIterObject *it;
- PyObject *rval;
- it = (PyArrayIterObject *) PyArray_IterNew((PyObject *)self);
- if (it == NULL) {
- Py_DECREF(mit);
- return NULL;
- }
- rval = iter_subscript(it, mit->indexobj);
- Py_DECREF(it);
- Py_DECREF(mit);
- return rval;
+ /* Error case when indexing 0-dim array with non-boolean. */
+ else if (PyArray_NDIM(self) == 0) {
+ PyErr_SetString(PyExc_IndexError,
+ "0-dimensional arrays can't be indexed");
+ return NULL;
+ }
+
+ else {
+ fancy = fancy_indexing_check(op);
+ if (fancy != SOBJ_NOTFANCY) {
+ ret = array_subscript_fancy(self, op, fancy);
}
- if (PyArray_MapIterBind(mit, self) != 0) {
- return NULL;
+ else {
+ ret = array_subscript_simple(self, op);
}
- other = (PyArrayObject *)PyArray_GetMap(mit);
- Py_DECREF(mit);
- return (PyObject *)other;
}
-
- return array_subscript_simple(self, op);
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ if (PyArray_Check(ret) && PyArray_NDIM((PyArrayObject *)ret) == 0
+ && !_check_ellipses(op)) {
+ return PyArray_Return((PyArrayObject *)ret);
+ }
+ return ret;
}
-
/*
* Another assignment hacked by using CopyObject.
* This only works if subscript returns a standard view.
@@ -1092,13 +1286,20 @@ array_ass_sub_simple(PyArrayObject *self, PyObject *ind, PyObject *op)
npy_intp value;
value = PyArray_PyIntAsIntp(ind);
- if (!error_converting(value)) {
- return array_ass_big_item(self, value, op);
+ if (value == -1 && PyErr_Occurred()) {
+ if (PyErr_ExceptionMatches(PyExc_TypeError)) {
+ /* Operand is not an integer type */
+ PyErr_Clear();
+ }
+ else {
+ return -1;
+ }
+ }
+ else {
+ return array_ass_item_object(self, value, op);
}
- PyErr_Clear();
/* Rest of standard (view-based) indexing */
-
if (PyArray_CheckExact(self)) {
tmp = (PyArrayObject *)array_subscript_simple(self, ind);
if (tmp == NULL) {
@@ -1119,7 +1320,7 @@ array_ass_sub_simple(PyArrayObject *self, PyObject *ind, PyObject *op)
}
if (!PyArray_Check(tmp0)) {
PyErr_SetString(PyExc_RuntimeError,
- "Getitem not returning array.");
+ "Getitem not returning array");
Py_DECREF(tmp0);
return -1;
}
@@ -1131,53 +1332,44 @@ array_ass_sub_simple(PyArrayObject *self, PyObject *ind, PyObject *op)
return ret;
}
-/* Check if ind is a tuple and if it has as many elements as arr has axes. */
-static NPY_INLINE int
-_is_full_index(PyObject *ind, PyArrayObject *arr)
-{
- return PyTuple_Check(ind) && (PyTuple_GET_SIZE(ind) == PyArray_NDIM(arr));
-}
-
-/*
- * Returns 0 if tuple-object seq is not a tuple of integers.
- * If the return value is positive, vals will be filled with the elements
- * from the tuple.
- * Returns -1 on error.
- */
static int
-_tuple_of_integers(PyObject *seq, npy_intp *vals, int maxvals)
+array_ass_sub_fancy(PyArrayObject *self, PyObject *ind, PyObject *op, int fancy)
{
- int i;
- PyObject *obj;
- npy_intp temp;
+ int oned, ret;
+ PyArrayMapIterObject *mit;
+ oned = ((PyArray_NDIM(self) == 1) &&
+ !(PyTuple_Check(ind) && PyTuple_GET_SIZE(ind) > 1));
+ mit = (PyArrayMapIterObject *) PyArray_MapIterNew(ind, oned, fancy);
+ if (mit == NULL) {
+ return -1;
+ }
+ if (oned) {
+ PyArrayIterObject *it;
+ int rval;
- for(i=0; i<maxvals; i++) {
- obj = PyTuple_GET_ITEM(seq, i);
- if ((PyArray_Check(obj) && PyArray_NDIM((PyArrayObject *)obj) > 0)
- || PyList_Check(obj)) {
- return 0;
- }
- temp = PyArray_PyIntAsIntp(obj);
- if (error_converting(temp)) {
- return 0;
- }
- if (!PyIndex_Check_Or_Unsupported(obj)) {
- if (DEPRECATE("non-integer scalar index. In a future numpy "
- "release, this will raise an error.") < 0) {
- return -1;
- }
+ it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)self);
+ if (it == NULL) {
+ Py_DECREF(mit);
+ return -1;
}
- vals[i] = temp;
+ rval = iter_ass_subscript(it, mit->indexobj, op);
+ Py_DECREF(it);
+ Py_DECREF(mit);
+ return rval;
}
- return 1;
+ if (PyArray_MapIterBind(mit, self) != 0) {
+ return -1;
+ }
+ ret = PyArray_SetMap(mit, op);
+ Py_DECREF(mit);
+ return ret;
}
static int
array_ass_sub(PyArrayObject *self, PyObject *ind, PyObject *op)
{
- int ret, oned, fancy;
- PyArrayMapIterObject *mit;
+ int fancy;
npy_intp vals[NPY_MAXDIMS];
if (op == NULL) {
@@ -1189,19 +1381,22 @@ array_ass_sub(PyArrayObject *self, PyObject *ind, PyObject *op)
return -1;
}
- if (PyInt_Check(ind) || PyArray_IsScalar(ind, Integer) ||
- PyLong_Check(ind) || (PyIndex_Check(ind) &&
- !PySequence_Check(ind))) {
- npy_intp value;
- value = PyArray_PyIntAsIntp(ind);
- if (PyErr_Occurred()) {
- PyErr_Clear();
+ /* Integer index */
+ if (PyArray_IsIntegerScalar(ind) || (PyIndex_Check(ind) &&
+ !PySequence_Check(ind))) {
+ npy_intp value = PyArray_PyIntAsIntp(ind);
+ if (value == -1 && PyErr_Occurred()) {
+ /* fail on error */
+ PyErr_SetString(PyExc_IndexError,
+ "cannot convert index to integer");
+ return -1;
}
else {
- return array_ass_big_item(self, value, op);
+ return array_ass_item_object(self, value, op);
}
}
+ /* Single field access */
if (PyString_Check(ind) || PyUnicode_Check(ind)) {
if (PyDataType_HASFIELDS(PyArray_DESCR(self))) {
PyObject *obj;
@@ -1218,19 +1413,19 @@ array_ass_sub(PyArrayObject *self, PyObject *ind, PyObject *op)
}
}
}
-
#if defined(NPY_PY3K)
PyErr_Format(PyExc_ValueError,
- "field named %S not found.",
+ "field named %S not found",
ind);
#else
PyErr_Format(PyExc_ValueError,
- "field named %s not found.",
+ "field named %s not found",
PyString_AsString(ind));
#endif
return -1;
}
+ /* Ellipsis index */
if (ind == Py_Ellipsis) {
/*
* Doing "a[...] += 1" triggers assigning an array to itself,
@@ -1253,29 +1448,33 @@ array_ass_sub(PyArrayObject *self, PyObject *ind, PyObject *op)
* 3) Using newaxis (None)
* 4) Boolean mask indexing
*/
+
+ /* Check for None or empty tuple */
if (ind == Py_None || (PyTuple_Check(ind) &&
(0 == PyTuple_GET_SIZE(ind) ||
count_new_axes_0d(ind) > 0))) {
- return PyArray_DESCR(self)->f->setitem(op, PyArray_DATA(self), self);
+ return PyArray_SETITEM(self, PyArray_DATA(self), op);
}
+ /* Check for boolean index */
if (PyBool_Check(ind) || PyArray_IsScalar(ind, Bool) ||
(PyArray_Check(ind) &&
- (PyArray_DIMS((PyArrayObject *)ind)==0) &&
+ (PyArray_NDIM((PyArrayObject *)ind)==0) &&
PyArray_ISBOOL((PyArrayObject *)ind))) {
if (PyObject_IsTrue(ind)) {
return PyArray_CopyObject(self, op);
}
- else { /* don't do anything */
+ else { /* False: don't do anything */
return 0;
}
}
- PyErr_SetString(PyExc_IndexError, "0-d arrays can't be indexed.");
+ PyErr_SetString(PyExc_IndexError,
+ "0-dimensional arrays can't be indexed");
return -1;
}
- /* Integer-tuple */
+ /* Integer-tuple index */
if (_is_full_index(ind, self)) {
- ret = _tuple_of_integers(ind, vals, PyArray_NDIM(self));
+ int ret = _tuple_of_integers(ind, vals, PyArray_NDIM(self));
/* In case an exception occurred (e.g. in PyErr_WarnEx) */
if (ret < 0) {
return -1;
@@ -1284,7 +1483,7 @@ array_ass_sub(PyArrayObject *self, PyObject *ind, PyObject *op)
int idim, ndim = PyArray_NDIM(self);
npy_intp *shape = PyArray_DIMS(self);
npy_intp *strides = PyArray_STRIDES(self);
- char *item = PyArray_DATA(self);
+ char *item = PyArray_BYTES(self);
for (idim = 0; idim < ndim; idim++) {
npy_intp v = vals[idim];
if (check_and_adjust_index(&v, shape[idim], idim) < 0) {
@@ -1292,10 +1491,9 @@ array_ass_sub(PyArrayObject *self, PyObject *ind, PyObject *op)
}
item += v * strides[idim];
}
- return PyArray_DESCR(self)->f->setitem(op, item, self);
+ return PyArray_SETITEM(self, item, op);
}
}
- PyErr_Clear();
/* Boolean indexing special case */
if (PyArray_Check(ind) &&
@@ -1336,162 +1534,20 @@ array_ass_sub(PyArrayObject *self, PyObject *ind, PyObject *op)
fancy = fancy_indexing_check(ind);
if (fancy != SOBJ_NOTFANCY) {
-
- oned = ((PyArray_NDIM(self) == 1) &&
- !(PyTuple_Check(ind) && PyTuple_GET_SIZE(ind) > 1));
- mit = (PyArrayMapIterObject *) PyArray_MapIterNew(ind, oned, fancy);
- if (mit == NULL) {
- return -1;
- }
- if (oned) {
- PyArrayIterObject *it;
- int rval;
-
- it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)self);
- if (it == NULL) {
- Py_DECREF(mit);
- return -1;
- }
- rval = iter_ass_subscript(it, mit->indexobj, op);
- Py_DECREF(it);
- Py_DECREF(mit);
- return rval;
- }
- if (PyArray_MapIterBind(mit, self) != 0) {
- return -1;
- }
- ret = PyArray_SetMap(mit, op);
- Py_DECREF(mit);
- return ret;
- }
-
- return array_ass_sub_simple(self, ind, op);
-}
-
-
-/*
- * There are places that require that array_subscript return a PyArrayObject
- * and not possibly a scalar. Thus, this is the function exposed to
- * Python so that 0-dim arrays are passed as scalars
- */
-
-
-static PyObject *
-array_subscript_nice(PyArrayObject *self, PyObject *op)
-{
-
- PyArrayObject *mp;
- int ret;
- npy_intp vals[NPY_MAXDIMS];
-
- if (PyInt_Check(op) || PyArray_IsScalar(op, Integer) ||
- PyLong_Check(op) || (PyIndex_Check(op) &&
- !PySequence_Check(op))) {
- npy_intp value;
- value = PyArray_PyIntAsIntp(op);
- if (PyErr_Occurred()) {
- PyErr_Clear();
- }
- else {
- return array_item_nice(self, (Py_ssize_t) value);
- }
- }
- /*
- * Optimization for a tuple of integers that is the same size as the
- * array's dimension.
- */
- if (PyArray_NDIM(self) > 1 && _is_full_index(op, self)) {
- ret = _tuple_of_integers(op, vals, PyArray_NDIM(self));
- /* In case an exception occurred (e.g. in PyErr_WarnEx) */
- if (ret < 0) {
- return NULL;
- }
- else if (ret > 0) {
- int idim, ndim = PyArray_NDIM(self);
- npy_intp *shape = PyArray_DIMS(self);
- npy_intp *strides = PyArray_STRIDES(self);
- char *item = PyArray_DATA(self);
- for (idim = 0; idim < ndim; idim++) {
- npy_intp v = vals[idim];
- if (check_and_adjust_index(&v, shape[idim], idim) < 0) {
- return NULL;
- }
- item += v * strides[idim];
- }
- return PyArray_Scalar(item, PyArray_DESCR(self), (PyObject *)self);
- }
- }
- PyErr_Clear();
- if ((PyNumber_Check(op) || PyArray_IsScalar(op, Number)) &&
- !PyIndex_Check_Or_Unsupported(op)) {
- if (DEPRECATE("non-integer scalar index. In a future numpy "
- "release, this will raise an error.") < 0) {
- return NULL;
- }
- }
- mp = (PyArrayObject *)array_subscript(self, op);
- /*
- * mp could be a scalar if op is not an Int, Scalar, Long or other Index
- * object and still convertable to an integer (so that the code goes to
- * array_subscript_simple). So, this cast is a bit dangerous..
- */
-
- if (mp == NULL) {
- return NULL;
+ return array_ass_sub_fancy(self, ind, op, fancy);
}
-
- if (PyErr_Occurred()) {
- Py_XDECREF(mp);
- return NULL;
- }
-
- /*
- * The following adds some additional logic to avoid calling
- * PyArray_Return if there is an ellipsis.
- */
-
- if (PyArray_Check(mp) && PyArray_NDIM(mp) == 0) {
- npy_bool noellipses = NPY_TRUE;
- if ((op == Py_Ellipsis) || PyString_Check(op) || PyUnicode_Check(op)) {
- noellipses = NPY_FALSE;
- }
- else if (PyBool_Check(op) || PyArray_IsScalar(op, Bool) ||
- (PyArray_Check(op) &&
- (PyArray_DIMS((PyArrayObject *)op)==0) &&
- PyArray_ISBOOL((PyArrayObject *)op))) {
- noellipses = NPY_FALSE;
- }
- else if (PySequence_Check(op)) {
- Py_ssize_t n, i;
- PyObject *temp;
-
- n = PySequence_Size(op);
- i = 0;
- while (i < n && noellipses) {
- temp = PySequence_GetItem(op, i);
- if (temp == Py_Ellipsis) {
- noellipses = NPY_FALSE;
- }
- Py_DECREF(temp);
- i++;
- }
- }
- if (noellipses) {
- return PyArray_Return(mp);
- }
+ else {
+ return array_ass_sub_simple(self, ind, op);
}
-
- return (PyObject *)mp;
}
-
NPY_NO_EXPORT PyMappingMethods array_as_mapping = {
#if PY_VERSION_HEX >= 0x02050000
(lenfunc)array_length, /*mp_length*/
#else
(inquiry)array_length, /*mp_length*/
#endif
- (binaryfunc)array_subscript_nice, /*mp_subscript*/
+ (binaryfunc)array_subscript, /*mp_subscript*/
(objobjargproc)array_ass_sub, /*mp_ass_subscript*/
};
@@ -1528,6 +1584,14 @@ _nonzero_indices(PyObject *myBool, PyArrayIterObject **iters)
return -1;
}
nd = PyArray_NDIM(ba);
+
+ if (nd == 0) {
+ PyErr_SetString(PyExc_IndexError,
+ "only scalars can be indexed by 0-dimensional "
+ "boolean arrays");
+ goto fail;
+ }
+
for (j = 0; j < nd; j++) {
iters[j] = NULL;
}
@@ -1566,6 +1630,7 @@ _nonzero_indices(PyObject *myBool, PyArrayIterObject **iters)
}
/*
+
* Loop through the Boolean array and copy coordinates
* for non-zero entries
*/
@@ -1920,20 +1985,14 @@ PyArray_MapIterNew(PyObject *indexobj, int oned, int fancy)
}
mit = (PyArrayMapIterObject *)PyArray_malloc(sizeof(PyArrayMapIterObject));
+ /* set all attributes of mapiter to zero */
+ memset(mit, 0, sizeof(PyArrayMapIterObject));
PyObject_Init((PyObject *)mit, &PyArrayMapIter_Type);
if (mit == NULL) {
return NULL;
}
- for (i = 0; i < NPY_MAXDIMS; i++) {
- mit->iters[i] = NULL;
- }
- mit->index = 0;
- mit->ait = NULL;
- mit->subspace = NULL;
- mit->numiter = 0;
+ /* initialize mapiter attributes */
mit->consec = 1;
- Py_INCREF(indexobj);
- mit->indexobj = indexobj;
if (fancy == SOBJ_LISTTUP) {
PyObject *newobj;
@@ -1941,10 +2000,13 @@ PyArray_MapIterNew(PyObject *indexobj, int oned, int fancy)
if (newobj == NULL) {
goto fail;
}
- Py_DECREF(indexobj);
indexobj = newobj;
mit->indexobj = indexobj;
}
+ else {
+ Py_INCREF(indexobj);
+ mit->indexobj = indexobj;
+ }
if (oned) {
@@ -1957,8 +2019,8 @@ PyArray_MapIterNew(PyObject *indexobj, int oned, int fancy)
*/
/* convert all inputs to iterators */
- if (PyArray_Check(indexobj) &&
- (PyArray_TYPE((PyArrayObject *)indexobj) == NPY_BOOL)) {
+ if (PyArray_Check(indexobj) && PyArray_ISBOOL(indexobj)
+ && !PyArray_IsZeroDim(indexobj)) {
mit->numiter = _nonzero_indices(indexobj, mit->iters);
if (mit->numiter < 0) {
goto fail;
diff --git a/numpy/core/src/multiarray/mapping.h b/numpy/core/src/multiarray/mapping.h
index b00397436..816b3b8e6 100644
--- a/numpy/core/src/multiarray/mapping.h
+++ b/numpy/core/src/multiarray/mapping.h
@@ -7,14 +7,20 @@ extern NPY_NO_EXPORT PyMappingMethods array_as_mapping;
NPY_NO_EXPORT PyMappingMethods array_as_mapping;
#endif
-NPY_NO_EXPORT PyObject *
-array_big_item(PyArrayObject *self, npy_intp i);
-
NPY_NO_EXPORT Py_ssize_t
array_length(PyArrayObject *self);
NPY_NO_EXPORT PyObject *
-array_item_nice(PyArrayObject *self, Py_ssize_t i);
+array_item_asarray(PyArrayObject *self, npy_intp i);
+
+NPY_NO_EXPORT PyObject *
+array_item_asscalar(PyArrayObject *self, npy_intp i);
+
+NPY_NO_EXPORT PyObject *
+array_item(PyArrayObject *self, Py_ssize_t i);
+
+NPY_NO_EXPORT PyObject *
+array_subscript_asarray(PyArrayObject *self, PyObject *op);
NPY_NO_EXPORT PyObject *
array_subscript(PyArrayObject *self, PyObject *op);
diff --git a/numpy/core/src/multiarray/sequence.c b/numpy/core/src/multiarray/sequence.c
index e5f74251e..6a9ecad97 100644
--- a/numpy/core/src/multiarray/sequence.c
+++ b/numpy/core/src/multiarray/sequence.c
@@ -134,7 +134,7 @@ NPY_NO_EXPORT PySequenceMethods array_as_sequence = {
(lenfunc)array_length, /*sq_length*/
(binaryfunc)NULL, /*sq_concat is handled by nb_add*/
(ssizeargfunc)NULL,
- (ssizeargfunc)array_item_nice,
+ (ssizeargfunc)array_item,
(ssizessizeargfunc)array_slice,
(ssizeobjargproc)array_ass_item, /*sq_ass_item*/
(ssizessizeobjargproc)array_ass_slice, /*sq_ass_slice*/
@@ -145,7 +145,7 @@ NPY_NO_EXPORT PySequenceMethods array_as_sequence = {
(inquiry)array_length, /*sq_length*/
(binaryfunc)NULL, /*sq_concat is handled by nb_add*/
(intargfunc)NULL, /*sq_repeat is handled nb_multiply*/
- (intargfunc)array_item_nice, /*sq_item*/
+ (intargfunc)array_item, /*sq_item*/
(intintargfunc)array_slice, /*sq_slice*/
(intobjargproc)array_ass_item, /*sq_ass_item*/
(intintobjargproc)array_ass_slice, /*sq_ass_slice*/
diff --git a/numpy/core/tests/test_indexing.py b/numpy/core/tests/test_indexing.py
index 1a23da3c5..6906dcf6b 100644
--- a/numpy/core/tests/test_indexing.py
+++ b/numpy/core/tests/test_indexing.py
@@ -14,14 +14,108 @@ import sys, warnings
# but hopefully NumPy indexing can be changed to be more systematic
# at some point in the future.
-def test_boolean_indexing():
- # Indexing a 2-dimensional array with a length-1 array of 'True'
- a = np.array([[ 0., 0., 0.]])
- b = np.array([ True], dtype=bool)
- assert_equal(a[b], a)
-
- a[b] = 1.
- assert_equal(a, [[1., 1., 1.]])
+class TestIndexing(TestCase):
+
+ def test_none_index(self):
+ # `None` index adds newaxis
+ a = np.array([1, 2, 3])
+ assert_equal(a[None], a[np.newaxis])
+ assert_equal(a[None].ndim, a.ndim + 1)
+
+ def test_empty_tuple_index(self):
+ # Empty tuple index creates a view
+ a = np.array([1, 2, 3])
+ assert_equal(a[()], a)
+ assert_(a[()].base is a)
+
+ def test_empty_fancy_index(self):
+ # Empty list index creates an empty array
+ # with the same dtype (but with weird shape)
+ a = np.array([1, 2, 3])
+ assert_equal(a[[]], [])
+ assert_equal(a[[]].dtype, a.dtype)
+
+ b = np.array([], dtype=np.intp)
+ assert_equal(a[[]], [])
+ assert_equal(a[[]].dtype, a.dtype)
+
+ b = np.array([])
+ assert_raises(IndexError, a.__getitem__, b)
+
+ def test_ellipsis_index(self):
+ # Ellipsis index does not create a view
+ a = np.array([[1, 2, 3],
+ [4 ,5, 6],
+ [7, 8, 9]])
+ assert_equal(a[...], a)
+ assert_(a[...] is a)
+
+ # Slicing with ellipsis can skip an
+ # arbitrary number of dimensions
+ assert_equal(a[0, ...], a[0])
+ assert_equal(a[0, ...], a[0, :])
+ assert_equal(a[..., 0], a[:, 0])
+
+ # Slicing with ellipsis always results
+ # in an array, not a scalar
+ assert_equal(a[0, ..., 1], np.array(2))
+
+ def test_single_int_index(self):
+ # Single integer index selects one row
+ a = np.array([[1, 2, 3],
+ [4 ,5, 6],
+ [7, 8, 9]])
+
+ assert_equal(a[0], [1, 2, 3])
+ assert_equal(a[-1], [7, 8, 9])
+
+ # Index out of bounds produces IndexError
+ assert_raises(IndexError, a.__getitem__, 1<<30)
+ # Index overflow produces IndexError
+ assert_raises(IndexError, a.__getitem__, 1<<64)
+
+ def test_single_bool_index(self):
+ # Single boolean index
+ a = np.array([[1, 2, 3],
+ [4 ,5, 6],
+ [7, 8, 9]])
+
+ # Python boolean converts to integer
+ assert_equal(a[True], a[1])
+ assert_equal(a[False], a[0])
+
+ # Same with NumPy boolean scalar
+ assert_equal(a[np.array(True)], a[1])
+ assert_equal(a[np.array(False)], a[0])
+
+ def test_boolean_indexing_onedim(self):
+ # Indexing a 2-dimensional array with
+ # boolean array of length one
+ a = np.array([[ 0., 0., 0.]])
+ b = np.array([ True], dtype=bool)
+ assert_equal(a[b], a)
+ # boolean assignment
+ a[b] = 1.
+ assert_equal(a, [[1., 1., 1.]])
+
+ def test_boolean_indexing_twodim(self):
+ # Indexing a 2-dimensional array with
+ # 2-dimensional boolean array
+ a = np.array([[1, 2, 3],
+ [4 ,5, 6],
+ [7, 8, 9]])
+ b = np.array([[ True, False, True],
+ [False, True, False],
+ [ True, False, True]])
+ assert_equal(a[b], [1, 3, 5, 7, 9])
+ assert_equal(a[b[1]], [[4, 5, 6]])
+ assert_equal(a[b[0]], a[b[2]])
+
+ # boolean assignment
+ a[b] = 0
+ assert_equal(a, [[0, 2, 0],
+ [4, 0, 6],
+ [0, 8, 0]])
if __name__ == "__main__":
run_module_suite()