diff options
author | Charles Harris <charlesr.harris@gmail.com> | 2012-10-08 15:41:16 -0600 |
---|---|---|
committer | Charles Harris <charlesr.harris@gmail.com> | 2012-10-08 15:41:16 -0600 |
commit | 926c5adbf74ee5e9b51fcc8fc8ffc0aa6ee309bc (patch) | |
tree | 71becddac587f3d298997c54f8a80483f9a64775 /numpy/core | |
parent | 3f10c36339c0fe40e72378a990e6b3c5423805fb (diff) | |
parent | 65bd91defe76f225d27b58a21a89dc5dcf7c53c2 (diff) | |
download | numpy-926c5adbf74ee5e9b51fcc8fc8ffc0aa6ee309bc.tar.gz |
Merge PR 377: expose Mapiter in the numpy API.
* PR-377:
inplace passes tests
fixed tests
added initial mapiter tests
eliminated oned and fancy arguments to MapIterArray
changed error handling for clarity
removed expsure of mapiter type
changed the name of _swap_axes
gave MapIter an API
Diffstat (limited to 'numpy/core')
-rw-r--r-- | numpy/core/code_generators/cversions.txt | 2 | ||||
-rw-r--r-- | numpy/core/code_generators/genapi.py | 1 | ||||
-rw-r--r-- | numpy/core/code_generators/numpy_api.py | 3 | ||||
-rw-r--r-- | numpy/core/setup_common.py | 2 | ||||
-rw-r--r-- | numpy/core/src/multiarray/mapping.c | 47 | ||||
-rw-r--r-- | numpy/core/src/multiarray/multiarray_tests.c.src | 134 | ||||
-rw-r--r-- | numpy/core/tests/test_multiarray.py | 17 |
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() |