Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
518fd6a
Implement tensor.isin
ndgrigorian Jun 6, 2025
85106f4
factor common utilities for scalar arguments to a new file
ndgrigorian Jun 8, 2025
ce757c8
Make constexpr variables in `isin` static
ndgrigorian Jun 11, 2025
8425cdc
Update implementation of `isin`
ndgrigorian Jun 11, 2025
204025a
Update per review comments
ndgrigorian Jun 16, 2025
cfb5154
Allow x to be a scalar in isin and remove assume_unique
ndgrigorian Jun 16, 2025
a448725
Make comparator static constexpr
ndgrigorian Jun 16, 2025
882a431
add basic tests for isin functionality
ndgrigorian Jun 17, 2025
d11626c
Remove unused import of dpctl in _set_functions.py
ndgrigorian Jun 17, 2025
710a6d0
Add type hints to isin
ndgrigorian Jun 17, 2025
411b976
Add usm_type to test_buf in isin
ndgrigorian Jun 18, 2025
3077bd6
Address review comments for isin tests
ndgrigorian Jun 18, 2025
ed9f376
Add test covering nans and +/- 0 in isin
ndgrigorian Jun 18, 2025
72278b5
Add test for isin with Python scalar args
ndgrigorian Jun 23, 2025
5b877c8
Add test for combinations of dtypes as inputs to isin
ndgrigorian Jun 23, 2025
538176c
Add compute follows data test for isin
ndgrigorian Jun 23, 2025
0cd24f5
Add isin to rendered docs
ndgrigorian Jun 23, 2025
0070331
Test that isin output is C-contiguous when input is strided
ndgrigorian Jun 23, 2025
2ebb3a1
improve formatting of isin docstring
ndgrigorian Jun 26, 2025
26f68d2
move rich_comparisons.hpp into utils
ndgrigorian Sep 11, 2025
365c3b4
factor out compare template param in isin
ndgrigorian Sep 11, 2025
44661ba
add missing includes to rich_comparisons
ndgrigorian Sep 17, 2025
62a9fa4
drop unused includes in isin kernel implementation
ndgrigorian Sep 17, 2025
ff68bca
validate that `invert` kwarg is boolean
ndgrigorian Sep 17, 2025
e28e1aa
add a test for input validation of invert
ndgrigorian Sep 17, 2025
68bc84e
make invert bool type check stricter
ndgrigorian Sep 17, 2025
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
Prev Previous commit
Next Next commit
Update implementation of isin
permit scalar input for second argument, address some review comments, add docstring
  • Loading branch information
ndgrigorian committed Sep 17, 2025
commit 8425cdc0ee1d87f88198ce00987b74ec3042b97c
124 changes: 84 additions & 40 deletions dpctl/tensor/_set_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@

from typing import NamedTuple

import dpctl
import dpctl.tensor as dpt
import dpctl.utils as du

from ._copy_utils import _empty_like_orderK
from ._scalar_utils import _get_dtype, _get_queue_usm_type, _validate_dtype
from ._tensor_elementwise_impl import _not_equal, _subtract
from ._tensor_impl import (
_copy_usm_ndarray_into_usm_ndarray,
Expand All @@ -36,8 +38,10 @@
_searchsorted_left,
_sort_ascending,
)
from ._type_utils import _resolve_weak_types_all_py_ints

