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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Updated `pre-commit` GitHub workflow to pass `no-commit-to-branch` check [#2501](https://github.com/IntelPython/dpnp/pull/2501)
* Updated the math formulas in summary of `dpnp.matvec` and `dpnp.vecmat` to correct a typo [#2503](https://github.com/IntelPython/dpnp/pull/2503)
* Avoided negating unsigned integers in ceil division used in `dpnp.resize` implementation [#2508](https://github.com/IntelPython/dpnp/pull/2508)
* Fixed `dpnp.unique` with 1d input array and `axis=0`, `equal_nan=True` keywords passed where the produced result doesn't collapse the NaNs [#2530](https://github.com/IntelPython/dpnp/pull/2530)

### Security

Expand Down
2 changes: 1 addition & 1 deletion dpnp/dpnp_iface_manipulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4245,7 +4245,7 @@ def unique(

"""

if axis is None:
if axis is None or (axis == 0 and ar.ndim == 1):
return _unique_1d(
ar, return_index, return_inverse, return_counts, equal_nan
)
Expand Down
10 changes: 9 additions & 1 deletion dpnp/tests/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ def get_integer_dtypes(all_int_types=False, no_unsigned=False):
if config.all_int_types or all_int_types:
dtypes += [dpnp.int8, dpnp.int16]
if not no_unsigned:
dtypes += [dpnp.uint8, dpnp.uint16, dpnp.uint32, dpnp.uint64]
dtypes += get_unsigned_dtypes()

return dtypes

Expand Down Expand Up @@ -378,6 +378,14 @@ def not_excluded(dtype):
return dtypes


def get_unsigned_dtypes():
"""
Build a list of unsigned integer types supported by DPNP.
"""

return [dpnp.uint8, dpnp.uint16, dpnp.uint32, dpnp.uint64]


def has_support_aspect16(device=None):
"""
Return True if the device supports 16-bit precision floating point operations,
Expand Down
52 changes: 28 additions & 24 deletions dpnp/tests/test_manipulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
get_float_dtypes,
get_integer_dtypes,
get_integer_float_dtypes,
get_unsigned_dtypes,
has_support_aspect64,
numpy_version,
)
Expand Down Expand Up @@ -1685,6 +1686,7 @@ def test_axis_list(self, axis):
expected = numpy.unique(a, axis=axis)
assert_array_equal(result, expected)

@testing.with_requires("numpy>=2.0.1")
@pytest.mark.parametrize("dt", get_all_dtypes(no_none=True))
@pytest.mark.parametrize(
"axis_kwd",
Expand Down Expand Up @@ -1716,17 +1718,6 @@ def test_2d_axis(self, dt, axis_kwd, return_kwds):
if len(return_kwds) == 0:
assert_array_equal(result, expected)
else:
if (
len(axis_kwd) == 0
and numpy.lib.NumpyVersion(numpy.__version__) < "2.0.1"
):
# gh-26961: numpy.unique(..., return_inverse=True, axis=None)
# returned flatten unique_inverse till 2.0.1 version
expected = (
expected[:2]
+ (expected[2].reshape(a.shape),)
+ expected[3:]
)
for iv, v in zip(result, expected):
assert_array_equal(iv, v)

Expand Down Expand Up @@ -1756,17 +1747,14 @@ def test_1d_axis(self, axis):
expected = numpy.unique(a, axis=axis)
assert_array_equal(result, expected)

@testing.with_requires("numpy>=2.0.1")
@pytest.mark.parametrize("axis", [None, 0, -1])
def test_2d_axis_inverse(self, axis):
a = numpy.array([[4, 4, 3], [2, 2, 1], [2, 2, 1], [4, 4, 3]])
ia = dpnp.array(a)

result = dpnp.unique(ia, return_inverse=True, axis=axis)
expected = numpy.unique(a, return_inverse=True, axis=axis)
if axis is None and numpy.lib.NumpyVersion(numpy.__version__) < "2.0.1":
# gh-26961: numpy.unique(..., return_inverse=True, axis=None)
# returned flatten unique_inverse till 2.0.1 version
expected = expected[:1] + (expected[1].reshape(a.shape),)

for iv, v in zip(result, expected):
assert_array_equal(iv, v)
Expand Down Expand Up @@ -1812,8 +1800,18 @@ def test_2d_axis_signed_inetger(self, dt):
expected = numpy.unique(a, axis=0)
assert_array_equal(result, expected)

@pytest.mark.parametrize("axis", [None, 0, 1])
@pytest.mark.parametrize("dt", get_unsigned_dtypes())
def test_2d_axis_unsigned_inetger(self, axis, dt):
a = numpy.array([[7, 1, 2, 1], [5, 7, 5, 7]], dtype=dt)
ia = dpnp.array(a)

result = dpnp.unique(ia, axis=axis)
expected = numpy.unique(a, axis=axis)
assert_array_equal(result, expected)

@pytest.mark.parametrize("axis", [None, 0])
@pytest.mark.parametrize("dt", "bBhHiIlLqQ")
@pytest.mark.parametrize("dt", get_integer_dtypes(all_int_types=True))
def test_1d_axis_all_inetger(self, axis, dt):
a = numpy.array([5, 7, 1, 2, 1, 5, 7], dtype=dt)
ia = dpnp.array(a)
Expand All @@ -1838,6 +1836,20 @@ def test_equal_nan(self, eq_nan_kwd):
expected = numpy.unique(a, **eq_nan_kwd)
assert_array_equal(result, expected)

# TODO: uncomment once numpy 2.3.2 release is published
# @testing.with_requires("numpy>=2.3.2")
def test_1d_equal_nan_axis0(self):
a = numpy.array([numpy.nan, 0, 0, numpy.nan])
ia = dpnp.array(a)

result = dpnp.unique(ia, axis=0, equal_nan=True)
expected = numpy.unique(a, axis=0, equal_nan=True)
# TODO: remove when numpy#29372 is released
if numpy_version() < "2.3.2":
expected = numpy.array([0.0, numpy.nan])
assert_array_equal(result, expected)

@testing.with_requires("numpy>=2.0.1")
@pytest.mark.parametrize("dt", get_float_complex_dtypes())
@pytest.mark.parametrize(
"axis_kwd",
Expand Down Expand Up @@ -1879,14 +1891,6 @@ def test_2d_axis_nans(self, dt, axis_kwd, return_kwds, row):
if len(return_kwds) == 0:
assert_array_equal(result, expected)
else:
if len(axis_kwd) == 0 and numpy_version() < "2.0.1":
# gh-26961: numpy.unique(..., return_inverse=True, axis=None)
# returned flatten unique_inverse till 2.0.1 version
expected = (
expected[:2]
+ (expected[2].reshape(a.shape),)
+ expected[3:]
)
for iv, v in zip(result, expected):
assert_array_equal(iv, v)

Expand Down
Loading