From 7c09df3ffdfa6f73d036b6c76426a0dce56ed7eb Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 12 Jun 2025 02:45:14 -0700 Subject: [PATCH 1/5] feat: add `isin` to the specification Closes: https://github.com/data-apis/array-api/issues/854 --- .../draft/API_specification/set_functions.rst | 1 + src/array_api_stubs/_draft/set_functions.py | 46 ++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/spec/draft/API_specification/set_functions.rst b/spec/draft/API_specification/set_functions.rst index addf31e1f..cf2af9f68 100644 --- a/spec/draft/API_specification/set_functions.rst +++ b/spec/draft/API_specification/set_functions.rst @@ -18,6 +18,7 @@ Objects in API :toctree: generated :template: method.rst + isin unique_all unique_counts unique_inverse diff --git a/src/array_api_stubs/_draft/set_functions.py b/src/array_api_stubs/_draft/set_functions.py index 7fee77ecb..303ec0020 100644 --- a/src/array_api_stubs/_draft/set_functions.py +++ b/src/array_api_stubs/_draft/set_functions.py @@ -1,9 +1,53 @@ -__all__ = ["unique_all", "unique_counts", "unique_inverse", "unique_values"] +__all__ = ["isin", "unique_all", "unique_counts", "unique_inverse", "unique_values"] from ._types import Tuple, array +def isin( + x1: Union[array, int, float, complex, bool], + x2: Union[array, int, float, complex, bool], + /, + *, + invert: bool = False, +) -> array: + """ + Tests whether each element in ``x1`` is in ``x2``. + + Parameters + ---------- + x1: Union[array, int, float, complex, bool] + first input array. **May** have any data type. + x2: Union[array, int, float, complex, bool] + second input array. **May** have any data type. + invert: bool + boolean indicating whether to invert the test criterion. If ``True``, the function **must** test whether each element in ``x1`` is *not* in ``x2``. If ``False``, the function **must** test whether each element in ``x1`` is in ``x2``. Default: ``False``. + + Returns + ------- + out: array + an array containing element-wise test results. The returned array **must** have the same shape as ``x1`` and **must** have a boolean data type. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` **must** be an array. + + - If an element in ``x1`` is in ``x1``, the corresponding element in the output array **must** be ``True``; otherwise, the corresponding element in the output array **must** be ``False``. + + - Testing whether an element in ``x1`` corresponds to an element in ``x2`` **should** be determined based on value equality (see :func:`~array_api.equal`). For input arrays having floating-point data types, value-based equality implies the following behavior. + + - As ``nan`` values compare as ``False``, if an element in ``x1`` is ``nan`` and ``invert`` is ``False``, the corresponding element in the returned array **should** be ``False``. Otherwise, if an element in ``x1`` is ``nan`` and ``invert`` is ``True``, the corresponding element in the returned array **should** be ``True``. + - As complex floating-point values having at least one ``nan`` component compare as ``False``, if an element in ``x1`` is a complex floating-point value having one or more ``nan`` components and ``invert`` is ``False``, the corresponding element in the returned array **should** be ``False``. Otherwise, if an element in ``x1`` is a complex floating-point value having one or more ``nan`` components and ``invert`` is ``True``, the corresponding element in the returned array **should** be ``True``. + - As ``-0`` and ``+0`` compare as ``True``, if an element in ``x1`` is ``±0`` and ``x2`` contains at least one element which is ``±0`` + + - if ``invert`` is ``False``, the corresponding element in the returned array **should** be ``True``. + - if ``invert`` is ``True``, the corresponding element in the returned array **should** be ``False``. + + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is unspecified and thus implementation-defined. + """ + + def unique_all(x: array, /) -> Tuple[array, array, array, array]: """ Returns the unique elements of an input array ``x``, the first occurring indices for each unique element in ``x``, the indices from the set of unique elements that reconstruct ``x``, and the corresponding counts for each unique element in ``x``. From 7259ac7c82ab1c513b697f2839cbc54d84ebf1f1 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 12 Jun 2025 03:03:30 -0700 Subject: [PATCH 2/5] docs: fix typo --- src/array_api_stubs/_draft/set_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/set_functions.py b/src/array_api_stubs/_draft/set_functions.py index 303ec0020..e7dcce4f6 100644 --- a/src/array_api_stubs/_draft/set_functions.py +++ b/src/array_api_stubs/_draft/set_functions.py @@ -33,7 +33,7 @@ def isin( - At least one of ``x1`` or ``x2`` **must** be an array. - - If an element in ``x1`` is in ``x1``, the corresponding element in the output array **must** be ``True``; otherwise, the corresponding element in the output array **must** be ``False``. + - If an element in ``x1`` is in ``x2``, the corresponding element in the output array **must** be ``True``; otherwise, the corresponding element in the output array **must** be ``False``. - Testing whether an element in ``x1`` corresponds to an element in ``x2`` **should** be determined based on value equality (see :func:`~array_api.equal`). For input arrays having floating-point data types, value-based equality implies the following behavior. From 428be601f19bced29c72badba39022134e25af8d Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 12 Jun 2025 03:07:16 -0700 Subject: [PATCH 3/5] fix: import missing type --- src/array_api_stubs/_draft/set_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/set_functions.py b/src/array_api_stubs/_draft/set_functions.py index e7dcce4f6..6bf409b72 100644 --- a/src/array_api_stubs/_draft/set_functions.py +++ b/src/array_api_stubs/_draft/set_functions.py @@ -1,7 +1,7 @@ __all__ = ["isin", "unique_all", "unique_counts", "unique_inverse", "unique_values"] -from ._types import Tuple, array +from ._types import Tuple, Union, array def isin( From 11662a4a52f551b8dd1454d401e28d4a02f34ed5 Mon Sep 17 00:00:00 2001 From: Athan Date: Sun, 22 Jun 2025 23:02:34 -0700 Subject: [PATCH 4/5] docs: update copy --- src/array_api_stubs/_draft/set_functions.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/array_api_stubs/_draft/set_functions.py b/src/array_api_stubs/_draft/set_functions.py index 6bf409b72..7d2b5cfad 100644 --- a/src/array_api_stubs/_draft/set_functions.py +++ b/src/array_api_stubs/_draft/set_functions.py @@ -35,14 +35,13 @@ def isin( - If an element in ``x1`` is in ``x2``, the corresponding element in the output array **must** be ``True``; otherwise, the corresponding element in the output array **must** be ``False``. - - Testing whether an element in ``x1`` corresponds to an element in ``x2`` **should** be determined based on value equality (see :func:`~array_api.equal`). For input arrays having floating-point data types, value-based equality implies the following behavior. + - Testing whether an element in ``x1`` corresponds to an element in ``x2`` **should** be determined based on value equality (see :func:`~array_api.equal`). For input arrays having floating-point data types, value-based equality implies the following behavior. When ``invert`` is ``False``, - - As ``nan`` values compare as ``False``, if an element in ``x1`` is ``nan`` and ``invert`` is ``False``, the corresponding element in the returned array **should** be ``False``. Otherwise, if an element in ``x1`` is ``nan`` and ``invert`` is ``True``, the corresponding element in the returned array **should** be ``True``. - - As complex floating-point values having at least one ``nan`` component compare as ``False``, if an element in ``x1`` is a complex floating-point value having one or more ``nan`` components and ``invert`` is ``False``, the corresponding element in the returned array **should** be ``False``. Otherwise, if an element in ``x1`` is a complex floating-point value having one or more ``nan`` components and ``invert`` is ``True``, the corresponding element in the returned array **should** be ``True``. - - As ``-0`` and ``+0`` compare as ``True``, if an element in ``x1`` is ``±0`` and ``x2`` contains at least one element which is ``±0`` + - As ``nan`` values compare as ``False``, if an element in ``x1`` is ``nan``, the corresponding element in the returned array **should** be ``False``. + - As complex floating-point values having at least one ``nan`` component compare as ``False``, if an element in ``x1`` is a complex floating-point value having one or more ``nan`` components, the corresponding element in the returned array **should** be ``False``. + - As ``-0`` and ``+0`` compare as ``True``, if an element in ``x1`` is ``±0`` and ``x2`` contains at least one element which is ``±0``, the corresponding element in the returned array **should** be ``True``. - - if ``invert`` is ``False``, the corresponding element in the returned array **should** be ``True``. - - if ``invert`` is ``True``, the corresponding element in the returned array **should** be ``False``. + When ``invert`` is ``True``, the returned array must contain the same results as if the operation is implemented as ``logical_not(isin(x1, x2))``. - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is unspecified and thus implementation-defined. """ From 1c78599b186873a4f2af2b04cc430eeed7b57f34 Mon Sep 17 00:00:00 2001 From: Athan Date: Sun, 22 Jun 2025 23:04:00 -0700 Subject: [PATCH 5/5] docs: s/should/must/ --- src/array_api_stubs/_draft/set_functions.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/array_api_stubs/_draft/set_functions.py b/src/array_api_stubs/_draft/set_functions.py index 7d2b5cfad..5afeb2836 100644 --- a/src/array_api_stubs/_draft/set_functions.py +++ b/src/array_api_stubs/_draft/set_functions.py @@ -35,13 +35,13 @@ def isin( - If an element in ``x1`` is in ``x2``, the corresponding element in the output array **must** be ``True``; otherwise, the corresponding element in the output array **must** be ``False``. - - Testing whether an element in ``x1`` corresponds to an element in ``x2`` **should** be determined based on value equality (see :func:`~array_api.equal`). For input arrays having floating-point data types, value-based equality implies the following behavior. When ``invert`` is ``False``, + - Testing whether an element in ``x1`` corresponds to an element in ``x2`` **must** be determined based on value equality (see :func:`~array_api.equal`). For input arrays having floating-point data types, value-based equality implies the following behavior. When ``invert`` is ``False``, - - As ``nan`` values compare as ``False``, if an element in ``x1`` is ``nan``, the corresponding element in the returned array **should** be ``False``. - - As complex floating-point values having at least one ``nan`` component compare as ``False``, if an element in ``x1`` is a complex floating-point value having one or more ``nan`` components, the corresponding element in the returned array **should** be ``False``. - - As ``-0`` and ``+0`` compare as ``True``, if an element in ``x1`` is ``±0`` and ``x2`` contains at least one element which is ``±0``, the corresponding element in the returned array **should** be ``True``. + - As ``nan`` values compare as ``False``, if an element in ``x1`` is ``nan``, the corresponding element in the returned array **must** be ``False``. + - As complex floating-point values having at least one ``nan`` component compare as ``False``, if an element in ``x1`` is a complex floating-point value having one or more ``nan`` components, the corresponding element in the returned array **must** be ``False``. + - As ``-0`` and ``+0`` compare as ``True``, if an element in ``x1`` is ``±0`` and ``x2`` contains at least one element which is ``±0``, the corresponding element in the returned array **must** be ``True``. - When ``invert`` is ``True``, the returned array must contain the same results as if the operation is implemented as ``logical_not(isin(x1, x2))``. + When ``invert`` is ``True``, the returned array **must** contain the same results as if the operation is implemented as ``logical_not(isin(x1, x2))``. - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is unspecified and thus implementation-defined. """