Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ This release is compatible with NumPy 2.5.
* Fixed the list of events the copy kernels of `dpnp.reshape`, `dpnp.tensor.reshape`, `dpnp.roll` and `dpnp.tensor.roll` wait on being padded with default-constructed events [#3072](https://github.com/IntelPython/dpnp/pull/3072)
* Fixed `simplify_iteration_three_strides` and `simplify_iteration_four_strides` accumulating into their third and fourth output displacements without zeroing them first, which required the caller to initialize them [#3072](https://github.com/IntelPython/dpnp/pull/3072)
* Fixed `dpnp.ndarray.flat` indexing and assignment edge cases, adding support for slices, ellipsis, and integer/boolean array indices [#3045](https://github.com/IntelPython/dpnp/pull/3045)
* Fixed `dpnp.nanmedian` dropping kept dimensions of size 1, which produced a wrong result shape [#3081](https://github.com/IntelPython/dpnp/pull/3081)
* Fixed incorrect results of `dpnp.tensor.vecdot` in some cases with strided outputs and of `dpnp.tensor` reductions, `dpnp.tensor.vecdot` and `dpnp.tensor.matmul` on large inputs with some data types [#3082](https://github.com/IntelPython/dpnp/pull/3082)
* Fixed `dpnp.median` and `dpnp.nanmedian` raising a `ValueError` for a tuple `axis` when a kept dimension has size 0 [#3081](https://github.com/IntelPython/dpnp/pull/3081)

### Security

Expand Down
9 changes: 7 additions & 2 deletions dpnp/dpnp_utils/dpnp_utils_statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
# THE POSSIBILITY OF SUCH DAMAGE.
# *****************************************************************************

import math
import warnings

import dpnp
Expand Down Expand Up @@ -88,7 +89,8 @@ def _calc_nanmedian(a, out=None):
if mask.all(axis=-1).any():
warnings.warn("All-NaN slice encountered", RuntimeWarning, stacklevel=6)

return dpnp.squeeze(res)
# only drop the reduced axis, keep size-1 dimensions that are not reduced
return dpnp.squeeze(res, axis=-1)


def _flatten_array_along_axes(a, axes_to_flatten, overwrite_input):
Expand All @@ -102,7 +104,10 @@ def _flatten_array_along_axes(a, axes_to_flatten, overwrite_input):
# Move the axes_to_flatten to the end
destination = list(range(len(axes_to_keep), a_ndim))
a_moved = dpnp.moveaxis(a, axes_to_flatten, destination)
new_shape = tuple(a.shape[axis] for axis in axes_to_keep) + (-1,)
# Compute the merged length explicitly instead of letting `reshape` infer
# it with -1, since -1 is ambiguous when a kept axis has size 0
merged = math.prod(a.shape[axis] for axis in axes_to_flatten)
new_shape = tuple(a.shape[axis] for axis in axes_to_keep) + (merged,)
a_flatten = a_moved.reshape(new_shape)

# Note that the output of a_flatten is not necessarily a view of the input
Expand Down
28 changes: 28 additions & 0 deletions dpnp/tests/test_nanfunctions.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,34 @@ def test_empty(self, axis, shape):
expected = numpy.nanmedian(a, axis=axis)
assert_dtype_allclose(result, expected)

@pytest.mark.usefixtures("suppress_mean_empty_slice_numpy_warnings")
@pytest.mark.parametrize(
"keepdims, out_shape", [(False, (0,)), (True, (0, 1, 1))]
)
def test_empty_kept_dim(self, keepdims, out_shape):
a = numpy.empty((0, 3, 4))
ia = dpnp.array(a)

result = dpnp.nanmedian(ia, axis=(1, 2), keepdims=keepdims)
assert result.shape == out_shape
if numpy_version() >= "2.5.4":
expected = numpy.nanmedian(a, axis=(1, 2), keepdims=keepdims)
assert_dtype_allclose(result, expected)

@pytest.mark.usefixtures("suppress_mean_empty_slice_numpy_warnings")
@pytest.mark.parametrize(
"shape, axis", [((1, 5), 1), ((3, 1, 4), 2), ((2, 1, 5), (0, 2))]
)
@pytest.mark.parametrize("keepdims", [True, False])
def test_size1_kept_dim(self, shape, axis, keepdims):
a = generate_random_numpy_array(shape)
a.flat[0] = numpy.nan
ia = dpnp.array(a)

result = dpnp.nanmedian(ia, axis=axis, keepdims=keepdims)
expected = numpy.nanmedian(a, axis=axis, keepdims=keepdims)
assert_dtype_allclose(result, expected)

@pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True))
@pytest.mark.parametrize("axis", [None, 0, (-1,), [0, 1], (0, -2, -1)])
def test_no_nan(self, dtype, axis):
Expand Down
14 changes: 14 additions & 0 deletions dpnp/tests/test_statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -944,6 +944,20 @@ def test_empty(self, axis, shape):
expected = numpy.median(a, axis=axis)
assert_dtype_allclose(result, expected)

@pytest.mark.usefixtures("suppress_mean_empty_slice_numpy_warnings")
@pytest.mark.parametrize(
"keepdims, out_shape", [(False, (0,)), (True, (0, 1, 1))]
)
def test_empty_kept_dim(self, keepdims, out_shape):
a = numpy.empty((0, 3, 4))
ia = dpnp.array(a)

result = dpnp.median(ia, axis=(1, 2), keepdims=keepdims)
assert result.shape == out_shape
if numpy_version() >= "2.5.4":
expected = numpy.median(a, axis=(1, 2), keepdims=keepdims)
assert_dtype_allclose(result, expected)

@pytest.mark.parametrize("dtype", get_all_dtypes())
@pytest.mark.parametrize(
"axis, out_shape", [(0, (3,)), (1, (2,)), ((0, 1), ())]
Expand Down
Loading