Skip to content

Commit

Permalink
BUG: core: fix bug in NpyIter buffering with discontinuous arrays
Browse files Browse the repository at this point in the history
It is possible to skip copying an array to the buffer only if the
reduction outer iterator is 1-dimensional --- the array may not be
c-contiguous.
  • Loading branch information
pv committed Sep 11, 2016
1 parent cb7f407 commit 21794ee
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 1 deletion.
2 changes: 1 addition & 1 deletion numpy/core/src/multiarray/nditer_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -2334,7 +2334,7 @@ npyiter_copy_to_buffers(NpyIter *iter, char **prev_dataptrs)
}
else {
/* It's all in one stride in the reduce outer loop */
if ((reduce_outerdim > 0) &&
if ((reduce_outerdim == 1) &&
(transfersize/reduce_innersize <=
NAD_SHAPE(reduce_outeraxisdata) -
NAD_INDEX(reduce_outeraxisdata))) {
Expand Down
16 changes: 16 additions & 0 deletions numpy/core/tests/test_nditer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2374,6 +2374,22 @@ def test_iter_buffering_reduction():
it.reset()
assert_equal(it[0], [1, 2, 1, 2])

# Iterator inner loop should take argument contiguity into account
x = np.ones((7, 13, 8), np.int8)[4:6,1:11:6,1:5].transpose(1, 2, 0)
x[...] = np.arange(x.size).reshape(x.shape)
y_base = np.arange(4*4, dtype=np.int8).reshape(4, 4)
y_base_copy = y_base.copy()
y = y_base[::2,:,None]

it = np.nditer([y, x],
['buffered', 'external_loop', 'reduce_ok'],
[['readwrite'], ['readonly']])
for a, b in it:
a.fill(2)

assert_equal(y_base[1::2], y_base_copy[1::2])
assert_equal(y_base[::2], 2)

def test_iter_buffering_reduction_reuse_reduce_loops():
# There was a bug triggering reuse of the reduce loop inappropriately,
# which caused processing to happen in unnecessarily small chunks
Expand Down
21 changes: 21 additions & 0 deletions numpy/core/tests/test_ufunc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1257,6 +1257,27 @@ def test_NotImplemented_not_returned(self):
for f in binary_funcs:
assert_raises(TypeError, f, a, b)

def test_reduce_noncontig_output(self):
# Check that reduction deals with non-contiguous output arrays
# appropriately.
#
# gh-8036

x = np.arange(7*13*8, dtype=np.int16).reshape(7, 13, 8)
x = x[4:6,1:11:6,1:5].transpose(1, 2, 0)
y_base = np.arange(4*4, dtype=np.int16).reshape(4, 4)
y = y_base[::2,:]

y_base_copy = y_base.copy()

r0 = np.add.reduce(x, out=y.copy(), axis=2)
r1 = np.add.reduce(x, out=y, axis=2)

# The results should match, and y_base shouldn't get clobbered
assert_equal(r0, r1)
assert_equal(y_base[1,:], y_base_copy[1,:])
assert_equal(y_base[3,:], y_base_copy[3,:])


if __name__ == "__main__":
run_module_suite()

0 comments on commit 21794ee

Please sign in to comment.