summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/code_generators/cversions.txt2
-rw-r--r--numpy/core/code_generators/genapi.py1
-rw-r--r--numpy/core/code_generators/numpy_api.py3
-rw-r--r--numpy/core/setup_common.py2
-rw-r--r--numpy/core/src/multiarray/mapping.c47
-rw-r--r--numpy/core/src/multiarray/multiarray_tests.c.src134
-rw-r--r--numpy/core/tests/test_multiarray.py17
7 files changed, 195 insertions, 11 deletions
diff --git a/numpy/core/code_generators/cversions.txt b/numpy/core/code_generators/cversions.txt
index 5bdb33c94..7d3b43d3b 100644
--- a/numpy/core/code_generators/cversions.txt
+++ b/numpy/core/code_generators/cversions.txt
@@ -11,3 +11,5 @@
0x00000006 = e61d5dc51fa1c6459328266e215d6987
# Version 7 (NumPy 1.7) improved datetime64, misc utilities.
0x00000007 = e396ba3912dcf052eaee1b0b203a7724
+# Version 8 Added interface to MapIterObject
+0x00000008 = 17321775fc884de0b1eda478cd61c74b
diff --git a/numpy/core/code_generators/genapi.py b/numpy/core/code_generators/genapi.py
index 3860fe6d7..32b0972a7 100644
--- a/numpy/core/code_generators/genapi.py
+++ b/numpy/core/code_generators/genapi.py
@@ -41,6 +41,7 @@ API_FILES = [join('multiarray', 'array_assign_array.c'),
join('multiarray', 'getset.c'),
join('multiarray', 'item_selection.c'),
join('multiarray', 'iterators.c'),
+ join('multiarray', 'mapping.c'),
join('multiarray', 'methods.c'),
join('multiarray', 'multiarraymodule.c'),
join('multiarray', 'nditer_api.c'),
diff --git a/numpy/core/code_generators/numpy_api.py b/numpy/core/code_generators/numpy_api.py
index cb598880b..16278f1a2 100644
--- a/numpy/core/code_generators/numpy_api.py
+++ b/numpy/core/code_generators/numpy_api.py
@@ -330,6 +330,9 @@ multiarray_funcs_api = {
'PyDataMem_FREE': 289,
'PyDataMem_RENEW': 290,
'PyDataMem_SetEventHook': 291,
+ 'PyArray_MapIterSwapAxes': 293,
+ 'PyArray_MapIterArray': 294,
+ 'PyArray_MapIterNext': 295,
}
ufunc_types_api = {
diff --git a/numpy/core/setup_common.py b/numpy/core/setup_common.py
index 58876a8e4..83589695d 100644
--- a/numpy/core/setup_common.py
+++ b/numpy/core/setup_common.py
@@ -29,7 +29,7 @@ C_ABI_VERSION = 0x01000009
# without breaking binary compatibility. In this case, only the C_API_VERSION
# (*not* C_ABI_VERSION) would be increased. Whenever binary compatibility is
# broken, both C_API_VERSION and C_ABI_VERSION should be increased.
-C_API_VERSION = 0x00000007
+C_API_VERSION = 0x00000008
class MismatchCAPIWarning(Warning):
pass
diff --git a/numpy/core/src/multiarray/mapping.c b/numpy/core/src/multiarray/mapping.c
index d414a1fbb..31446ca41 100644
--- a/numpy/core/src/multiarray/mapping.c
+++ b/numpy/core/src/multiarray/mapping.c
@@ -166,8 +166,11 @@ array_ass_big_item(PyArrayObject *self, npy_intp i, PyObject *v)
/* -------------------------------------------------------------- */
-static void
-_swap_axes(PyArrayMapIterObject *mit, PyArrayObject **ret, int getmap)
+/*NUMPY_API
+ *
+*/
+NPY_NO_EXPORT void
+PyArray_MapIterSwapAxes(PyArrayMapIterObject *mit, PyArrayObject **ret, int getmap)
{
PyObject *new;
int n1, n2, n3, val, bnd;
@@ -297,7 +300,7 @@ PyArray_GetMap(PyArrayMapIterObject *mit)
/* check for consecutive axes */
if ((mit->subspace != NULL) && (mit->consec)) {
if (mit->iteraxes[0] > 0) { /* then we need to swap */
- _swap_axes(mit, &ret, 1);
+ PyArray_MapIterSwapAxes(mit, &ret, 1);
}
}
return (PyObject *)ret;
@@ -326,7 +329,7 @@ PyArray_SetMap(PyArrayMapIterObject *mit, PyObject *op)
}
if ((mit->subspace != NULL) && (mit->consec)) {
if (mit->iteraxes[0] > 0) { /* then we need to swap */
- _swap_axes(mit, &arr, 0);
+ PyArray_MapIterSwapAxes(mit, &arr, 0);
if (arr == NULL) {
return -1;
}
@@ -1628,7 +1631,7 @@ PyArray_MapIterReset(PyArrayMapIterObject *mit)
return;
}
-/*
+/*NUMPY_API
* This function needs to update the state of the map iterator
* and point mit->dataptr to the memory-location of the next object
*/
@@ -1899,11 +1902,6 @@ PyArray_MapIterNew(PyObject *indexobj, int oned, int fancy)
mit->indexobj = indexobj;
}
-#undef SOBJ_NOTFANCY
-#undef SOBJ_ISFANCY
-#undef SOBJ_BADARRAY
-#undef SOBJ_TOOMANY
-#undef SOBJ_LISTTUP
if (oned) {
return (PyObject *)mit;
@@ -2028,6 +2026,35 @@ PyArray_MapIterNew(PyObject *indexobj, int oned, int fancy)
return NULL;
}
+/*NUMPY_API
+*/
+NPY_NO_EXPORT PyObject *
+PyArray_MapIterArray(PyArrayObject * a, PyObject * index)
+{
+ PyArrayMapIterObject * mit;
+ int fancy = fancy_indexing_check(index);
+ int oned = 0;
+ if (fancy != SOBJ_NOTFANCY) {
+
+ oned = ((PyArray_NDIM(a) == 1) &&
+ !(PyTuple_Check(index) && PyTuple_GET_SIZE(index) > 1));
+ }
+ mit = (PyArrayMapIterObject *) PyArray_MapIterNew(index, oned, fancy);
+ if (mit == NULL) {
+ return NULL;
+ }
+
+ PyArray_MapIterBind(mit, a);
+ PyArray_MapIterReset(mit);
+ return mit;
+}
+
+
+#undef SOBJ_NOTFANCY
+#undef SOBJ_ISFANCY
+#undef SOBJ_BADARRAY
+#undef SOBJ_TOOMANY
+#undef SOBJ_LISTTUP
static void
arraymapiter_dealloc(PyArrayMapIterObject *mit)
diff --git a/numpy/core/src/multiarray/multiarray_tests.c.src b/numpy/core/src/multiarray/multiarray_tests.c.src
index 9e46624bf..954097e28 100644
--- a/numpy/core/src/multiarray/multiarray_tests.c.src
+++ b/numpy/core/src/multiarray/multiarray_tests.c.src
@@ -428,6 +428,137 @@ test_pydatamem_seteventhook_end(PyObject* NPY_UNUSED(self), PyObject* NPY_UNUSED
return Py_None;
}
+
+typedef void (*inplace_map_binop)(PyArrayMapIterObject *, PyArrayIterObject *);
+
+static void npy_float64_inplace_add(PyArrayMapIterObject *mit, PyArrayIterObject *it)
+{
+ int index = mit->size;
+ while (index--) {
+ ((npy_float64*)mit->dataptr)[0] = ((npy_float64*)mit->dataptr)[0] + ((npy_float64*)it->dataptr)[0];
+
+ PyArray_MapIterNext(mit);
+ PyArray_ITER_NEXT(it);
+ }
+}
+
+inplace_map_binop addition_funcs[] = {
+npy_float64_inplace_add,
+NULL};
+
+int type_numbers[] = {
+NPY_FLOAT64,
+-1000};
+
+
+
+static int
+map_increment(PyArrayMapIterObject *mit, PyObject *op, inplace_map_binop add_inplace)
+{
+ PyArrayObject *arr = NULL;
+ PyArrayIterObject *it;
+ PyArray_Descr *descr;
+
+ if (mit->ait == NULL) {
+ return -1;
+ }
+ descr = PyArray_DESCR(mit->ait->ao);
+ Py_INCREF(descr);
+ arr = (PyArrayObject *)PyArray_FromAny(op, descr,
+ 0, 0, NPY_ARRAY_FORCECAST, NULL);
+ if (arr == NULL) {
+ return -1;
+ }
+
+ if ((mit->subspace != NULL) && (mit->consec)) {
+ if (mit->iteraxes[0] > 0) {
+ PyArray_MapIterSwapAxes(mit, (PyArrayObject **)&arr, 0);
+ if (arr == NULL) {
+ return -1;
+ }
+ }
+ }
+
+ if ((it = (PyArrayIterObject *)\
+ PyArray_BroadcastToShape(arr, mit->dimensions, mit->nd)) == NULL) {
+ Py_DECREF(arr);
+
+ return -1;
+ }
+
+ (*add_inplace)(mit, it);
+
+ Py_DECREF(arr);
+ Py_DECREF(it);
+ return 0;
+}
+
+
+static PyObject *
+inplace_increment(PyObject *dummy, PyObject *args)
+{
+ PyObject *arg_a = NULL, *index=NULL, *inc=NULL;
+ PyArrayObject *a;
+ inplace_map_binop add_inplace = NULL;
+ int type_number = -1;
+ int i =0;
+ PyArrayMapIterObject * mit;
+
+ if (!PyArg_ParseTuple(args, "OOO", &arg_a, &index,
+ &inc)) {
+ return NULL;
+ }
+ if (!PyArray_Check(arg_a)) {
+ PyErr_SetString(PyExc_ValueError, "needs an ndarray as first argument");
+ return NULL;
+ }
+ a = (PyArrayObject *) arg_a;
+
+ if (PyArray_FailUnlessWriteable(a, "input/output array") < 0) {
+ return NULL;
+ }
+
+ if (PyArray_NDIM(a) == 0) {
+ PyErr_SetString(PyExc_IndexError, "0-d arrays can't be indexed.");
+ return NULL;
+ }
+ type_number = PyArray_TYPE(a);
+
+
+
+
+ while (type_numbers[i] >= 0 && addition_funcs[i] != NULL){
+ if (type_number == type_numbers[i]) {
+ add_inplace = addition_funcs[i];
+ break;
+ }
+ i++ ;
+ }
+
+ if (add_inplace == NULL) {
+ PyErr_SetString(PyExc_TypeError, "unsupported type for a");
+ return NULL;
+ }
+
+ mit = (PyArrayMapIterObject *) PyArray_MapIterArray(a, index);
+ if (mit == NULL) {
+ goto fail;
+ }
+
+ if (map_increment(mit, inc, add_inplace) != 0) {
+ goto fail;
+ }
+
+ Py_DECREF(mit);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+
+fail:
+ Py_XDECREF(mit);
+
+ return NULL;
+}
static PyMethodDef Multiarray_TestsMethods[] = {
{"test_neighborhood_iterator",
test_neighborhood_iterator,
@@ -441,6 +572,9 @@ static PyMethodDef Multiarray_TestsMethods[] = {
{"test_pydatamem_seteventhook_end",
test_pydatamem_seteventhook_end,
METH_NOARGS, NULL},
+ {"test_inplace_increment",
+ inplace_increment,
+ METH_VARARGS, NULL},
{NULL, NULL, 0, NULL} /* Sentinel */
};
diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py
index e554d79fc..5b3f0de0e 100644
--- a/numpy/core/tests/test_multiarray.py
+++ b/numpy/core/tests/test_multiarray.py
@@ -12,6 +12,7 @@ from test_print import in_foreign_locale
from numpy.core.multiarray_tests import (
test_neighborhood_iterator, test_neighborhood_iterator_oob,
test_pydatamem_seteventhook_start, test_pydatamem_seteventhook_end,
+ test_inplace_increment
)
from numpy.testing import (
TestCase, run_module_suite, assert_, assert_raises,
@@ -2837,6 +2838,22 @@ class TestMemEventHook(TestCase):
del a
test_pydatamem_seteventhook_end()
+class TestMapIter(TestCase):
+ def test_mapiter(self):
+ # The actual tests are within the C code in
+ # multiarray/multiarray_tests.c.src
+
+ a = arange(12).reshape((3,4)).astype(float)
+ index = ([1,1,2,0],
+ [0,0,2,3])
+ vals = [50,50, 30,16]
+
+ test_inplace_increment(a, index, vals)
+ assert_equal(a, [[ 0. , 1., 2., 19.,],
+ [ 104., 5., 6., 7.,],
+ [ 8., 9., 40., 11.,]])
+
+
if __name__ == "__main__":
run_module_suite()