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

Added inplace_increment function #326

Closed
wants to merge 27 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
2d4fc32
added index increment function
jsalvatier Jun 25, 2012
ef1d021
made index_increment return the array; if the input wasn't the right …
jsalvatier Jun 25, 2012
6af27c5
made index increment require a double array
jsalvatier Jun 26, 2012
82587d3
made index increment require a double array
jsalvatier Jun 26, 2012
e9b0c2b
improved error handling
jsalvatier Jun 26, 2012
ccc1189
added support for multiple datatypes
jsalvatier Jun 27, 2012
745faa8
only goto fail if we've initialized mit
jsalvatier Jun 27, 2012
5aef9c7
added initial doc
jsalvatier Jun 27, 2012
86b15d6
renamed index_increment to inplace_increment
jsalvatier Jun 27, 2012
a47e934
made inplace_increment import by default
jsalvatier Jun 27, 2012
77d5341
updated examples
jsalvatier Jun 27, 2012
e6cecf9
supported complex types
jsalvatier Jun 27, 2012
47b1f15
added initial tests
jsalvatier Jun 27, 2012
27bd77b
added more tests
jsalvatier Jun 27, 2012
420a241
fixed tests mostly
jsalvatier Jun 27, 2012
3085f98
fixed boolean test
jsalvatier Jun 27, 2012
7d03753
added another example
jsalvatier Jul 6, 2012
6f84384
fixed formatting issues that travis pointed out
jsalvatier Jul 18, 2012
68cafc1
fixed style issues
jsalvatier Jul 23, 2012
684ac6a
added more types and refactored typing generation; it seems kind of c…
jsalvatier Jul 23, 2012
16603b5
corrected a segfault issue from reformatting
jsalvatier Jul 23, 2012
bd513bf
Revert "added more types and refactored typing generation; it seems k…
jsalvatier Jul 23, 2012
f9314aa
forgot ;
jsalvatier Jul 23, 2012
44a1c49
added other datatypes
jsalvatier Jul 23, 2012
6a80aba
added check for non-array
jsalvatier Jul 23, 2012
73b36f4
moved the looping into the datatype specific functions and simplified…
jsalvatier Jul 25, 2012
d862f52
Merge remote-tracking branch 'main/master'
jsalvatier Nov 6, 2012
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
53 changes: 53 additions & 0 deletions numpy/add_newdocs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2231,6 +2231,59 @@ def luf(lamdaexpr, *args, **kwargs):
30

""")

add_newdoc('numpy.core.multiarray', 'inplace_increment',
"""
inplace_increment(a, index, inc)

Increments `a` inplace by `inc` in the locations specified by the index tuple
`index`. Supports advanced indexing. Repeated indexes are repeatedly
incremented.

Parameters
----------
a : ndarray
Array to increment.
index : tuple of indexes
Supports advanced indexing.
inc : array_like
How much to increment `a`.

Returns
-------
output : None

Examples
--------
>>> a = arange(12).reshape((3,4)).astype(float64)
>>> index = ([1,1,2,0], [0,0,2,3])
>>> vals = [50,50, 30,16]
>>> a
array([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.]])
>>> inplace_increment(a, index, vals)
>>> a
array([[ 0., 1., 2., 19.],
[ 104., 5., 6., 7.],
[ 8., 9., 40., 11.]])

>>> x = zeros((3,3))
>>> x
array([[ 0., 0., 0.],
[ 0., 0., 0.],
[ 0., 0., 0.]])
>>> y = arange(3*3).reshape((3,3))
>>> y
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
>>> inplace_increment(x, [0,1,1], y)
>>> x
array([[ 0., 1., 2.],
[ 9., 11., 13.],
[ 0., 0., 0.]])
""")


##############################################################################
Expand Down
3 changes: 2 additions & 1 deletion numpy/core/bscript
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@ def pre_build(context):
"src/multiarray/arraytypes.c.src",
"src/multiarray/nditer_templ.c.src",
"src/multiarray/lowlevel_strided_loops.c.src",
"src/multiarray/mapping.c.src",
"src/multiarray/einsum.c.src"]
bld(target="multiarray_templates", source=multiarray_templates)
if ENABLE_SEPARATE_COMPILATION:
Expand All @@ -449,7 +450,7 @@ def pre_build(context):
pjoin('src', 'multiarray', 'item_selection.c'),
pjoin('src', 'multiarray', 'iterators.c'),
pjoin('src', 'multiarray', 'lowlevel_strided_loops.c.src'),
pjoin('src', 'multiarray', 'mapping.c'),
pjoin('src', 'multiarray', 'mapping.c.src'),
pjoin('src', 'multiarray', 'methods.c'),
pjoin('src', 'multiarray', 'multiarraymodule.c'),
pjoin('src', 'multiarray', 'nditer_pywrap.c'),
Expand Down
3 changes: 2 additions & 1 deletion numpy/core/numeric.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
'alterdot', 'restoredot', 'roll', 'rollaxis', 'cross', 'tensordot',
'array2string', 'get_printoptions', 'set_printoptions',
'array_repr', 'array_str', 'set_string_function',
'little_endian', 'require',
'little_endian', 'require', 'inplace_increment',
'fromiter', 'array_equal', 'array_equiv',
'indices', 'fromfunction', 'isclose',
'load', 'loads', 'isscalar', 'binary_repr', 'base_repr',
Expand Down Expand Up @@ -252,6 +252,7 @@ def extend_all(module):
compare_chararrays = multiarray.compare_chararrays
putmask = multiarray.putmask
einsum = multiarray.einsum
inplace_increment = multiarray.inplace_increment

def asarray(a, dtype=None, order=None):
"""
Expand Down
3 changes: 2 additions & 1 deletion numpy/core/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,7 @@ def generate_multiarray_templated_sources(ext, build_dir):
join(local_dir, subpath, 'arraytypes.c.src'),
join(local_dir, subpath, 'nditer_templ.c.src'),
join(local_dir, subpath, 'lowlevel_strided_loops.c.src'),
join(local_dir, subpath, 'mapping.c.src'),
join(local_dir, subpath, 'einsum.c.src')]

