diff --git a/bottleneck/include/iterators.h b/bottleneck/include/iterators.h index 1f5120a18..8be840f77 100644 --- a/bottleneck/include/iterators.h +++ b/bottleneck/include/iterators.h @@ -87,9 +87,6 @@ static inline void init_iter_all(iter *it, PyArrayObject *a, int ravel, int anyo it->nits = 1; it->a_ravel = NULL; - /* The fix for relaxed strides checking in numpy and the fix for - * issue #183 has left this if..else tree in need of a refactor from the - * the ground up */ if (ndim == 1) { it->ndim_m2 = -1; it->length = shape[0]; @@ -98,47 +95,12 @@ static inline void init_iter_all(iter *it, PyArrayObject *a, int ravel, int anyo it->ndim_m2 = -1; it->length = 1; it->astride = 0; - } else if (C_CONTIGUOUS(a) && !F_CONTIGUOUS(a)) { - /* The &&! in the next two else ifs is to deal with relaxed - * stride checking introduced in numpy 1.12.0; see gh #161 */ + } else if (C_CONTIGUOUS(a) || (anyorder && F_CONTIGUOUS(a))) { + /* If continguous then we just need the itemsize */ it->ndim_m2 = -1; - it->axis = ndim - 1; + // it->axis does not matter it->length = PyArray_SIZE(a); - it->astride = 0; - for (i = ndim - 1; i > -1; i--) { - /* protect against length zero strides such as in - * np.ones((2, 2))[..., np.newaxis] */ - if (strides[i] == 0) { - continue; - } - it->astride = strides[i]; - break; - } - } else if (F_CONTIGUOUS(a) && !C_CONTIGUOUS(a)) { - if (anyorder || !ravel) { - it->ndim_m2 = -1; - it->length = PyArray_SIZE(a); - it->astride = 0; - for (i = 0; i < ndim; i++) { - /* protect against length zero strides such as in - * np.ones((2, 2), order='F')[np.newaxis, ...] */ - if (strides[i] == 0) { - continue; - } - it->astride = strides[i]; - break; - } - } else { - it->ndim_m2 = -1; - if (anyorder) { - a = (PyArrayObject *)PyArray_Ravel(a, NPY_ANYORDER); - } else { - a = (PyArrayObject *)PyArray_Ravel(a, NPY_CORDER); - } - it->a_ravel = a; - it->length = PyArray_DIM(a, 0); - it->astride = PyArray_STRIDE(a, 0); - } + it->astride = item_size; } else if (ravel) { it->ndim_m2 = -1; if (anyorder) { diff --git a/bottleneck/tests/reduce_test.py b/bottleneck/tests/reduce_test.py index 56723e1d9..02298dd1b 100644 --- a/bottleneck/tests/reduce_test.py +++ b/bottleneck/tests/reduce_test.py @@ -236,3 +236,31 @@ def test_ddof_nans(func, dtype): for axis in [None, 0, 1, -1]: result = func(array, axis=axis, ddof=3) assert np.isnan(result) + + +@pytest.mark.parametrize("dtype", DTYPES) +@pytest.mark.parametrize( + ("func", "expected"), + [(bn.nansum, 1000), + (bn.nanmean, 1), + (bn.nanmax, 1)], + ids=lambda x: x.__name__ if not isinstance(x, int) else x +) +def test_reduce_with_unordered_strides_ccontig(func, expected, dtype) -> None: + array = np.ones((1, 500, 2), dtype=dtype).transpose((1,2,0)) + result = func(array) + assert result == expected + +@pytest.mark.parametrize("dtype", DTYPES) +@pytest.mark.parametrize( + ("func", "expected"), + [(bn.nansum, 1000), + (bn.nanmean, 1), + (bn.nanmax, 1)], + ids=lambda x: x.__name__ if not isinstance(x, int) else x +) +def test_reduce_with_unordered_strides_fcontig(func, expected, dtype) -> None: + array = np.ones((1, 500, 2), dtype=dtype).transpose((0,2,1)) + result = func(array) + assert result == expected +