Skip to content

Commit

Permalink
Fix #277, reductions on arrays with leading dimension of 1
Browse files Browse the repository at this point in the history
  • Loading branch information
robbmcleod committed Jul 19, 2017
1 parent 52ee958 commit e639060
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 3 deletions.
3 changes: 3 additions & 0 deletions RELEASE_NOTES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ Changes from 2.6.2 to 2.6.3

- Fixed a bug where complex constants would return an error, fixing
problems with `sympy` when using NumExpr as a backend.

- Fix for #277 whereby arrays of shape (1,...) would be reduced as
if they were full reduction. Behavoir now matches that of NumPy.

Changes from 2.6.1 to 2.6.2
===========================
Expand Down
12 changes: 9 additions & 3 deletions numexpr/interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -979,9 +979,9 @@ NumExpr_run(NumExprObject *self, PyObject *args, PyObject *kwds)
unsigned int i, n_inputs;
int r, pc_error = 0;
int reduction_axis = -1;
npy_intp reduction_size = 1;
npy_intp reduction_size = -1; // For #277 change this 1 -> -1 to be in-line with NumPy 1.8,
int ex_uses_vml = 0, is_reduction = 0;
bool reduction_outer_loop = false, need_output_buffering = false;
bool reduction_outer_loop = false, need_output_buffering = false, full_reduction = false;

// To specify axes when doing a reduction
int op_axes_values[NPY_MAXARGS][NPY_MAXDIMS],
Expand Down Expand Up @@ -1148,6 +1148,7 @@ NumExpr_run(NumExprObject *self, PyObject *args, PyObject *kwds)
}
// A full reduction can be done without nested iteration
if (oa_ndim == 0) {
full_reduction = true;
if (operands[0] == NULL) {
npy_intp dim = 1;
operands[0] = (PyArrayObject *)PyArray_SimpleNew(0, &dim,
Expand Down Expand Up @@ -1278,8 +1279,13 @@ NumExpr_run(NumExprObject *self, PyObject *args, PyObject *kwds)


/* Allocate the iterator or nested iterators */
if (reduction_size == 1) {
if (reduction_size < 0 || full_reduction) {
/* When there's no reduction, reduction_size is 1 as well */
// RAM: in issue #277 this was also the case for reductions on arrays
// with axis=0 having singleton dimension, i.e. such ops were interpreted
// as full_reductions when they weren't in Numpy. As such, the default
// reduction_size is now -1 and we add the flag for full_reduction,
// e.g. ne.evaluate("sum(a)")"
iter = NpyIter_AdvancedNew(n_inputs+1, operands,
NPY_ITER_BUFFERED|
NPY_ITER_REDUCE_OK|
Expand Down
6 changes: 6 additions & 0 deletions numexpr/tests/test_numexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ def test_reductions(self):
assert_allclose(evaluate("min(x)"), np.min(x))
assert_allclose(evaluate("max(x,axis=0)"), np.max(x, axis=0))

# Fix for #277, array with leading singleton dimension
x = np.arange(10).reshape(1,10)
assert_allclose(evaluate("sum(x,axis=None)"), sum(x, axis=None) )
assert_allclose(evaluate("sum(x,axis=0)"), sum(x, axis=0) )
assert_allclose(evaluate("sum(x,axis=1)"), sum(x, axis=1) )

x = arange(10.0)
assert_allclose(evaluate("sum(x**2+2,axis=0)"), sum(x ** 2 + 2, axis=0))
assert_allclose(evaluate("prod(x**2+2,axis=0)"), prod(x ** 2 + 2, axis=0))
Expand Down

0 comments on commit e639060

Please sign in to comment.