# numpy.distutils generate .c from .c.src in weird directories, we have
Expand Down Expand Up @@ -776,7 +777,7 @@ def generate_multiarray_templated_sources(ext, build_dir):
join('src', 'multiarray', 'item_selection.c'),
join('src', 'multiarray', 'iterators.c'),
join('src', 'multiarray', 'lowlevel_strided_loops.c.src'),
join('src', 'multiarray', 'mapping.c'),
join('src', 'multiarray', 'mapping.c.src'),
join('src', 'multiarray', 'methods.c'),
join('src', 'multiarray', 'multiarraymodule.c'),
join('src', 'multiarray', 'nditer_templ.c.src'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2056,6 +2056,193 @@ PyArray_MapIterArray(PyArrayObject * a, PyObject * index)
#undef SOBJ_TOOMANY
#undef SOBJ_LISTTUP

typedef void (*inplace_map_binop)(PyArrayMapIterObject *, PyArrayIterObject *);

/**begin repeat
* #type = npy_int8, npy_int16, npy_int32, npy_int64, npy_int128, npy_int256,
npy_uint8, npy_uint16, npy_uint32, npy_uint64, npy_uint128, npy_uint256,
npy_float16, npy_float32, npy_float64, npy_float80, npy_float96, npy_float128, npy_float256#

* #typen = NPY_INT8, NPY_INT16, NPY_INT32, NPY_INT64, NPY_INT128, NPY_INT256,
NPY_UINT8, NPY_UINT16, NPY_UINT32, NPY_UINT64, NPY_UINT128, NPY_UINT256,
NPY_FLOAT16, NPY_FLOAT32, NPY_FLOAT64, NPY_FLOAT80, NPY_FLOAT96, NPY_FLOAT128, NPY_FLOAT256#
*/
#if defined(@typen@)
static void @type@_inplace_add(PyArrayMapIterObject *mit, PyArrayIterObject *it)
{
int index = mit->size;
while (index--) {
((@type@*)mit->dataptr)[0] = ((@type@*)mit->dataptr)[0] + ((@type@ *)it->dataptr)[0];

PyArray_MapIterNext(mit);
PyArray_ITER_NEXT(it);
}
}
#endif
/**end repeat**/

/**begin repeat
* #type = npy_complex32, npy_complex64, npy_complex128, npy_complex160, npy_complex192, npy_complex512#
* #typen = NPY_COMPLEX32, NPY_COMPLEX64, NPY_COMPLEX128, NPY_COMPLEX160, NPY_COMPLEX192, NPY_COMPLEX512#
*/
#if defined(@typen@)
static void @type@_inplace_add(PyArrayMapIterObject *mit, PyArrayIterObject *it)
{
int index = mit->size;
while (index--) {
((@type@*)mit->dataptr)[0].real = ((@type@*)mit->dataptr)[0].real + ((@type@ *)it->dataptr)[0].real;
((@type@*)mit->dataptr)[0].imag = ((@type@*)mit->dataptr)[0].imag + ((@type@ *)it->dataptr)[0].imag;

PyArray_MapIterNext(mit);
PyArray_ITER_NEXT(it);
}
}
#endif
/**end repeat**/

inplace_map_binop addition_funcs[] = {
/**begin repeat
* #type = npy_int8, npy_int16, npy_int32, npy_int64, npy_int128, npy_int256,
npy_uint8, npy_uint16, npy_uint32, npy_uint64, npy_uint128, npy_uint256,
npy_float16, npy_float32, npy_float64, npy_float80, npy_float96, npy_float128, npy_float256,
npy_complex32, npy_complex64, npy_complex128, npy_complex160, npy_complex192, npy_complex512#

* #typen = NPY_INT8, NPY_INT16, NPY_INT32, NPY_INT64, NPY_INT128, NPY_INT256,
NPY_UINT8, NPY_UINT16, NPY_UINT32, NPY_UINT64, NPY_UINT128, NPY_UINT256,
NPY_FLOAT16, NPY_FLOAT32, NPY_FLOAT64, NPY_FLOAT80, NPY_FLOAT96, NPY_FLOAT128, NPY_FLOAT256,
NPY_COMPLEX32, NPY_COMPLEX64, NPY_COMPLEX128, NPY_COMPLEX160, NPY_COMPLEX192, NPY_COMPLEX512#
*/
#if defined(@typen@)
@type@_inplace_add,
#endif
/**end repeat**/
NULL};

int type_numbers[] = {
/**begin repeat
* #typen = NPY_INT8, NPY_INT16, NPY_INT32, NPY_INT64, NPY_INT128, NPY_INT256,
NPY_UINT8, NPY_UINT16, NPY_UINT32, NPY_UINT64, NPY_UINT128, NPY_UINT256,
NPY_FLOAT16, NPY_FLOAT32, NPY_FLOAT64, NPY_FLOAT80, NPY_FLOAT96, NPY_FLOAT128, NPY_FLOAT256,
NPY_COMPLEX32, NPY_COMPLEX64, NPY_COMPLEX128, NPY_COMPLEX160, NPY_COMPLEX192, NPY_COMPLEX512#
*/
#if defined(@typen@)
@typen@,
#endif
/**end repeat**/
-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) {
_swap_axes(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;
}



PyArray_MapIterReset(mit);

(*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_MapIterNew(index, 0, 1);
if (mit == NULL) {
goto fail;
}
PyArray_MapIterBind(mit, a);
if (map_increment(mit, inc, add_inplace) != 0) {
goto fail;
}

Py_DECREF(mit);

Py_INCREF(Py_None);
return Py_None;
Copy link
Member

Choose a reason for hiding this comment

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

Align this line with the previous one.


fail:
Py_XDECREF(mit);

return NULL;
}

static void
arraymapiter_dealloc(PyArrayMapIterObject *mit)
{
Expand Down
3 changes: 3 additions & 0 deletions numpy/core/src/multiarray/mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,7 @@ PyArray_MapIterBind(PyArrayMapIterObject *, PyArrayObject *);
NPY_NO_EXPORT PyObject*
PyArray_MapIterNew(PyObject *, int, int);

static PyObject *
inplace_increment(PyObject *dummy, PyObject *args);

#endif
3 changes: 3 additions & 0 deletions numpy/core/src/multiarray/multiarraymodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -3677,6 +3677,9 @@ static struct PyMethodDef array_module_methods[] = {
{"test_interrupt",
(PyCFunction)test_interrupt,
METH_VARARGS, NULL},
{"inplace_increment",
(PyCFunction)inplace_increment,
METH_VARARGS, NULL},
{NULL, NULL, 0, NULL} /* sentinel */
};

Expand Down
49 changes: 49 additions & 0 deletions numpy/core/tests/test_inplace_increment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import numpy as np
from numpy.testing import *
from numpy.testing.utils import WarningManager
import warnings


class TestInplaceIncrement(TestCase):
def test_dtypes(self):
def testdt(dt):
a = np.arange(12).reshape((3,4)).astype(dt)
index = ([1,1,2,0], [0,0,2,3])
inc = [50,50, 30,16]

np.inplace_increment(a, index, inc)

assert_array_almost_equal(a, np.array([[ 0, 1, 2, 19],
[ 104, 5, 6, 7],
[ 8, 9, 40, 11]]).astype(dt))

testdt(np.float)
testdt(np.int)
testdt(np.complex)

def test_slice(self):
a = np.arange(12).reshape((3,4)).astype(float)
index = (1, slice(None, None))
inc = [50,50, 30,16]

np.inplace_increment(a, index, inc)

assert_array_almost_equal(a, np.array([[ 0, 1, 2, 3],
[ 54, 55, 36, 23],
[ 8, 9, 10, 11]]).astype(float))

def test_boolean(self):
a = np.arange(12).reshape((3,4)).astype(float)
index = (1, np.array([ False, True, False, True], dtype = bool))
inc = [30,16]

np.inplace_increment(a, index, inc)

assert_array_almost_equal(a, np.array([[ 0, 1, 2, 3],
[ 4, 35, 6, 23],
[ 8, 9, 10, 11]]).astype(float))



if __name__ == "__main__":
run_module_suite()