From 250d38feb10d54834a4dc5fbcc4a13cbffa1cfa9 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 7 Apr 2022 02:36:10 -0700 Subject: [PATCH 1/8] Add `take` specification --- spec/API_specification/indexing_functions.rst | 28 +++++++++++++++++++ .../signatures/indexing_functions.py | 28 +++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 spec/API_specification/indexing_functions.rst create mode 100644 spec/API_specification/signatures/indexing_functions.py diff --git a/spec/API_specification/indexing_functions.rst b/spec/API_specification/indexing_functions.rst new file mode 100644 index 000000000..5816fceab --- /dev/null +++ b/spec/API_specification/indexing_functions.rst @@ -0,0 +1,28 @@ +.. _indexing-functions: + +Indexing Functions +=================== + + Array API specification for functions for indexing arrays. + +A conforming implementation of the array API standard must provide and support the following functions adhering to the following conventions. + +- Positional parameters must be `positional-only `_ parameters. Positional-only parameters have no externally-usable name. When a function accepting positional-only parameters is called, positional arguments are mapped to these parameters based solely on their order. +- Optional parameters must be `keyword-only `_ arguments. +- Broadcasting semantics must follow the semantics defined in :ref:`broadcasting`. +- Unless stated otherwise, functions must support the data types defined in :ref:`data-types`. +- Unless stated otherwise, functions must adhere to the type promotion rules defined in :ref:`type-promotion`. + +Objects in API +-------------- + +.. currentmodule:: signatures.indexing_functions + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + take diff --git a/spec/API_specification/signatures/indexing_functions.py b/spec/API_specification/signatures/indexing_functions.py new file mode 100644 index 000000000..c36514fc5 --- /dev/null +++ b/spec/API_specification/signatures/indexing_functions.py @@ -0,0 +1,28 @@ +from ._types import Union, array + +def take(x: array, indices: Union[int, array], /, *, axis: int) -> array: + """ + Returns elements of an array along an axis. + + .. note:: + Conceptually, the call ``take(x, indices, axis=3)`` is equivalent to ``x[:,:,:,indices,...]``; however, explicit indexing via arrays of indices is not currently supported in this specification due to concerns regarding ``__setitem__`` and array mutation semantics. + + Parameters + ---------- + x: array + input array. + indices: Union[int, array] + array indices. If ``indices`` is an array, the array must be one-dimensional and have an integer data type. If ``indices`` is an integer, the function must follow single-axis indexing semantics (see :ref:`indexing`). + axis: int + axis over which to select values. If ``axis`` is negative, the function must determine the axis along which to select values by counting from the last dimension. + + Returns + ------- + out: array + an array having the same data type as ``x``. If ``indices`` is an array, the output array must have the same rank (i.e., number of dimensions) as ``x`` and must have the same shape as ``x``, except for the axis specified by ``axis`` whose size must equal the number of elements in ``indices``. If ``indices`` is an integer, the output array must have one less dimension than ``x`` (i.e., the array rank should decrease by one). In particular, if ``x`` has rank ``N``, when ``indices`` is an integer, this function must be equivalent to a selection tuple (e.g., ``x[:,:,3,:]``, ``x[0,:]``, et cetera) with the ``m``\th element an integer (and all other entries ``:``), thus indexing a sub-array with rank ``N-1``. + + .. note:: + When ``indices`` is an integer and ``x`` is an array of rank ``1``, the returned array must be an array of rank ``0``, not a scalar. + """ + +__all__ = ['take'] From 2b9484bcc13f7c67d9105a6997ddddd33388c30c Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 7 Apr 2022 02:47:56 -0700 Subject: [PATCH 2/8] Update copy --- spec/API_specification/signatures/indexing_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/signatures/indexing_functions.py b/spec/API_specification/signatures/indexing_functions.py index c36514fc5..ece083a77 100644 --- a/spec/API_specification/signatures/indexing_functions.py +++ b/spec/API_specification/signatures/indexing_functions.py @@ -12,7 +12,7 @@ def take(x: array, indices: Union[int, array], /, *, axis: int) -> array: x: array input array. indices: Union[int, array] - array indices. If ``indices`` is an array, the array must be one-dimensional and have an integer data type. If ``indices`` is an integer, the function must follow single-axis indexing semantics (see :ref:`indexing`). + array indices. If ``indices`` is an array, the array must be one-dimensional and have an integer data type. If ``indices`` is an integer, the function must follow multi-axis indexing semantics when providing an integer for a single-axis index (see :ref:`indexing`). axis: int axis over which to select values. If ``axis`` is negative, the function must determine the axis along which to select values by counting from the last dimension. From 5f093070817a6b7ecbdafd31d6de9c01f97ba646 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 7 Apr 2022 02:51:09 -0700 Subject: [PATCH 3/8] Update index --- spec/API_specification/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/API_specification/index.rst b/spec/API_specification/index.rst index 1d4c9cfef..b7201dbcb 100644 --- a/spec/API_specification/index.rst +++ b/spec/API_specification/index.rst @@ -16,6 +16,7 @@ API specification elementwise_functions function_and_method_signatures indexing + indexing_functions linear_algebra_functions manipulation_functions searching_functions From 370675b3e9daaf01a9ab32cbfec593f6800da8e2 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 18 Apr 2022 00:40:41 -0700 Subject: [PATCH 4/8] Clarify behavior when provided a zero-dimensional array --- spec/API_specification/signatures/indexing_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/signatures/indexing_functions.py b/spec/API_specification/signatures/indexing_functions.py index ece083a77..710a147bb 100644 --- a/spec/API_specification/signatures/indexing_functions.py +++ b/spec/API_specification/signatures/indexing_functions.py @@ -12,7 +12,7 @@ def take(x: array, indices: Union[int, array], /, *, axis: int) -> array: x: array input array. indices: Union[int, array] - array indices. If ``indices`` is an array, the array must be one-dimensional and have an integer data type. If ``indices`` is an integer, the function must follow multi-axis indexing semantics when providing an integer for a single-axis index (see :ref:`indexing`). + array indices. If ``indices`` is an integer (or a zero-dimensional array satisfying ``operator.index``), the function must follow multi-axis indexing semantics when providing an integer for a single-axis index (see :ref:`indexing`). If ``indices`` is a non-zero-dimensional array, the array must be one-dimensional and have an integer data type. axis: int axis over which to select values. If ``axis`` is negative, the function must determine the axis along which to select values by counting from the last dimension. From 915c02685eeb6dc61faf82d7178cab51034e9c3e Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 19 Sep 2022 01:14:23 -0700 Subject: [PATCH 5/8] Rephrase description and add guidance concerning when `axis` is required --- spec/API_specification/array_api/indexing_functions.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/API_specification/array_api/indexing_functions.py b/spec/API_specification/array_api/indexing_functions.py index 710a147bb..7fb57ab69 100644 --- a/spec/API_specification/array_api/indexing_functions.py +++ b/spec/API_specification/array_api/indexing_functions.py @@ -12,10 +12,12 @@ def take(x: array, indices: Union[int, array], /, *, axis: int) -> array: x: array input array. indices: Union[int, array] - array indices. If ``indices`` is an integer (or a zero-dimensional array satisfying ``operator.index``), the function must follow multi-axis indexing semantics when providing an integer for a single-axis index (see :ref:`indexing`). If ``indices`` is a non-zero-dimensional array, the array must be one-dimensional and have an integer data type. + array indices. If ``indices`` is a non-zero-dimensional array, the array must be one-dimensional and have an integer data type. If ``indices`` is an integer (or a zero-dimensional array satisfying ``operator.index``), the function must follow indexing semantics as specified in :ref:`indexing`. axis: int axis over which to select values. If ``axis`` is negative, the function must determine the axis along which to select values by counting from the last dimension. + If ``x`` is a one-dimensional array, providing an ``axis`` is optional; however, if ``x`` has more than one dimension, providing an ``axis`` is required. + Returns ------- out: array From ff155ccefc538d617b2d5c1c7a92dbc678fae9d9 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 19 Sep 2022 01:29:04 -0700 Subject: [PATCH 6/8] Fix module --- spec/API_specification/indexing_functions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/indexing_functions.rst b/spec/API_specification/indexing_functions.rst index 5816fceab..264b787ae 100644 --- a/spec/API_specification/indexing_functions.rst +++ b/spec/API_specification/indexing_functions.rst @@ -16,7 +16,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.indexing_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order From 0024b6a5076d35514c1775dcd61126e2beee955c Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 19 Sep 2022 01:32:53 -0700 Subject: [PATCH 7/8] Fix missing import --- spec/API_specification/array_api/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/API_specification/array_api/__init__.py b/spec/API_specification/array_api/__init__.py index e5de2e49f..198838e46 100644 --- a/spec/API_specification/array_api/__init__.py +++ b/spec/API_specification/array_api/__init__.py @@ -4,6 +4,7 @@ from .data_type_functions import * import array_api.data_types as dtype from .elementwise_functions import * +from .indexing_functions import * from .linear_algebra_functions import * from .manipulation_functions import * from .searching_functions import * From b14151ae8f44f15df71008dbbfc630674979c554 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 2 Nov 2022 22:45:28 -0700 Subject: [PATCH 8/8] Remove support for providing an integer for the `indices` kwarg --- .../array_api/indexing_functions.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/spec/API_specification/array_api/indexing_functions.py b/spec/API_specification/array_api/indexing_functions.py index 7fb57ab69..65f2c3450 100644 --- a/spec/API_specification/array_api/indexing_functions.py +++ b/spec/API_specification/array_api/indexing_functions.py @@ -1,18 +1,18 @@ from ._types import Union, array -def take(x: array, indices: Union[int, array], /, *, axis: int) -> array: +def take(x: array, indices: array, /, *, axis: int) -> array: """ Returns elements of an array along an axis. .. note:: - Conceptually, the call ``take(x, indices, axis=3)`` is equivalent to ``x[:,:,:,indices,...]``; however, explicit indexing via arrays of indices is not currently supported in this specification due to concerns regarding ``__setitem__`` and array mutation semantics. + Conceptually, ``take(x, indices, axis=3)`` is equivalent to ``x[:,:,:,indices,...]``; however, explicit indexing via arrays of indices is not currently supported in this specification due to concerns regarding ``__setitem__`` and array mutation semantics. Parameters ---------- x: array input array. - indices: Union[int, array] - array indices. If ``indices`` is a non-zero-dimensional array, the array must be one-dimensional and have an integer data type. If ``indices`` is an integer (or a zero-dimensional array satisfying ``operator.index``), the function must follow indexing semantics as specified in :ref:`indexing`. + indices: array + array indices. The array must be one-dimensional and have an integer data type. axis: int axis over which to select values. If ``axis`` is negative, the function must determine the axis along which to select values by counting from the last dimension. @@ -21,10 +21,7 @@ def take(x: array, indices: Union[int, array], /, *, axis: int) -> array: Returns ------- out: array - an array having the same data type as ``x``. If ``indices`` is an array, the output array must have the same rank (i.e., number of dimensions) as ``x`` and must have the same shape as ``x``, except for the axis specified by ``axis`` whose size must equal the number of elements in ``indices``. If ``indices`` is an integer, the output array must have one less dimension than ``x`` (i.e., the array rank should decrease by one). In particular, if ``x`` has rank ``N``, when ``indices`` is an integer, this function must be equivalent to a selection tuple (e.g., ``x[:,:,3,:]``, ``x[0,:]``, et cetera) with the ``m``\th element an integer (and all other entries ``:``), thus indexing a sub-array with rank ``N-1``. - - .. note:: - When ``indices`` is an integer and ``x`` is an array of rank ``1``, the returned array must be an array of rank ``0``, not a scalar. + an array having the same data type as ``x``. The output array must have the same rank (i.e., number of dimensions) as ``x`` and must have the same shape as ``x``, except for the axis specified by ``axis`` whose size must equal the number of elements in ``indices``. """ __all__ = ['take']