Skip to content

Commit 0e85000

Browse files
authored
Merge branch 'master' into remove-wa-sat-7414
2 parents 4e9c064 + 876e940 commit 0e85000

File tree

8 files changed

+97
-39
lines changed

8 files changed

+97
-39
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414
* Added a new backend routine `syrk` from oneMKL to perform symmetric rank-k update which is used for a specialized matrix multiplication where the result is a symmetric matrix [2509](https://github.com/IntelPython/dpnp/pull/2509)
1515
* Added `timeout-minutes` property to GitHub jobs [#2526](https://github.com/IntelPython/dpnp/pull/2526)
1616
* Added implementation of `dpnp.ndarray.data` and `dpnp.ndarray.data.ptr` attributes [#2521](https://github.com/IntelPython/dpnp/pull/2521)
17+
* Added `dpnp.ndarray.__contains__` method [#2534](https://github.com/IntelPython/dpnp/pull/2534)
1718

1819
### Changed
1920

@@ -42,6 +43,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4243
* Updated `pre-commit` GitHub workflow to pass `no-commit-to-branch` check [#2501](https://github.com/IntelPython/dpnp/pull/2501)
4344
* Updated the math formulas in summary of `dpnp.matvec` and `dpnp.vecmat` to correct a typo [#2503](https://github.com/IntelPython/dpnp/pull/2503)
4445
* Avoided negating unsigned integers in ceil division used in `dpnp.resize` implementation [#2508](https://github.com/IntelPython/dpnp/pull/2508)
46+
* 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)
47+
* Resolved issue when `dpnp.ndarray` constructor is called with `dpnp.ndarray.data` as `buffer` keyword [#2533](https://github.com/IntelPython/dpnp/pull/2533)
4548

4649
### Security
4750

dpnp/dpnp_array.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,9 @@ def __bool__(self):
242242
def __complex__(self):
243243
return self._array_obj.__complex__()
244244

245-
# '__contains__',
245+
def __contains__(self, value, /):
246+
r"""Return :math:`\text{value in self}`."""
247+
return (self == value).any()
246248

247249
def __copy__(self):
248250
"""

dpnp/dpnp_iface_manipulation.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,11 +1346,11 @@ def column_stack(tup):
13461346
--------
13471347
>>> import dpnp as np
13481348
>>> a = np.array((1, 2, 3))
1349-
>>> b = np.array((2, 3, 4))
1349+
>>> b = np.array((4, 5, 6))
13501350
>>> np.column_stack((a, b))
1351-
array([[1, 2],
1352-
[2, 3],
1353-
[3, 4]])
1351+
array([[1, 4],
1352+
[2, 5],
1353+
[3, 6]])
13541354
13551355
"""
13561356

@@ -1778,18 +1778,18 @@ def dstack(tup):
17781778
--------
17791779
>>> import dpnp as np
17801780
>>> a = np.array((1, 2, 3))
1781-
>>> b = np.array((2, 3, 4))
1781+
>>> b = np.array((4, 5, 6))
17821782
>>> np.dstack((a, b))
1783-
array([[[1, 2],
1784-
[2, 3],
1785-
[3, 4]]])
1783+
array([[[1, 4],
1784+
[2, 5],
1785+
[3, 6]]])
17861786
17871787
>>> a = np.array([[1], [2], [3]])
1788-
>>> b = np.array([[2], [3], [4]])
1788+
>>> b = np.array([[4], [5], [6]])
17891789
>>> np.dstack((a, b))
1790-
array([[[1, 2]],
1791-
[[2, 3]],
1792-
[[3, 4]]])
1790+
array([[[1, 4]],
1791+
[[2, 5]],
1792+
[[3, 6]]])
17931793
17941794
"""
17951795

@@ -4245,7 +4245,7 @@ def unique(
42454245
42464246
"""
42474247

4248-
if axis is None:
4248+
if axis is None or (axis == 0 and ar.ndim == 1):
42494249
return _unique_1d(
42504250
ar, return_index, return_inverse, return_counts, equal_nan
42514251
)

dpnp/memory/_memory.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ def create_data(x):
9595
)
9696
usm_data = x.usm_data
9797

98+
if isinstance(usm_data, tuple(dispatch.values())):
99+
return usm_data
100+
98101
cls = dispatch.get(type(usm_data), None)
99102
if cls:
100103
data = cls(usm_data)

dpnp/tests/helper.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ def get_integer_dtypes(all_int_types=False, no_unsigned=False):
343343
if config.all_int_types or all_int_types:
344344
dtypes += [dpnp.int8, dpnp.int16]
345345
if not no_unsigned:
346-
dtypes += [dpnp.uint8, dpnp.uint16, dpnp.uint32, dpnp.uint64]
346+
dtypes += get_unsigned_dtypes()
347347

348348
return dtypes
349349

@@ -378,6 +378,14 @@ def not_excluded(dtype):
378378
return dtypes
379379

380380

381+
def get_unsigned_dtypes():
382+
"""
383+
Build a list of unsigned integer types supported by DPNP.
384+
"""
385+
386+
return [dpnp.uint8, dpnp.uint16, dpnp.uint32, dpnp.uint64]
387+
388+
381389
def has_support_aspect16(device=None):
382390
"""
383391
Return True if the device supports 16-bit precision floating point operations,

dpnp/tests/test_manipulation.py

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
get_float_dtypes,
2222
get_integer_dtypes,
2323
get_integer_float_dtypes,
24+
get_unsigned_dtypes,
2425
has_support_aspect64,
2526
numpy_version,
2627
)
@@ -1685,6 +1686,7 @@ def test_axis_list(self, axis):
16851686
expected = numpy.unique(a, axis=axis)
16861687
assert_array_equal(result, expected)
16871688

1689+
@testing.with_requires("numpy>=2.0.1")
16881690
@pytest.mark.parametrize("dt", get_all_dtypes(no_none=True))
16891691
@pytest.mark.parametrize(
16901692
"axis_kwd",
@@ -1716,17 +1718,6 @@ def test_2d_axis(self, dt, axis_kwd, return_kwds):
17161718
if len(return_kwds) == 0:
17171719
assert_array_equal(result, expected)
17181720
else:
1719-
if (
1720-
len(axis_kwd) == 0
1721-
and numpy.lib.NumpyVersion(numpy.__version__) < "2.0.1"
1722-
):
1723-
# gh-26961: numpy.unique(..., return_inverse=True, axis=None)
1724-
# returned flatten unique_inverse till 2.0.1 version
1725-
expected = (
1726-
expected[:2]
1727-
+ (expected[2].reshape(a.shape),)
1728-
+ expected[3:]
1729-
)
17301721
for iv, v in zip(result, expected):
17311722
assert_array_equal(iv, v)
17321723

@@ -1756,17 +1747,14 @@ def test_1d_axis(self, axis):
17561747
expected = numpy.unique(a, axis=axis)
17571748
assert_array_equal(result, expected)
17581749

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

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

17711759
for iv, v in zip(result, expected):
17721760
assert_array_equal(iv, v)
@@ -1812,8 +1800,18 @@ def test_2d_axis_signed_inetger(self, dt):
18121800
expected = numpy.unique(a, axis=0)
18131801
assert_array_equal(result, expected)
18141802

1803+
@pytest.mark.parametrize("axis", [None, 0, 1])
1804+
@pytest.mark.parametrize("dt", get_unsigned_dtypes())
1805+
def test_2d_axis_unsigned_inetger(self, axis, dt):
1806+
a = numpy.array([[7, 1, 2, 1], [5, 7, 5, 7]], dtype=dt)
1807+
ia = dpnp.array(a)
1808+
1809+
result = dpnp.unique(ia, axis=axis)
1810+
expected = numpy.unique(a, axis=axis)
1811+
assert_array_equal(result, expected)
1812+
18151813
@pytest.mark.parametrize("axis", [None, 0])
1816-
@pytest.mark.parametrize("dt", "bBhHiIlLqQ")
1814+
@pytest.mark.parametrize("dt", get_integer_dtypes(all_int_types=True))
18171815
def test_1d_axis_all_inetger(self, axis, dt):
18181816
a = numpy.array([5, 7, 1, 2, 1, 5, 7], dtype=dt)
18191817
ia = dpnp.array(a)
@@ -1838,6 +1836,20 @@ def test_equal_nan(self, eq_nan_kwd):
18381836
expected = numpy.unique(a, **eq_nan_kwd)
18391837
assert_array_equal(result, expected)
18401838

1839+
# TODO: uncomment once numpy 2.3.2 release is published
1840+
# @testing.with_requires("numpy>=2.3.2")
1841+
def test_1d_equal_nan_axis0(self):
1842+
a = numpy.array([numpy.nan, 0, 0, numpy.nan])
1843+
ia = dpnp.array(a)
1844+
1845+
result = dpnp.unique(ia, axis=0, equal_nan=True)
1846+
expected = numpy.unique(a, axis=0, equal_nan=True)
1847+
# TODO: remove when numpy#29372 is released
1848+
if numpy_version() < "2.3.2":
1849+
expected = numpy.array([0.0, numpy.nan])
1850+
assert_array_equal(result, expected)
1851+
1852+
@testing.with_requires("numpy>=2.0.1")
18411853
@pytest.mark.parametrize("dt", get_float_complex_dtypes())
18421854
@pytest.mark.parametrize(
18431855
"axis_kwd",
@@ -1879,14 +1891,6 @@ def test_2d_axis_nans(self, dt, axis_kwd, return_kwds, row):
18791891
if len(return_kwds) == 0:
18801892
assert_array_equal(result, expected)
18811893
else:
1882-
if len(axis_kwd) == 0 and numpy_version() < "2.0.1":
1883-
# gh-26961: numpy.unique(..., return_inverse=True, axis=None)
1884-
# returned flatten unique_inverse till 2.0.1 version
1885-
expected = (
1886-
expected[:2]
1887-
+ (expected[2].reshape(a.shape),)
1888-
+ expected[3:]
1889-
)
18901894
for iv, v in zip(result, expected):
18911895
assert_array_equal(iv, v)
18921896

dpnp/tests/test_memory.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,8 @@ def test_wrong_usm_data(self):
2626

2727
with pytest.raises(TypeError):
2828
dpm.create_data(d)
29+
30+
def test_ndarray_from_data(self):
31+
a = dpnp.empty(5)
32+
b = dpnp.ndarray(a.shape, buffer=a.data)
33+
assert b.data.ptr == a.data.ptr

dpnp/tests/test_ndarray.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,39 @@ def test_attributes(self):
7474
assert_equal(self.two.itemsize, self.two.dtype.itemsize)
7575

7676

77+
@testing.parameterize(*testing.product({"xp": [dpnp, numpy]}))
78+
class TestContains:
79+
def test_basic(self):
80+
a = self.xp.arange(10).reshape((2, 5))
81+
assert 4 in a
82+
assert 20 not in a
83+
84+
def test_broadcast(self):
85+
xp = self.xp
86+
a = xp.arange(6).reshape((2, 3))
87+
assert 4 in a
88+
assert xp.array([0, 1, 2]) in a
89+
assert xp.array([5, 3, 4]) not in a
90+
91+
def test_broadcast_error(self):
92+
a = self.xp.arange(10).reshape((2, 5))
93+
with pytest.raises(
94+
ValueError,
95+
match="operands could not be broadcast together with shapes",
96+
):
97+
self.xp.array([1, 2]) in a
98+
99+
def test_strides(self):
100+
xp = self.xp
101+
a = xp.arange(10).reshape((2, 5))
102+
a = a[:, ::2]
103+
assert 4 in a
104+
assert 8 not in a
105+
assert xp.full(a.shape[-1], fill_value=2) in a
106+
assert xp.full_like(a, fill_value=7) in a
107+
assert xp.full_like(a, fill_value=6) not in a
108+
109+
77110
class TestView:
78111
def test_none_dtype(self):
79112
a = numpy.ones((1, 2, 4), dtype=numpy.int32)

0 commit comments

Comments
 (0)