__all__ = [
"isin",
"unique_values",
"unique_counts",
"unique_inverse",
Expand Down Expand Up @@ -629,61 +633,101 @@ def unique_all(x: dpt.usm_ndarray) -> UniqueAllResult:


def isin(x, test_elements, /, *, assume_unique=False, invert=False):
"""
Tests `x in test_elements` for each element of `x`. Returns a boolean array
Comment thread
ndgrigorian marked this conversation as resolved.
Outdated
with the same shape as `x` that is `True` where the element is in
`test_elements`, `False` otherwise.

Args:
x (usm_ndarray):
input array.
test_elements (Union[usm_ndarray, bool, int, float, complex]):
elements against which to test each value of `x`.
Default: `None`.
Comment thread
ndgrigorian marked this conversation as resolved.
Outdated
assume_unique (Optional[bool]):
if `True`, the input arrays are both assumed to be unique, which
currently has no effect.
Default: `False`.
invert (Optional[bool]):
if `True`, the output results are inverted, i.e., are equivalent to
testing `x not in test_elements` for each element of `x`.
Default: `False`.

Returns:
usm_ndarray:
an array of the inclusion test results. The returned array has a
boolean data type and the same shape as `x`.
"""
if not isinstance(x, dpt.usm_ndarray):
raise TypeError(f"Expected dpctl.tensor.usm_ndarray, got {type(x)}")
if not isinstance(test_elements, dpt.usm_ndarray):
raise TypeError(
f"Expected dpctl.tensor.usm_ndarray, got {type(test_elements)}"
q1, x_usm_type = x.sycl_queue, x.usm_type
q2, test_usm_type = _get_queue_usm_type(test_elements)
if q2 is None:
exec_q = q1
res_usm_type = x_usm_type
else:
exec_q = dpctl.utils.get_execution_queue((q1, q2))
if exec_q is None:
raise du.ExecutionPlacementError(
"Execution placement can not be unambiguously inferred "
"from input arguments."
)
res_usm_type = dpctl.utils.get_coerced_usm_type(
(
x_usm_type,
test_usm_type,
)
)
dpctl.utils.validate_usm_type(res_usm_type, allow_none=False)
Comment thread
ndgrigorian marked this conversation as resolved.
Outdated
sycl_dev = exec_q.sycl_device

q = du.get_execution_queue([x.sycl_queue, test_elements.sycl_queue])
if q is None:
raise du.ExecutionPlacementError(
"Execution placement can not be unambiguously "
"inferred from input arguments."
)
x_dt = x.dtype
test_dt = _get_dtype(test_elements, sycl_dev)
if not _validate_dtype(test_dt):
raise ValueError("`test_elements` has unsupported dtype")

x1 = x
x2 = dpt.reshape(test_elements, -1)
dt = dpt.result_type(
*_resolve_weak_types_all_py_ints(x_dt, test_dt, sycl_dev)
)

x1_dt = x1.dtype
x2_dt = x2.dtype
_manager = du.SequentialOrderManager[exec_q]

_manager = du.SequentialOrderManager[q]
dep_evs = _manager.submitted_events
if x_dt != dt:
x_buf = _empty_like_orderK(x, dt)
dep_evs = _manager.submitted_events
ht_ev, ev = _copy_usm_ndarray_into_usm_ndarray(
src=x, dst=x_buf, sycl_queue=exec_q, depends=dep_evs
)
_manager.add_event_pair(ht_ev, ev)
else:
x_buf = x

if x1_dt != x2_dt:
dt = dpt.result_type(x1, x2)
if x1_dt != dt:
x1_buf = _empty_like_orderK(x1, dt)
dep_evs = _manager.submitted_events
ht_ev, ev = _copy_usm_ndarray_into_usm_ndarray(
src=x1, dst=x1_buf, sycl_queue=q, depends=dep_evs
)
_manager.add_event_pair(ht_ev, ev)
x1 = x1_buf
if x2_dt != dt:
x2_buf = _empty_like_orderK(x2, dt)
dep_evs = _manager.submitted_events
ht_ev, ev = _copy_usm_ndarray_into_usm_ndarray(
src=x2, dst=x2_buf, sycl_queue=q, depends=dep_evs
)
_manager.add_event_pair(ht_ev, ev)
x2 = x2_buf
if not isinstance(test_elements, dpt.usm_ndarray):
test_buf = dpt.asarray(test_elements, dtype=dt, sycl_queue=exec_q)
Comment thread
ndgrigorian marked this conversation as resolved.
Outdated
elif test_dt != dt:
# copy into C-contiguous memory, because the array will be flattened
test_buf = dpt.empty_like(test_elements, dt, order="C")
Comment thread
ndgrigorian marked this conversation as resolved.
Outdated
dep_evs = _manager.submitted_events
ht_ev, ev = _copy_usm_ndarray_into_usm_ndarray(
Comment thread
ndgrigorian marked this conversation as resolved.
src=test_elements, dst=test_buf, sycl_queue=exec_q, depends=dep_evs
)
_manager.add_event_pair(ht_ev, ev)
else:
test_buf = test_elements

x2 = dpt.sort(x2)
test_buf = dpt.reshape(test_buf, -1)
test_buf = dpt.sort(test_buf)

dst_usm_type = du.get_coerced_usm_type([x1.usm_type, x2.usm_type])
dst = _empty_like_orderK(x1, dpt.bool, usm_type=dst_usm_type)
dst = _empty_like_orderK(x_buf, dpt.bool, usm_type=res_usm_type)
Comment thread
ndgrigorian marked this conversation as resolved.
Outdated

dep_evs = _manager.submitted_events
ht_ev, s_ev = _isin(
needles=x1,
hay=x2,
needles=x_buf,
hay=test_buf,
dst=dst,
sycl_queue=q,
sycl_queue=exec_q,
invert=invert,
Comment thread
ndgrigorian marked this conversation as resolved.
depends=dep_evs,
)
_manager.add_event_pair(ht_ev, s_ev)
return dpt.reshape(dst, x.shape)
return dst