Skip to content

Commit 422854f

Browse files
authored
Merge pull request numpy#24281 from seberg/fixup-indexed
BUG: Further fixes to indexing loop and added tests
2 parents 7fc7277 + ee16c22 commit 422854f

File tree

5 files changed

+63
-25
lines changed

5 files changed

+63
-25
lines changed

numpy/core/src/umath/_umath_tests.c.src

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -375,13 +375,18 @@ INT32_negative_indexed(PyArrayMethod_Context *NPY_UNUSED(context),
375375
npy_intp const *steps, NpyAuxData *NPY_UNUSED(func))
376376
{
377377
char *ip1 = args[0];
378-
char *indx = args[1];
378+
char *indxp = args[1];
379379
npy_intp is1 = steps[0], isindex = steps[1];
380380
npy_intp n = dimensions[0];
381+
npy_intp shape = steps[3];
381382
npy_intp i;
382383
int32_t *indexed;
383-
for(i = 0; i < n; i++, indx += isindex) {
384-
indexed = (int32_t *)(ip1 + is1 * *(npy_intp *)indx);
384+
for(i = 0; i < n; i++, indxp += isindex) {
385+
npy_intp indx = *(npy_intp *)indxp;
386+
if (indx < 0) {
387+
indx += shape;
388+
}
389+
indexed = (int32_t *)(ip1 + is1 * indx);
385390
if (i == 3) {
386391
*indexed = -200;
387392
} else {

numpy/core/src/umath/loops_arithm_fp.dispatch.c.src

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -258,14 +258,19 @@ NPY_NO_EXPORT int NPY_CPU_DISPATCH_CURFX(@TYPE@_@kind@_indexed)
258258
(PyArrayMethod_Context *NPY_UNUSED(context), char * const*args, npy_intp const *dimensions, npy_intp const *steps, NpyAuxData *NPY_UNUSED(func))
259259
{
260260
char *ip1 = args[0];
261-
char *indx = args[1];
261+
char *indxp = args[1];
262262
char *value = args[2];
263263
npy_intp is1 = steps[0], isindex = steps[1], isb = steps[2];
264+
npy_intp shape = steps[3];
264265
npy_intp n = dimensions[0];
265266
npy_intp i;
266267
@type@ *indexed;
267-
for(i = 0; i < n; i++, indx += isindex, value += isb) {
268-
indexed = (@type@ *)(ip1 + is1 * *(npy_intp *)indx);
268+
for(i = 0; i < n; i++, indxp += isindex, value += isb) {
269+
npy_intp indx = *(npy_intp *)indxp;
270+
if (indx < 0) {
271+
indx += shape;
272+
}
273+
indexed = (@type@ *)(ip1 + is1 * indx);
269274
*indexed = *indexed @OP@ *(@type@ *)value;
270275
}
271276
return 0;
@@ -650,14 +655,19 @@ NPY_NO_EXPORT int NPY_CPU_DISPATCH_CURFX(@TYPE@_@kind@_indexed)
650655
(PyArrayMethod_Context *NPY_UNUSED(context), char * const*args, npy_intp const *dimensions, npy_intp const *steps, NpyAuxData *NPY_UNUSED(func))
651656
{
652657
char *ip1 = args[0];
653-
char *indx = args[1];
658+
char *indxp = args[1];
654659
char *value = args[2];
655660
npy_intp is1 = steps[0], isindex = steps[1], isb = steps[2];
661+
npy_intp shape = steps[3];
656662
npy_intp n = dimensions[0];
657663
npy_intp i;
658664
@ftype@ *indexed;
659-
for(i = 0; i < n; i++, indx += isindex, value += isb) {
660-
indexed = (@ftype@ *)(ip1 + is1 * *(npy_intp *)indx);
665+
for(i = 0; i < n; i++, indxp += isindex, value += isb) {
666+
npy_intp indx = *(npy_intp *)indxp;
667+
if (indx < 0) {
668+
indx += shape;
669+
}
670+
indexed = (@ftype@ *)(ip1 + is1 * indx);
661671
const @ftype@ b_r = ((@ftype@ *)value)[0];
662672
const @ftype@ b_i = ((@ftype@ *)value)[1];
663673
#if @is_mul@

numpy/core/src/umath/loops_arithmetic.dispatch.c.src

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -400,14 +400,19 @@ NPY_NO_EXPORT int NPY_CPU_DISPATCH_CURFX(@TYPE@_divide_indexed)
400400
(PyArrayMethod_Context *NPY_UNUSED(context), char * const*args, npy_intp const *dimensions, npy_intp const *steps, NpyAuxData *NPY_UNUSED(func))
401401
{
402402
char *ip1 = args[0];
403-
char *indx = args[1];
403+
char *indxp = args[1];
404404
char *value = args[2];
405405
npy_intp is1 = steps[0], isindex = steps[1], isb = steps[2];
406+
npy_intp shape = steps[3];
406407
npy_intp n = dimensions[0];
407408
npy_intp i;
408409
@type@ *indexed;
409-
for(i = 0; i < n; i++, indx += isindex, value += isb) {
410-
indexed = (@type@ *)(ip1 + is1 * *(npy_intp *)indx);
410+
for(i = 0; i < n; i++, indxp += isindex, value += isb) {
411+
npy_intp indx = *(npy_intp *)indxp;
412+
if (indx < 0) {
413+
indx += shape;
414+
}
415+
indexed = (@type@ *)(ip1 + is1 * indx);
411416
*indexed = floor_div_@TYPE@(*indexed, *(@type@ *)value);
412417
}
413418
return 0;
@@ -486,14 +491,19 @@ NPY_NO_EXPORT int NPY_CPU_DISPATCH_CURFX(@TYPE@_divide_indexed)
486491
(PyArrayMethod_Context *NPY_UNUSED(context), char * const*args, npy_intp const *dimensions, npy_intp const *steps, NpyAuxData *NPY_UNUSED(func))
487492
{
488493
char *ip1 = args[0];
489-
char *indx = args[1];
494+
char *indxp = args[1];
490495
char *value = args[2];
491496
npy_intp is1 = steps[0], isindex = steps[1], isb = steps[2];
497+
npy_intp shape = steps[3];
492498
npy_intp n = dimensions[0];
493499
npy_intp i;
494500
@type@ *indexed;
495-
for(i = 0; i < n; i++, indx += isindex, value += isb) {
496-
indexed = (@type@ *)(ip1 + is1 * *(npy_intp *)indx);
501+
for(i = 0; i < n; i++, indxp += isindex, value += isb) {
502+
npy_intp indx = *(npy_intp *)indxp;
503+
if (indx < 0) {
504+
indx += shape;
505+
}
506+
indexed = (@type@ *)(ip1 + is1 * indx);
497507
@type@ in2 = *(@type@ *)value;
498508
if (NPY_UNLIKELY(in2 == 0)) {
499509
npy_set_floatstatus_divbyzero();

numpy/core/src/umath/loops_minmax.dispatch.c.src

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -456,14 +456,19 @@ NPY_NO_EXPORT int NPY_CPU_DISPATCH_CURFX(@TYPE@_@kind@_indexed)
456456
(PyArrayMethod_Context *NPY_UNUSED(context), char *const *args, npy_intp const *dimensions, npy_intp const *steps, NpyAuxData *NPY_UNUSED(func))
457457
{
458458
char *ip1 = args[0];
459-
char *indx = args[1];
459+
char *indxp = args[1];
460460
char *value = args[2];
461461
npy_intp is1 = steps[0], isindex = steps[1], isb = steps[2];
462462
npy_intp n = dimensions[0];
463+
npy_intp shape = steps[3];
463464
npy_intp i;
464465
@type@ *indexed;
465-
for(i = 0; i < n; i++, indx += isindex, value += isb) {
466-
indexed = (@type@ *)(ip1 + is1 * *(npy_intp *)indx);
466+
for(i = 0; i < n; i++, indxp += isindex, value += isb) {
467+
npy_intp indx = *(npy_intp *)indxp;
468+
if (indx < 0) {
469+
indx += shape;
470+
}
471+
indexed = (@type@ *)(ip1 + is1 * indx);
467472
*indexed = SCALAR_OP(*indexed, *(@type@ *)value);
468473
}
469474
return 0;

numpy/core/tests/test_ufunc.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2224,13 +2224,21 @@ def test_ufunc_at_advanced(self):
22242224
np.maximum.at(a, [0], 0)
22252225
assert_equal(a, np.array([1, 2, 3]))
22262226

2227-
def test_at_negative_indexes(self):
2228-
a = np.arange(10)
2229-
indxs = np.array([-1, 1, -1, 2])
2230-
np.add.at(a, indxs, 1)
2231-
assert a[-1] == 11 # issue 24147
2232-
assert a[1] == 2
2233-
assert a[2] == 3
2227+
@pytest.mark.parametrize("dtype",
2228+
np.typecodes['AllInteger'] + np.typecodes['Float'])
2229+
@pytest.mark.parametrize("ufunc",
2230+
[np.add, np.subtract, np.divide, np.minimum, np.maximum])
2231+
def test_at_negative_indexes(self, dtype, ufunc):
2232+
a = np.arange(0, 10).astype(dtype)
2233+
indxs = np.array([-1, 1, -1, 2]).astype(np.intp)
2234+
vals = np.array([1, 5, 2, 10], dtype=a.dtype)
2235+
2236+
expected = a.copy()
2237+
for i, v in zip(indxs, vals):
2238+
expected[i] = ufunc(expected[i], v)
2239+
2240+
ufunc.at(a, indxs, vals)
2241+
assert_array_equal(a, expected)
22342242
assert np.all(indxs == [-1, 1, -1, 2])
22352243

22362244
def test_at_not_none_signature(self):

0 commit comments

Comments
 (0)